-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Comparable, StringId, StringIdConverter (#119)
- Loading branch information
Showing
9 changed files
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace FsCodec.NewtonsoftJson | ||
|
||
/// <summary>Implements conversion to/from <c>string</c> for a <c>FsCodec.StringId</c>-derived type.</summary> | ||
[<AbstractClass>] | ||
type StringIdConverter<'T when 'T :> FsCodec.StringId<'T> >(parse: string -> 'T) = | ||
inherit JsonIsomorphism<'T, string>() | ||
override _.Pickle value = value.ToString() | ||
override _.UnPickle input = parse input |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace FsCodec.SystemTextJson | ||
|
||
/// <summary>Implements conversion to/from <c>string</c> for a <c>FsCodec.StringId</c>-derived type.</summary> | ||
[<AbstractClass>] | ||
type StringIdConverter<'T when 'T :> FsCodec.StringId<'T> >(parse: string -> 'T) = | ||
inherit System.Text.Json.Serialization.JsonConverter<'T>() | ||
override _.Write(writer, value, _options) = value.ToString() |> writer.WriteStringValue | ||
override _.Read(reader, _type, _options) = reader.GetString() |> parse | ||
|
||
/// <summary>Implements conversion to/from <c>string</c> for a <c>FsCodec.StringId</c>-derived type.<br/> | ||
/// Opts into use of the underlying token as a valid property name when tth type is used as a Key in a <c>IDictionary</c>.</summary> | ||
[<AbstractClass>] | ||
type StringIdOrDictionaryKeyConverter<'T when 'T :> FsCodec.StringId<'T> >(parse: string -> 'T) = | ||
inherit System.Text.Json.Serialization.JsonConverter<'T>() | ||
override _.Write(writer, value, _options) = value.ToString() |> writer.WriteStringValue | ||
override _.WriteAsPropertyName(writer, value, _options) = value.ToString() |> writer.WritePropertyName | ||
override _.Read(reader, _type, _options) = reader.GetString() |> parse | ||
override _.ReadAsPropertyName(reader, _type, _options) = reader.GetString() |> parse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
namespace FsCodec | ||
|
||
/// Endows any type that inherits this class with standard .NET comparison semantics using a supplied token identifier | ||
[<AbstractClass>] | ||
type Comparable<'TComp, 'Token when 'TComp :> Comparable<'TComp, 'Token> and 'Token: comparison>(token: 'Token) = | ||
member private _.Token = token | ||
override x.Equals y = match y with :? Comparable<'TComp, 'Token> as y -> x.Token = y.Token | _ -> false | ||
override _.GetHashCode() = hash token | ||
interface System.IComparable with | ||
member x.CompareTo y = | ||
match y with | ||
| :? Comparable<'TComp, 'Token> as y -> compare x.Token y.Token | ||
| _ -> invalidArg "y" "invalid comparand" | ||
|
||
/// Endows any type that inherits this class with standard .NET comparison semantics using a supplied token identifier | ||
/// + treats the token as the canonical rendition for `ToString()` purposes | ||
[<AbstractClass>] | ||
type StringId<'TComp when 'TComp :> Comparable<'TComp, string>>(token: string) = | ||
inherit Comparable<'TComp, string>(token) | ||
override _.ToString() = token |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
module FsCodec.SystemTextJson.Tests.StringIdTests | ||
|
||
open System.Collections.Generic | ||
open FsCodec.SystemTextJson | ||
open Xunit | ||
open Swensen.Unquote | ||
|
||
(* Recommended helper aliases to put in your namespace global to avoid having to open long namespaces *) | ||
|
||
type StjNameAttribute = System.Text.Json.Serialization.JsonPropertyNameAttribute | ||
type StjIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute | ||
type StjConverterAttribute = System.Text.Json.Serialization.JsonConverterAttribute | ||
|
||
module Guid = | ||
|
||
let inline gen () = System.Guid.NewGuid() | ||
let inline toStringN (x: System.Guid) = x.ToString "N" | ||
let inline parse (x: string) = System.Guid.Parse x | ||
|
||
module Bare = | ||
|
||
[<Sealed; AutoSerializable false; StjConverter(typeof<SkuIdConverter>)>] | ||
type SkuId(value: System.Guid) = | ||
// No JSON Ignore attribute required as read-only property | ||
member val Value = value | ||
and private SkuIdConverter() = | ||
inherit JsonIsomorphism<SkuId, string>() | ||
override _.Pickle(value: SkuId) = value.Value |> Guid.toStringN | ||
override _.UnPickle input = input |> Guid.parse |> SkuId | ||
|
||
[<Fact>] | ||
let comparison () = | ||
let g = Guid.gen () | ||
let id1, id2 = SkuId g, SkuId g | ||
false =! id1.Equals id2 | ||
id1 <>! id2 | ||
|
||
[<Fact>] | ||
let serdes () = | ||
let x = Guid.gen () |> SkuId | ||
$"\"{Guid.toStringN x.Value}\"" =! Serdes.Default.Serialize x | ||
let ser = Serdes.Default.Serialize x | ||
$"\"{x.Value}\"" <>! ser // Default render of Guid is not toStringN | ||
x.Value =! Serdes.Default.Deserialize<SkuId>(ser).Value | ||
|
||
let d = Dictionary() | ||
d.Add(x, "value") | ||
raises<System.NotSupportedException> <@ Serdes.Default.Serialize d @> | ||
|
||
module StringIdIsomorphism = | ||
|
||
[<Sealed; AutoSerializable false; StjConverter(typeof<SkuIdConverter>)>] | ||
type SkuId(value: System.Guid) = inherit FsCodec.StringId<SkuId>(Guid.toStringN value) | ||
and private SkuIdConverter() = | ||
inherit JsonIsomorphism<SkuId, string>() | ||
override _.Pickle(value: SkuId) = value |> string | ||
override _.UnPickle input = input |> Guid.parse |> SkuId | ||
|
||
[<Fact>] | ||
let comparison () = | ||
let g = Guid.gen() | ||
let id1, id2 = SkuId g, SkuId g | ||
true =! id1.Equals id2 | ||
id1 =! id2 | ||
|
||
[<Fact>] | ||
let serdes () = | ||
let x = Guid.gen () |> SkuId | ||
let ser = Serdes.Default.Serialize x | ||
$"\"{x}\"" =! ser | ||
x =! Serdes.Default.Deserialize ser | ||
|
||
let d = Dictionary() | ||
d.Add(x, "value") | ||
raises<System.NotSupportedException> <@ Serdes.Default.Serialize d @> | ||
|
||
module StringIdConverter = | ||
|
||
[<Sealed; AutoSerializable false; StjConverter(typeof<SkuIdConverter>)>] | ||
type SkuId(value: System.Guid) = inherit FsCodec.StringId<SkuId>(Guid.toStringN value) | ||
and private SkuIdConverter() = inherit StringIdConverter<SkuId>(Guid.parse >> SkuId) | ||
|
||
[<Fact>] | ||
let comparison () = | ||
let g = Guid.gen() | ||
let id1, id2 = SkuId g, SkuId g | ||
true =! id1.Equals id2 | ||
id1 =! id2 | ||
|
||
[<Fact>] | ||
let serdes () = | ||
let x = Guid.gen () |> SkuId | ||
$"\"{x}\"" =! Serdes.Default.Serialize x | ||
|
||
let d = Dictionary() | ||
d.Add(x, "value") | ||
raises<System.NotSupportedException> <@ Serdes.Default.Serialize d @> | ||
|
||
module StringIdOrKeyConverter = | ||
|
||
[<Sealed; AutoSerializable false; StjConverter(typeof<SkuIdConverter>)>] | ||
type SkuId(value: System.Guid) = inherit FsCodec.StringId<SkuId>(Guid.toStringN value) | ||
and private SkuIdConverter() = inherit StringIdOrDictionaryKeyConverter<SkuId>(Guid.parse >> SkuId) | ||
|
||
[<Fact>] | ||
let comparison () = | ||
let g = Guid.gen() | ||
let id1, id2 = SkuId g, SkuId g | ||
true =! id1.Equals id2 | ||
id1 =! id2 | ||
|
||
[<Fact>] | ||
let serdes () = | ||
let x = Guid.gen () |> SkuId | ||
$"\"{x}\"" =! Serdes.Default.Serialize x | ||
|
||
let d = Dictionary() | ||
d.Add(x, "value") | ||
$"{{\"{x}\":\"value\"}}" =! Serdes.Default.Serialize d |