You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For types that deserialize to Json Objets, typically (but not limited to) records, you can alternatively use codecs and have a single method which maps between fields and values.
25
24
*)
26
25
@@ -31,16 +30,16 @@ type Person = {
31
30
with
32
31
static memberJsonObjCodec=
33
32
fun f l a c ->{ name =(f, l); age = a; children = c }
34
-
<!> jreq "firstName"(Some <<fun x -> fst x.name)
35
-
<*> jreq "lastName"(Some <<fun x -> snd x.name)
33
+
<!> jreq "firstName"(fun x ->Some (fst x.name))
34
+
<*> jreq "lastName"(fun x ->Some (snd x.name))
36
35
<*> jopt "age"(fun x -> x.age)// Optional fields: use 'jopt'
37
36
<*> jreq "children"(fun x -> Some x.children)
38
37
39
38
40
39
letp={name =("John","Doe"); age = None; children =[{name =("Johnny","Doe"); age = Some 21; children =[]}]}
41
40
//printfn "%s" (string (toJson p))
42
41
43
-
letjohn=parseJson<Person>"""{
42
+
letjohn=ofJsonText<Person>"""{
44
43
"children": [{
45
44
"children": [],
46
45
"age": 21,
@@ -52,21 +51,21 @@ let john = parseJson<Person> """{
52
51
}"""
53
52
54
53
(**
55
-
If you prefer you can write the same with functions:
54
+
If you prefer you can write the same with a codec computation expression:
56
55
*)
57
56
58
57
typePersonF={
59
58
name :string * string
60
59
age :int option
61
60
children:PersonF list }
62
61
with
63
-
static memberJsonObjCodec=
64
-
fun f l a c ->{ name =(f, l); age = a; children = c }
65
-
|> withFields
66
-
|> jfield "firstName"(fun x ->fst x.name)
67
-
|> jfield "lastName"(fun x ->snd x.name)
68
-
|> jfieldOpt "age"(fun x -> x.age)
69
-
|> jfieldWithLazy (fun()-> jsonValueCodec)"children"(fun x -> x.children)
62
+
static memberJsonObjCodec= codec {
63
+
let!f= jreq "firstName"(fun x ->Some (fst x.name))
64
+
and! l = jreq "lastName"(fun x -> Some (snd x.name))
65
+
and! a = jopt "age"(fun x ->x.age)
66
+
and! c = jreq "children"(fun x ->Some x.children)
67
+
return{ name =(f, l); age = a; children = c }
68
+
}
70
69
71
70
(**
72
71
Both approaches build a codec from the same pieces:
@@ -79,30 +78,28 @@ Discriminated unions can be modeled with alternatives:
Circle <!> jreq "radius"(function Circle x -> Some x |_-> None)
101
+
Prism <!> jreq "prism"(function Prism (x, y, z)-> Some (x, y, z)|_-> None)
102
+
}
106
103
107
104
(**
108
105
What's happening here is that we're getting a Codec to/from a Json Object (not neccesarily a JsonValue) which Fleece is able to take it and fill the gap by composing it with a codec from JsonObject to/from JsonValue.
@@ -116,14 +113,12 @@ type CompassDirection =
116
113
| South
117
114
| West
118
115
with
119
-
static memberJsonObjCodec=
120
-
jchoice
121
-
[
122
-
(fun()-> North)<!> jreq "north"(function North -> Some ()|_-> None)
123
-
(fun()-> South)<!> jreq "south"(function South -> Some ()|_-> None)
124
-
(fun()-> East)<!> jreq "east"(function East -> Some ()|_-> None)
125
-
(fun()-> West)<!> jreq "west"(function West -> Some ()|_-> None)
126
-
]
116
+
static memberJsonObjCodec= codec {
117
+
(fun()-> North)<!> jreq "north"(function North -> Some ()|_-> None)
118
+
(fun()-> South)<!> jreq "south"(function South -> Some ()|_-> None)
119
+
(fun()-> East)<!> jreq "east"(function East -> Some ()|_-> None)
120
+
(fun()-> West)<!> jreq "west"(function West -> Some ()|_-> None)
121
+
}
127
122
128
123
129
124
(**
@@ -152,51 +147,47 @@ let someShapes = """
152
147
153
148
openFSharpPlus
154
149
openFSharpPlus.Operators
155
-
openFSharpPlus.Data
156
150
157
-
openFleece.Operators
158
151
159
152
typeShapeD=
160
-
| Rectangle ofwidth:float*length:float
161
-
| Circle ofradius:float
162
-
| Prism ofwidth:float*float*height:float
153
+
| Rectangle ofwidth:float*length:float
154
+
| Circle ofradius:float
155
+
| Prism ofwidth:float*float*height:float
163
156
with
164
157
static memberJsonObjCodec=
165
-
/// Derives a concrete field codec for a required field and value
158
+
/// Derives a field codec for a required field and value
166
159
let inlinejreqValue prop value codec =
167
160
letmatchPropValue o =
168
161
match IReadOnlyDictionary.tryGetValue prop o with
169
-
| Some a when(ofJson a)= Ok value -> Ok o
162
+
| Some a when ofJson a = Ok value -> Ok o
170
163
| Some a -> Decode.Fail.invalidValue a value
171
-
| None -> Decode.Fail.propertyNotFound prop o
172
-
Codec.ofConcrete codec
164
+
| None -> Decode.Fail.propertyNotFound prop o
165
+
codec
173
166
|> Codec.compose (
174
-
matchPropValue <->
175
-
fun(encoded: PropertyList<Encoding>)->
176
-
if encoded.Count=0then encoded // we have not encoded anything so no need to add property and value
Copy file name to clipboardExpand all lines: src/Fleece/Compatibility.fs
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -229,7 +229,8 @@ module Operators =
229
229
/// A codec to encode a Json value to a Json text and the other way around.
230
230
letjsonValueToTextCodec=(fun x ->try Ok (Encoding.Parse x)with e -> Decode.Fail.parseError e x)<->(fun(x: Encoding)-> string x)
231
231
232
-
let inlineparseJson(x:string):ParseResult<'T>= Codec.decode jsonValueToTextCodec x >>= Operators.ofJson
232
+
let inlineparseJson<'Twhen(Internals.GetDec or ^T):(static member GetCodec:^T*Internals.GetDec *Internals.GetDec *Internals.OpDecode ->Codec<Encoding,^T>)>(x:string):ParseResult<'T>=
233
+
Codec.decode jsonValueToTextCodec x >>= Operators.ofJson
233
234
234
235
let inlinejreq name getter = jreq name getter : Codec<PropertyList<Encoding>,_,_,_>
235
236
let inlinejopt name getter = jopt name getter : Codec<PropertyList<Encoding>,_,_,_>
0 commit comments