Thoth.Json icon indicating copy to clipboard operation
Thoth.Json copied to clipboard

Is it the time now to include Codec support?

Open MangelMaxime opened this issue 5 years ago • 3 comments

Inspiration: https://package.elm-lang.org/packages/miniBill/elm-codec/latest/Codec#Codec

Ideas comes from twitter: https://twitter.com/huwmanity/status/1298891485258166272

And this is something I wanted to do for a long time as there is no good way to declare encoder/decoder right now and they can get out of sync easily etc.

It should also be designed with recommendation on how to structure the code to make it easier to use/transparent independently from the type attached to it from the final user POV.

For example, attach as a class member for DUs, classes etc.

Using a module of the name of the type for the type who can't have members.

Pseudocode to explains my idea:

open Thoth.Json
open Fable.Core

type Codec<'T> =
    {
        Encoder : obj
        Decoder : obj
    }

type MyEnum =
    | Value1 = 0
    | Value2 = 2

module MyEnum =

    let codec : Codec<MyEnum> = 
        {
            Encoder = 
                //...
                ""
            Decoder =
                //...
                ""
        }

type Animal =
    | Dog
    | Cat 

    static member codec : Codec<Animal> = 
        {
            Encoder = 
                //...
                ""
            Decoder =
                //...
                ""
        }

// Final user usage

MyEnum.codec |> ignore

Animal.codec |> ignore

MangelMaxime avatar Aug 27 '20 08:08 MangelMaxime

Here are some basic examples of codecs for unions I created using my port of the codec library:

module Example =
    open MiniBill.ElmCodec.Net

    type Animal =
    | Dog
    | Cat

    module Animal =
        let codec =
            Codec.custom
                (fun dog cat->
                    function
                    | Dog -> dog
                    | Cat -> cat
                )
            |> Codec.variant0 "dog" Dog
            |> Codec.variant0 "cat" Cat
            |> Codec.buildCustom

    type Input =
        | Digit of int
        | Letter of char 

    module Input =  
        let codec = 
            Codec.custom
                (fun digit letter -> 
                    function 
                    | Digit n -> digit n
                    | Letter c -> letter c
                )
            |> Codec.variant1 "digit" Digit Codec.int
            |> Codec.variant1 "letter" Letter Codec.char
            |> Codec.buildCustom

    type User =
        { EmailAddress: string
          PasswordHash: byte array
          Role: string
          Forenames: string
          Surname: string
        }

   module User =
        let codec : Codec<User> =
            Codec.object
                (fun emailAddress passwordHash role forenames surname ->
                    { EmailAddress = emailAddress
                      PasswordHash = passwordHash
                      Role = role
                      Forenames = forenames
                      Surname = surname
                    })
            |> Codec.field "emailAddress" (fun o -> o.EmailAddress) Codec.string
            |> Codec.field "passwordHash" (fun o -> o.PasswordHash) (Codec.array Codec.byte)
            |> Codec.field "role" (fun o -> o.Role) Codec.string
            |> Codec.field "forenames" (fun o -> o.Forenames) Codec.string
            |> Codec.field "surname" (fun o -> o.Surname) Codec.string
            |> Codec.buildObject

huwmanatee avatar Aug 27 '20 13:08 huwmanatee

Not sure if this feature is still planned, but I was interested in what could be done building on top of the library without modifying it.

I put together a proof-of-concept library here: https://github.com/njlr/thoth-json-codec

I think the new Applicative CEs make this quite nice in F#!

njlr avatar May 22 '22 23:05 njlr

@njlr I like what you have done with your Codec library, especially the Computation Expressions.

huwmanatee avatar Jul 07 '22 13:07 huwmanatee