Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document+test coverage for upconversion of new object fields #64

Merged
merged 14 commits into from
Jun 23, 2021
Merged
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,32 @@ There are two events that we were not able to decode, for varying reasons:

_Note however, that we don't have a clean way to trap the data and log it. See [Logging unmatched events](#logging-unmatched-events) for an example of how one might log such unmatched events_

### Handling introduction of new fields in JSON
The below example demonstrates the addition of a `CartId` property in a newer version of `CreateCart`. It's worth noting that
deserializing `CartV1.CreateCart` into `CartV2.CreateCart` requires `CartId` to be an optional property or the property will
deserialize into `null` which is an invalid state for the `CartV2.CreateCart` record in F# (F# `type`s are assumed to never be `null`).

```
module CartV1 =
type CreateCart = { name: string }

type Events =
| Created of CreateCart
interface IUnionContract

module CartV2 =
type CreateCart = { name: string; cartId: CartId option }
type Events =
| Created of CreateCart
interface IUnionContract
```

FsCodec.SystemTextJson looks to provide an analogous mechanism. In general, FsCodec is seeking to provide a pragmatic middle way of
using NewtonsoftJson or SystemTextJson in F# without completely changing what one might expect to happen when using JSON.NET in
order to provide an F# only experience.

The aim is to provide helpers to smooth the way for using reflection based serialization in a way that would not surprise
people coming from a C# background and/or in mixed C#/F# codebases.
## Adding Matchers to the Event Contract

We can clarify the consuming code a little by adding further helper Active Patterns alongside the event contract :-
Expand Down Expand Up @@ -655,4 +681,4 @@ Please raise GitHub issues for any questions so others can benefit from the disc
```powershell
# verify the integrity of the repo wrt being able to build/pack/test
./dotnet build build.proj
```
```
25 changes: 25 additions & 0 deletions tests/FsCodec.NewtonsoftJson.Tests/PicklerTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ open Swensen.Unquote
open System
open Xunit

open FsCodec.NewtonsoftJson.Tests.Fixtures

// NB Feel free to ignore this opinion and copy the 4 lines into your own globals - the pinning test will remain here
/// <summary>
/// Renders all Guids without dashes.
Expand Down Expand Up @@ -39,3 +41,26 @@ let [<Fact>] ``Global GuidConverter`` () =

test <@ "\"00000000-0000-0000-0000-000000000000\"" = resDashes
&& "\"00000000000000000000000000000000\"" = resNoDashes @>

module CartV1 =
type CreateCart = { Name: string }

type Events =
| Create of CreateCart
interface TypeShape.UnionContract.IUnionContract

module CartV2 =
type CreateCart = { Name: string; CartId: CartId option }
type Events =
| Create of CreateCart
interface TypeShape.UnionContract.IUnionContract

let [<Fact>] ``Deserialize missing field a as optional property None value`` () =
let expectedCreateCartV2: CartV2.CreateCart = { Name = "cartName"; CartId = None }
let createCartV1: CartV1.CreateCart = { Name = "cartName" }

let createCartV1JSON = JsonConvert.SerializeObject createCartV1

let createCartV2 = JsonConvert.DeserializeObject<CartV2.CreateCart>(createCartV1JSON)

test <@ expectedCreateCartV2 = createCartV2 @>