Skip to content

Commit c8ccdf4

Browse files
committed
Update docs
1 parent cf6e889 commit c8ccdf4

File tree

4 files changed

+84
-92
lines changed

4 files changed

+84
-92
lines changed

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,12 @@ let colorEncoder = function
279279
let colorCodec () = colorDecoder <-> colorEncoder
280280
281281
let carCodec () =
282-
fun i c k -> { Id = i; Color = c; Kms = k }
283-
|> withFields
284-
|> jfieldWith Codecs.string "id" (fun x -> x.Id)
285-
|> jfieldWith (colorCodec ()) "color" (fun x -> x.Color)
286-
|> jfieldWith Codecs.int "kms" (fun x -> x.Kms)
282+
codec {
283+
let! i = jreqWith Codecs.string "id" (fun x -> Some x.Id)
284+
and! c = jreqWith colorCodec "color" (fun x -> Some x.Color)
285+
and! k = jreqWith Codecs.int "kms" (fun x -> Some x.Kms)
286+
return { Id = i; Color = c; Kms = k }
287+
}
287288
|> Codec.compose (Codecs.propList Codecs.id)
288289
289290
let car = { Id = "xyz"; Color = Red; Kms = 0 }
@@ -292,6 +293,13 @@ let jsonCar : Fleece.SystemTextJson.Encoding = Codec.encode (carCodec ()) car
292293
// val jsonCar: SystemTextJson.Encoding = {"id":"xyz","color":"red","kms":0}
293294
```
294295

296+
### Json Lenses
297+
298+
Json lenses allow to focus on a specific part of the json structure to perform operations live view, write and update.
299+
300+
For a quick reference have a look at this test file https://github.com/fsprojects/Fleece/blob/master/test/Tests/Lenses.fs
301+
302+
295303
## Maintainer(s)
296304

297305
- [@mausch](https://github.com/mausch)

docsrc/content/codec.fsx

Lines changed: 54 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,20 @@
66
#r @"../../src/Fleece.SystemJson/bin/Release/netstandard2.0/Fleece.dll"
77
#r @"../../src/Fleece.SystemJson/bin/Release/netstandard2.0/Fleece.SystemJson.dll"
88

9-
open Fleece
10-
open Fleece.SystemJson
11-
open Fleece.SystemJson.Operators
12-
13-
149
(**
1510
1611
## CODEC
1712
1813
```f#
1914
#r "nuget: Fleece.SystemJson"
15+
```
16+
*)
17+
18+
open Fleece
2019
open Fleece.SystemJson
2120
open Fleece.SystemJson.Operators
22-
```
2321

22+
(**
2423
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.
2524
*)
2625

@@ -31,16 +30,16 @@ type Person = {
3130
with
3231
static member JsonObjCodec =
3332
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))
3635
<*> jopt "age" (fun x -> x.age) // Optional fields: use 'jopt'
3736
<*> jreq "children" (fun x -> Some x.children)
3837

3938

4039
let p = {name = ("John", "Doe"); age = None; children = [{name = ("Johnny", "Doe"); age = Some 21; children = []}]}
4140
//printfn "%s" (string (toJson p))
4241

43-
let john = parseJson<Person> """{
42+
let john = ofJsonText<Person> """{
4443
"children": [{
4544
"children": [],
4645
"age": 21,
@@ -52,21 +51,21 @@ let john = parseJson<Person> """{
5251
}"""
5352

5453
(**
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:
5655
*)
5756

5857
type PersonF = {
5958
name : string * string
6059
age : int option
6160
children: PersonF list }
6261
with
63-
static member JsonObjCodec =
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 member JsonObjCodec = 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+
}
7069

7170
(**
7271
Both approaches build a codec from the same pieces:
@@ -79,30 +78,28 @@ Discriminated unions can be modeled with alternatives:
7978
*)
8079

8180
type Shape =
82-
| Rectangle of width : float * length : float
83-
| Circle of radius : float
84-
| Prism of width : float * float * height : float
81+
| Rectangle of width : float * length : float
82+
| Circle of radius : float
83+
| Prism of width : float * float * height : float
8584
with
8685
static member JsonObjCodec =
8786
Rectangle <!> jreq "rectangle" (function Rectangle (x, y) -> Some (x, y) | _ -> None)
8887
<|> ( Circle <!> jreq "radius" (function Circle x -> Some x | _ -> None) )
8988
<|> ( Prism <!> jreq "prism" (function Prism (x, y, z) -> Some (x, y, z) | _ -> None) )
9089
(**
91-
or using the jchoice combinator:
90+
or using the codec computation expression:
9291
*)
9392

9493
type ShapeC =
9594
| Rectangle of width : float * length : float
9695
| Circle of radius : float
9796
| Prism of width : float * float * height : float
9897
with
99-
static member JsonObjCodec =
100-
jchoice
101-
[
102-
Rectangle <!> jreq "rectangle" (function Rectangle (x, y) -> Some (x, y) | _ -> None)
103-
Circle <!> jreq "radius" (function Circle x -> Some x | _ -> None)
104-
Prism <!> jreq "prism" (function Prism (x, y, z) -> Some (x, y, z) | _ -> None)
105-
]
98+
static member JsonObjCodec = codec {
99+
Rectangle <!> jreq "rectangle" (function Rectangle (x, y) -> Some (x, y) | _ -> None)
100+
Circle <!> jreq "radius" (function Circle x -> Some x | _ -> None)
101+
Prism <!> jreq "prism" (function Prism (x, y, z) -> Some (x, y, z) | _ -> None)
102+
}
106103

107104
(**
108105
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 =
116113
| South
117114
| West
118115
with
119-
static member JsonObjCodec =
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 member JsonObjCodec = 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+
}
127122

128123

129124
(**
@@ -152,51 +147,47 @@ let someShapes = """
152147

153148
open FSharpPlus
154149
open FSharpPlus.Operators
155-
open FSharpPlus.Data
156150

157-
open Fleece.Operators
158151

159152
type ShapeD =
160-
| Rectangle of width : float * length : float
161-
| Circle of radius : float
162-
| Prism of width : float * float * height : float
153+
| Rectangle of width : float * length : float
154+
| Circle of radius : float
155+
| Prism of width : float * float * height : float
163156
with
164157
static member JsonObjCodec =
165-
/// Derives a concrete field codec for a required field and value
158+
/// Derives a field codec for a required field and value
166159
let inline jreqValue prop value codec =
167160
let matchPropValue o =
168161
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
170163
| 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
173166
|> Codec.compose (
174-
matchPropValue <->
175-
fun (encoded: PropertyList<Encoding>) ->
176-
if encoded.Count=0 then encoded // we have not encoded anything so no need to add property and value
177-
else PropertyList [|prop, toJson value|] ++ encoded
178-
)
179-
|> Codec.toConcrete
180-
167+
matchPropValue <->
168+
fun (encoded: PropertyList<Encoding>) ->
169+
if encoded.Count = 0 then encoded // we have not encoded anything so no need to add property and value
170+
else PropertyList [|prop, toJson value|] ++ encoded
171+
)
181172

182173
jchoice
183174
[
184-
fun w l -> Rectangle (w,l)
185-
<!> jreq "width" (function Rectangle(w, _) -> Some w | _ -> None)
175+
fun w l -> Rectangle (w, l)
176+
<!> jreq "width" (function Rectangle(w, _) -> Some w | _ -> None)
186177
<*> jreq "length" (function Rectangle(_, l) -> Some l | _ -> None)
187178
|> jreqValue "type" "rectangle"
188179

189180
Circle
190-
<!> jreq "radius" (function Circle (r) -> Some r | _ -> None)
181+
<!> jreq "radius" (function Circle r -> Some r | _ -> None)
191182
|> jreqValue "type" "circle"
192183

193-
fun (w,w2) h -> Prism (w,w2,h)
194-
<!> jreq "width" (function Prism (x, y, _) -> Some (x, y) | _ -> None)
195-
<*> jreq "height" (function Prism (_, _, h) -> Some h | _ -> None)
184+
fun (w, w2) h -> Prism (w, w2, h)
185+
<!> jreq "width" (function Prism (x, y, _) -> Some (x, y) | _ -> None)
186+
<*> jreq "height" (function Prism (_, _, h) -> Some h | _ -> None)
196187
|> jreqValue "type" "prism"
197188
]
198189

199-
let parsedShapedD = parseJson<ShapeD list> someShapes
190+
let parsedShapedD = ofJsonText<ShapeD list> someShapes
200191

201192
(**
202193
We can manipulate codecs by using functions in the Codec module. Here's an example:
@@ -207,22 +198,10 @@ let pf : PersonF= {name = ("John", "Doe"); age = None; children = [{name = ("Joh
207198
let personBytesCodec =
208199
let getString (bytes:byte array) = Encoding.UTF8.GetString bytes
209200
PersonF.JsonObjCodec
210-
|> Codec.compose jsonObjToValueCodec // this is the codec that fills the gap to/from JsonValue
211-
|> Codec.compose jsonValueToTextCodec // this is a codec between JsonValue and JsonText
212-
|> Codec.invmap getString Encoding.UTF8.GetBytes // This is a pair of of isomorphic functions
201+
|> Codec.compose jsonObjToValueCodec // this is the codec that fills the gap to/from JsonValue
202+
|> Codec.compose jsonValueToTextCodec // this is a codec between JsonValue and JsonText
203+
|> Codec.invmap getString Encoding.UTF8.GetBytes // This is a pair of of isomorphic functions
213204

214205
let bytePerson = Codec.encode personBytesCodec pf
215206
// val bytePerson : byte [] = [|123uy; 13uy; 10uy; 32uy; 32uy; ... |]
216-
let p' = Codec.decode personBytesCodec bytePerson
217-
218-
(**
219-
While if the type of codec is concrete then we need to convert it to before composing it
220-
*)
221-
222-
let personBytesCodec2 =
223-
let getString (bytes:byte array) = Encoding.UTF8.GetString bytes
224-
Person.JsonObjCodec
225-
|> Codec.ofConcrete
226-
|> Codec.compose jsonObjToValueCodec // this is the codec that fills the gap to/from JsonValue
227-
|> Codec.compose jsonValueToTextCodec // this is a codec between JsonValue and JsonText
228-
|> Codec.invmap getString Encoding.UTF8.GetBytes // This is a pair of of isomorphic functions
207+
let p' = Codec.decode personBytesCodec bytePerson

docsrc/content/combinators.fsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
#r @"../../src/Fleece.SystemJson/bin/Release/netstandard2.0/Fleece.dll"
77
#r @"../../src/Fleece.SystemJson/bin/Release/netstandard2.0/Fleece.SystemJson.dll"
88

9-
open Fleece
10-
open Fleece.Operators
11-
open Fleece.SystemJson
12-
open Fleece.SystemJson.Operators
139

1410
(**
1511
```f#
1612
#r "nuget: Fleece.SystemJson"
17-
open Fleece.SystemJson
1813
```
1914
15+
*)
16+
17+
open Fleece
18+
open Fleece.SystemJson
19+
open Fleece.SystemJson.Operators
20+
21+
(**
22+
2023
## Combinators
2124
2225
So far we've seen how Fleece is capable of encoding/decoding by deriving automatically a codec from static members in the type.
@@ -50,12 +53,13 @@ let colorEncoder = function
5053
let colorCodec = colorDecoder <-> colorEncoder
5154

5255
let [<GeneralizableValue>]carCodec<'t> =
53-
fun i c k -> { Id = i; Color = c; Kms = k }
54-
|> withFields
55-
|> jfieldWith Codecs.string "id" (fun x -> x.Id)
56-
|> jfieldWith colorCodec "color" (fun x -> x.Color)
57-
|> jfieldWith Codecs.int "kms" (fun x -> x.Kms)
58-
|> Codec.compose jsonObjToValueCodec
56+
codec {
57+
let! i = jreqWith Codecs.string "id" (fun x -> Some x.Id)
58+
and! c = jreqWith colorCodec "color" (fun x -> Some x.Color)
59+
and! k = jreqWith Codecs.int "kms" (fun x -> Some x.Kms)
60+
return { Id = i; Color = c; Kms = k }
61+
}
62+
|> Codec.compose (Codecs.propList Codecs.id)
5963

6064
let car = { Id = "xyz"; Color = Red; Kms = 0 }
6165

src/Fleece/Compatibility.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ module Operators =
229229
/// A codec to encode a Json value to a Json text and the other way around.
230230
let jsonValueToTextCodec = (fun x -> try Ok (Encoding.Parse x) with e -> Decode.Fail.parseError e x) <-> (fun (x: Encoding) -> string x)
231231

232-
let inline parseJson (x: string) : ParseResult<'T> = Codec.decode jsonValueToTextCodec x >>= Operators.ofJson
232+
let inline parseJson<'T when (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
233234

234235
let inline jreq name getter = jreq name getter : Codec<PropertyList<Encoding>,_,_,_>
235236
let inline jopt name getter = jopt name getter : Codec<PropertyList<Encoding>,_,_,_>

0 commit comments

Comments
 (0)