基于Fleece为复杂嵌套可辨识联合(DU)实现正确的JsonObjCodec
Let's break down why your codec is failing and fix it step by step. The core issue is that you're only handling the encoding side (converting your DUs to strings) but not the decoding side (converting strings back to your DUs), which creates a type mismatch between what jreq returns and what your DU constructors expect. Additionally, you're not leveraging existing codecs for types like BiometricMeasure correctly.
Here's the corrected JsonObjCodec for BiometricRules:
open Fleece open Fleece.NewtonsoftJson open FSharpPlus 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 with static member JsonObjCodec = // Age case: Convert encoded string pair back to Comparator and AgeMeasure Age <!> (jreq "Age" (function Age (comp, am) -> Some (string comp, string am) | _ -> None) |> map (fun (cStr, amStr) -> Comparator.FromString cStr, AgeMeasure.FromString amStr)) <|> // Glycemia case: Convert comparator string back to DU; use BiometricMeasure's existing codec (Glycemia <!> (jreq "Glycemia" (function Glycemia (comp, bm) -> Some (string comp, bm) | _ -> None) |> map (fun (cStr, bm) -> Comparator.FromString cStr, bm))) <|> // Biometric case: Convert BiometricType and Comparator strings back to their DUs (Biometric <!> (jreq "BiometricRule" (function Biometric (bt, comp, bm) -> Some (string bt, string comp, bm) | _ -> None) |> map (fun (btStr, cStr, bm) -> BiometricType.FromString btStr, Comparator.FromString cStr, bm))) <|> // Sex case: Convert encoded string back to SexMeasure (Sex <!> (jreq "Sex" (function Sex s -> Some (string s) | _ -> None) |> map SexMeasure.FromString)) <|> // MedicalCondition case: Use its pre-defined JsonObjCodec directly (MedicalCondition <!> jreq "MedicalCondition" (function MedicalCondition mc -> Some mc | _ -> None)) <|> // Score case: Convert ScoreType and Comparator strings back to their DUs (Score <!> (jreq "Score" (function Score (st, comp, sm) -> Some (string st, string comp, sm) | _ -> None) |> map (fun (stStr, cStr, sm) -> ScoreType.FromString stStr, Comparator.FromString cStr, sm)))
Key Fixes Explained:
Add Decoding Type Conversions
Your original code only converted DUs to strings for encoding, but didn't reverse that process during decoding. Themapfunction bridges this gap: it takes the raw values from the JSON (like strings) and converts them back to your target types using yourFromStringmethods. This resolves the type mismatch that caused the "Map" overload error.Leverage Existing Codecs
For types likeBiometricMeasureandMedicalConditionthat already have their ownJsonObjCodec, you don't need to manually convert them to strings. Fleece will automatically use their codecs to handle serialization/deserialization, which keeps your code clean and avoids custom parsing errors.Handle Multi-Parameter DU Cases
For DUs with multiple parameters (likeAgeorBiometric), we usemapto transform the tuple of raw JSON values into the exact parameter tuple the DU constructor expects.
Additional Notes:
- Consider updating your
FromStringmethods to returnResult<'T, string>instead of usingfailwith—this lets Fleece surface deserialization errors gracefully instead of crashing. - Double-check that all your
ToStringimplementations produce strings thatFromStringcan fully reverse (e.g., no typos or missing edge cases).
内容的提问来源于stack exchange,提问作者Oanta William Richard

