Skip to content

Commit

Permalink
Core,GrpcModels: Match & Option json converters
Browse files Browse the repository at this point in the history
Implemented json converters for Match and Option<'T> types.

Match type converter is placed in GrpcModels.ModelSerialization
since it's not used in Redis, but only in GRPC.
  • Loading branch information
webwarrior-ws committed Sep 5, 2024
1 parent 90fe289 commit 7b4e449
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 2 deletions.
31 changes: 30 additions & 1 deletion src/FX.Core/RedisStorageLayer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,39 @@ module Serialization =
override this.Write(writer, value, _options ) =
writer.WriteStringValue(value.ToString())

// code from https://gist.github.com/mbuhot/c224f15e0266adf5ba8ca4e882f88a75
// Converts Option<T> to/from JSON by projecting to null or T
type OptionValueConverter<'T>() =
inherit JsonConverter<Option<'T>>()

override this.Read (reader: byref<Utf8JsonReader>, _typ: Type, options: JsonSerializerOptions) =
match reader.TokenType with
| JsonTokenType.Null -> None
| _ -> Some <| JsonSerializer.Deserialize<'T>(&reader, options)

override this.Write (writer: Utf8JsonWriter, value: Option<'T>, options: JsonSerializerOptions) =
match value with
| None -> writer.WriteNullValue ()
| Some value -> JsonSerializer.Serialize(writer, value, options)

// Instantiates the correct OptionValueConverter<T>
type OptionConverter() =
inherit JsonConverterFactory()
override this.CanConvert(typ: Type) : bool =
typ.IsGenericType &&
typ.GetGenericTypeDefinition() = typedefof<Option<_>>

override this.CreateConverter(typeToConvert: Type,
_options: JsonSerializerOptions) : JsonConverter =
let typ = typeToConvert.GetGenericArguments() |> Array.head
let converterType = typedefof<OptionValueConverter<_>>.MakeGenericType(typ)
Activator.CreateInstance(converterType) :?> JsonConverter

let serializationOptions =
let options = JsonSerializerOptions()
options.Converters.Add(SideTypeConverter())
options.Converters.Add(CurrencyTypeConverter())
options.Converters.Add(CurrencyTypeConverter())
options.Converters.Add(OptionConverter())
options


Expand Down
1 change: 1 addition & 0 deletions src/FX.GrpcModels/FX.GrpcModels.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<Compile Include="Models.fs" />
<Compile Include="ModelSerialization.fs" />
<Compile Include="Marshalling.fs" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/FX.GrpcModels/Marshalling.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open System
open System.Reflection
open System.Text.Json

open FsharpExchangeDotNetStandard.Redis.Serialization
open ModelSerialization

module VersionHelper =
let CURRENT_VERSION =
Expand Down
54 changes: 54 additions & 0 deletions src/FX.GrpcModels/ModelSerialization.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace GrpcModels

open System.Text.Json
open System.Text.Json.Serialization

open FsharpExchangeDotNetStandard

module ModelSerialization =
type MatchTypeConverter() =
inherit JsonConverter<Match>()

override this.Read(reader, _typeToConvert, _options) =
if reader.TokenType <> JsonTokenType.StartObject then
raise <| JsonException()

// "Type" key
reader.Read() |> ignore
if reader.TokenType <> JsonTokenType.PropertyName || reader.GetString() <> "Type" then
raise <| JsonException()
// "Type" value
reader.Read() |> ignore
match reader.GetString() with
| "Full" ->
reader.Read() |> ignore
if reader.TokenType <> JsonTokenType.EndObject then
raise <| JsonException()
Match.Full
| "Partial" ->
// "Amount" key
reader.Read() |> ignore
if reader.TokenType <> JsonTokenType.PropertyName || reader.GetString() <> "Amount" then
raise <| JsonException()
// "Amount" value
let amount = reader.GetDecimal()
reader.Read() |> ignore
if reader.TokenType <> JsonTokenType.EndObject then
raise <| JsonException()
Match.Partial amount
| typeName -> raise <| JsonException("Unknown Match type: " + typeName)

override this.Write(writer, value, _options ) =
writer.WriteStartObject()
match value with
| Full ->
writer.WriteString("Type", "Full")
| Partial amount ->
writer.WriteString("Type", "Partial")
writer.WriteNumber("Amount", amount)
writer.WriteEndObject()

let serializationOptions =
let options = JsonSerializerOptions(Redis.Serialization.serializationOptions)
options.Converters.Add(MatchTypeConverter())
options

0 comments on commit 7b4e449

Please sign in to comment.