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

Ease way to add JsonObjCodec for types with string transformations #99

Open
williamoanta opened this issue Jan 19, 2021 · 2 comments
Open

Comments

@williamoanta
Copy link

williamoanta commented Jan 19, 2021

I have the following DU which is composed of other DUs or/and Records.

type BiometricRules =
        | Age of Comparator * AgeMeasure
        | Glycemia of Comparator * BiometricMeasure
        | Biometric of BiometricType * Comparator * BiometricMeasure
        | Sex of SexMeasure
        | MedicalCondition of MedicalCondition
        | Score of ScoreType * Comparator * ScoreMeasure

While trying to deserialize and serialize with Fleece, I have written the following JsonObjCodec.

For an unknown reason, it does not compile with the error No overloads match for method 'Map'. All the nested DUs or Records have either a JsonObjCodec or static FromString and ToString methods defined.

Any solution with respect to how I could solve this via Fleece would be appreciated. The library is already deeply used in the project, so changing it would involve too much refactoring.

Below I copy-pasted the definition of the other DU and Records, as reference:

type Comparator =
        | GreaterThan
        | LowerThan
        | LowerThanOrEqual
        | GreaterThanOrEqual
        | EqualTo
    with
        override this.ToString() =
            match this with
            | GreaterThan -> ">"
            | LowerThan -> "<"
            | LowerThanOrEqual -> "<="
            | GreaterThanOrEqual -> ">="
            | EqualTo -> "="   
        static member FromString s =
            match s with
            | ">" -> GreaterThan
            | "<" -> LowerThan
            | ">=" -> GreaterThanOrEqual
            | "<=" -> LowerThanOrEqual
            | "=" -> EqualTo
            | _ -> failwith "Not a valid comparator."


    type AgeMeasure =
        | Years of decimal
        | Months of decimal
        | Weeks of decimal
    with
        override this.ToString() =
            match this with
            | Years y -> string y + " years"
            | Months m -> string m + " months"
            | Weeks w -> string w + " weeks"
        static member FromString (s: string) =
            match s with
            | _ when s.EndsWith("years") -> Years (Decimal.Parse(s.Replace("years", "")))
            | _ when s.EndsWith("months") -> Months (Decimal.Parse(s.Replace("months", "")))
            | _ when s.EndsWith("weeks") -> Weeks (Decimal.Parse(s.Replace("weeks", "")))


    type BiometricMeasure = {
        Value: decimal
        UoM: string option
    } with
        static member JsonObjCodec =
            fun va uom -> {
                Value = va
                UoM = if uom = "NA" then None else Some uom
            }
            <!> jreq "Value" (Some << fun bm -> bm.Value)
            <*> jreq "UoM" (Some << fun bm -> if bm.UoM |> Option.isNone then "NA" else bm.UoM |> Option.get)


    type BiometricType =
        | SBP
        | DBP
        | Glycemia
        | Specified of string
    with
        override this.ToString() =
            match this with
            | SBP -> "SBP"
            | DBP -> "DBP"
            | Glycemia -> "Glycemia"
            | Specified s -> s
        static member FromString s =
            match s with
            | "SBP" -> SBP
            | "DBP" -> DBP
            | "Glycemia" -> Glycemia
            | _ -> Specified s  


    type SexMeasure =
        | Female
        | Male
        | Other of string
    with
        override this.ToString() =
            match this with
            | Female -> "Female"
            | Male -> "Male"
            | Other s -> s
        static member FromString (s: string) =
            match s.ToLower() with
            | "Female" -> Female
            | "Male" -> Male
            | other -> Other other   


    type MedicalCondition =
        | ICD of ICD
        | Other of string
    with
        static member JsonObjCodec =
            ICD <!> jreq "MedicalCondition" (function ICD v -> Some v | _ -> None)            
            <|> (Other <!> jreq "MedicalCondition" (function Other v -> Some v | _ -> None))


    type ScoreType =
        | BMI
        | Other of string 
    with
        override this.ToString() =
            match this with
            | BMI -> "BMI"
            | Other s -> s
        static member FromString s =
            match s with
            | "BMI" -> BMI
            | _ -> Other s  


    type ScoreMeasure = decimal

Libraries Used in project:

    <PackageReference Update="FSharp.Core" Version="4.7" />
    <PackageReference Include="FSharpPlus" Version="1.1.1" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
    <PackageReference Include="Fleece.NewtonsoftJson" Version="0.8.0" />
    <PackageReference Include="FSharp.Data" Version="3.3.3" />

Also posted on StackOverflow

@gusty
Copy link
Member

gusty commented Jan 19, 2021

I answered you in Stack Overflow, basically your JsonObjCodec does conversions to string but not parsing. I suggested some alternative solutions.

But since you opened an issue here I would like to take the opportunity to evaluate adding some utilities in the library to work with types that don't have json transformations but do have transformation to/from string.

It's an interesting scenario for complex things like composing codecs, and take precisely advantage of codec composability properties.

@gusty gusty changed the title Proper JsonObjCodec with Fleece for Complex, Nested Discriminated Unions Ease way to add JsonObjCodec for types with string transformations Jan 19, 2021
@williamoanta
Copy link
Author

williamoanta commented Jan 20, 2021

Thanks for your prompt response! I have also replied on StackOverflow. I would be curious to see what solution you come up with if any.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants