xyncro / chiron

JSON for F#
https://xyncro.tech/chiron
MIT License
173 stars 41 forks source link

How to serialize a list to a Json object #77

Open felixbecker opened 7 years ago

felixbecker commented 7 years ago

Hi,

I have a question regarding a list serialization. Since I could not find any pointers in the tests or docs. I would be great if someone could point me in the right direction.

Given I have a type like this:

type Post = {
    Id: Guid
    Title: string
    Body: string
} with static member ToJson(x:Post) = json{
        do! Json.write "id" x.Id
        do! Json.write "title" x.Title
        do! Json.write "body" x.Body
}

and a list of posts like this

 let post1 = {Id= Guid.NewGuid();Title="Title hello world post 1";Body="My body"}
 let post2 = {Id= Guid.NewGuid();Title="Title hello world post 2";Body="My body"}
 let listOfPosts = [post1;post2]

    listOfPosts
        |> Json.serialize
        |> Json.formatWith JsonFormattingOptions.Pretty

this would results obviously in this

"[
  {
    "body": "My body",
    "id": "0356c901-e1fa-4bae-8fe3-70061d2e05f3",
    "title": "Title hello world post 1"
  },
  {
    "body": "My body",
    "id": "292a275b-960e-46b4-b04b-c3e214c78b0d",
    "title": "Title hello world post 2"
  }
]" 

But how can I write a custom list serialization function that would produce something like this to an object graph:

"{
  "0356c901-e1fa-4bae-8fe3-70061d2e05f3":{
    "body": "My body",
    "title": "Title hello world post 1"
  },
  "292a275b-960e-46b4-b04b-c3e214c78b0d":{
    "body": "My body",
    "title": "Title hello world post 2"
  }
}"

Thanks for any help.

kolektiv commented 7 years ago

Oh that's interesting! Sorry i've not got back to you sooner, I was away for the weekend, but that's an interesting question. I'll have to play around with it and have a think about that - but I'll try and get back to you soon 😄

ingted commented 7 years ago

Hi kolektiv & felixbecker,

May I ask you here? Because I think I am doing something like this issue (not very sure), and my (useless / full of bug) method is

e.g.

At first I have a Monkey type, and I hope I could ## serialize IDictionary``2[int64, Monkey]

Yeah, I guess this is easy to transform to a ## list ^_^

#r @"..\..\..\chiron\src\Chiron\bin\Chiron.dll"
#r @"..\..\..\aether\src\Aether\bin\Aether.dll"
#r @"..\..\..\..\gdrive_anighost\fparsec\Build\VS14-PCL\bin\Debug\FParsec.dll"
#r @"..\..\..\..\gdrive_anighost\fparsec\Build\VS14-PCL\bin\Debug\FParsecCS.dll"

open Aether
open Aether.Operators
open Chiron
open Chiron.Operators
open System.Collections.Concurrent
open System.Collections.Generic
open System.Runtime.CompilerServices

[<CLIMutable>]
type Monkey =
  { sound : string
    height : decimal }

  static member ToJson (x : Monkey) =
    Json.write "sound" x.sound
    *> Json.write "height" x.height

So I define a extension method like this:

[<Extension>]
type ExtensionMethds2 () = 
    [<Extension>]
    static member inline ToJson (dic: IDictionary<int64, Monkey>): Json<unit> =
        Seq.fold (fun (sn : Json<unit>) key ->
            let x = dic.[key]
            sn 
            *> Json.write (key.ToString()) x
            ) (Json.init ()) dic.Keys

But when I tried to serialize it with:

let dictest = dict [123L, { sound = "ooh"; height = 1.53m }; 456L, { sound = "ooh"; height = 1.53m }]
Json.format (Json.serialize dictest)

Fsi.exe complains:

StatExtract.fsx(744,29): error FS0001: No overloads match for method 'ToJson'. The available overloads are shown below (or in the Error List window).
Possible overload: 'static member ToJsonDefaults.ToJson : x:unit -> Json<unit>'. Type constraint mismatch. The type 
    IDictionary<int64,Monkey>    
is not compatible with type
    unit    
The type 'IDictionary<int64,Monkey>' is not compatible with the type 'unit'.
Possible overload: 'static member ToJsonDefaults.ToJson : x:bool -> Json<unit>'. Type constraint mismatch. The type 
    IDictionary<int64,Monkey>    
is not compatible with type
    bool    

Even I add this code, it still not work...

type ToJsonDefaults with 
    static member inline ToJson (x: IDictionary<int64, Monkey>) =
        x.ToJson()

And I take a look at the source code:

    let inline internal toJsonDefaults (a: ^a, _: ^b) =
        ((^a or ^b) : (static member ToJson: ^a -> unit Json) a)

But I couldn't understand this syntax... would you please give me some clue / url / doc for understand this syntax? (esp. ((^a or ^b) : (static member ToJson: ^a -> unit Json) a))

Thank you so much!!

ingted commented 7 years ago

Hi,

I got some workaround:

type Dicttc = Dicttc of IDictionary<int64, Monkey>

[<Extension>]
type ExtensionMethds2 () = 
    [<Extension>]
    static member inline ToJson2 (dic: Dicttc): Json<unit> =
        let ddic = (fun (Dicttc d) -> d) dic 
        Seq.fold (fun (sn : Json<unit>) key ->
            let x = ddic.[key]
            sn 
            *> Json.write (key.ToString()) x
            ) (Json.init ()) ddic.Keys

type Dicttc with
    static member ToJson (x : Dicttc) =
        x.ToJson2()

let dictest = Dicttc (dict [123L, { sound = "ooh"; height = 1.53m }; 456L, { sound = "ooh"; height = 1.53m }])
Json.format (Json.serialize dictest)

The result is:

val it : string =
  "{"123":{"height":1.53,"sound":"ooh"},"456":{"height":1.53,"sound":"ooh"}}"
ingted commented 7 years ago

Hi again,

A refinement... no extension method required! (in the fact, extension method way caused another issues.)

type Ooo = Ooo of IDictionary<int64, Monkey[]> with
    static member ToJson (x: Ooo) =
        let xx = (fun (Ooo d) -> d) x 
        Seq.fold (fun (sn : Json<unit>) key ->
            let xxx = xx.[key]
            sn 
            *> Json.write (key.ToString()) xxx
            ) (Json.init ()) xx.Keys

let dictest2 = Ooo   (dict [123L, [|{ sound = "ooh"; height = 0.53m }|]; 456L, [|{ sound = "ooh2"; height = 1.53m }|]])

Json.format (Json.serialize dictest2)