Skip to content

Instantly share code, notes, and snippets.

@BrianVallelunga
Last active October 24, 2020 07:14
Show Gist options
  • Select an option

  • Save BrianVallelunga/1fb2be0318e3e81282c552cbf3612cb0 to your computer and use it in GitHub Desktop.

Select an option

Save BrianVallelunga/1fb2be0318e3e81282c552cbf3612cb0 to your computer and use it in GitHub Desktop.
A custom CosmosSerializer that uses the CompactUnionJsonConverter from Microsoft.FSharpLu.Json to format Cosmos DB documents in a more humane way.
type CompactCosmosSerializer() =
inherit CosmosSerializer()
let defaultEncoding = new UTF8Encoding(false, true)
let jsonSerializerSettings = new JsonSerializerSettings()
do jsonSerializerSettings.Converters <- [| CompactUnionJsonConverter(true) |]
let serializer = JsonSerializer.Create(jsonSerializerSettings)
override u.FromStream<'T>(stream: Stream): 'T =
let returnCastedStream() =
(box stream) :?> 'T
let readStreamAndConvert() =
use streamReader = new StreamReader(stream)
use jsonTextReader = new JsonTextReader(streamReader)
serializer.Deserialize<'T>(jsonTextReader)
try
if typeof<Stream>.IsAssignableFrom(typeof<'T>)
then returnCastedStream()
else readStreamAndConvert()
finally
stream.Dispose()
override u.ToStream<'T>(input: 'T): Stream =
let streamPayload = new MemoryStream()
use streamWriter = new StreamWriter(streamPayload,
encoding = defaultEncoding,
bufferSize = 1024,
leaveOpen = true )
use writer = new JsonTextWriter(streamWriter)
writer.Formatting <- Newtonsoft.Json.Formatting.None
serializer.Serialize(writer, input)
writer.Flush()
streamWriter.Flush()
streamPayload.Position <- 0L
streamPayload :> Stream
@PhalanxHead
Copy link

Thankyou so much! This has made life so much easier!

This should be part of the dotnet Cosmos Documentation.

For the newbies like me who are trying to connect Cosmos to F# via Aaron's F# Cosmos Wrapper, this is the vague setup you need.

  1. Install Microsoft.FSharpLu.Json
  2. Here's a basic layout.
open FSharp.CosmosDb
open FSharp.Control
open Azure.Cosmos.Serialization
open System.Text
open Microsoft.FSharpLu.Json

module Serializer =
    type CompactCosmosSerializer() =
        inherit CosmosSerializer()

        let defaultEncoding = new UTF8Encoding(false, true)
        let jsonSerializerSettings = new JsonSerializerSettings()
        do jsonSerializerSettings.Converters <- [| CompactUnionJsonConverter(true) |]

        let serializer =
            JsonSerializer.Create(jsonSerializerSettings)

        override u.FromStream<'T>(stream: Stream): 'T =
            let returnCastedStream () = (box stream) :?> 'T

            let readStreamAndConvert () =
                use streamReader = new StreamReader(stream)
                use jsonTextReader = new JsonTextReader(streamReader)
                serializer.Deserialize<'T>(jsonTextReader)

            try
                if typeof<Stream>.IsAssignableFrom(typeof<'T>)
                then returnCastedStream ()
                else readStreamAndConvert ()
            finally
                stream.Dispose()

        override u.ToStream<'T>(input: 'T): Stream =
            let streamPayload = new MemoryStream()

            use streamWriter =
                new StreamWriter(streamPayload, encoding = defaultEncoding, bufferSize = 1024, leaveOpen = true)

            use writer = new JsonTextWriter(streamWriter)
            writer.Formatting <- Newtonsoft.Json.Formatting.None
            serializer.Serialize(writer, input)
            writer.Flush()
            streamWriter.Flush()

            streamPayload.Position <- 0L
            streamPayload :> Stream

module Domain = 
    type FamilyMember = Mum | Dad | Child
    type Person = { id: Guid; FirstName : string; LastName : string; FamilyType: FamilyMember }

module Programme = 
    [<EntryPoint>]
    let main argv =
        async {

            let person = { id = Guid.NewGuid(); FirstName = "Minecraft"; LastName = "Steve"; FamiltyType = Dad }

            let connString = "..."

            let op: Azure.Cosmos.CosmosClientOptions = Azure.Cosmos.CosmosClientOptions()
            op.Serializer <- Serializer.CompactCosmosSerializer()

            let insertPerson =
                Cosmos.fromConnectionStringWithOptions connString op
                |> Cosmos.database "Sample"
                |> Cosmos.container "People"
                |> Cosmos.insert<Person> person
                |> Cosmos.execAsync

            let person = insertPerson 
            do! person 
                |> AsyncSeq.iter (fun u -> printfn "%A" u)

        return 0 // return an integer exit code
    }
    |> Async.RunSynchronously

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment