package ppx_deriving_encoding
Install
Dune Dependency
Authors
Maintainers
Sources
md5=3e928d75f5b165a0ad511d806cab11e5
sha512=97ecaca0f2fad0ad8c5e82d910f665f381796995ee1133f26032f9caa036bcf2a9249c4020e90e935946aafff7e7adedac1bcf817391c35ca00bb97dcffe677b
Description
Published: 27 Apr 2022
README
Json_encoding Ppx deriver
ppx_deriving_encoding is a json-encoding ppx deriver.
type x = {
a : string;
b : int list;
c : Ezjsonm.value option;
} [@@deriving encoding]
will produce the encoding:
let x_enc : x encoding =
conv
(fun {a; b; c} -> (a, b, c))
(fun (a, b, c) -> {a; b; c})
(obj3
(req "a" string)
(req "b" (list int))
(opt "c" any_ezjson_value))
Most of regular json types are handled. GADT and variant inheritance are not handled yet.
Field Options
[@dft expr]
Default field insteada : x [@dft expr]
will produce a field :
(dft "a" x_enc expr)
[@opt]
Optional field (undefined)a : x [@opt]
will produce a field :
(opt "a" x_enc)
[@ddft expr]
Default field always constructeda : x [@ddft expr]
will produce a field :
(dft ~construct:true "a" x_enc expr)
[@req]
(for an option type) Nullable field instead ofdft "..." (option enc) None
a : x option [@req]
will produce a field :
(req "a" (option x_enc))
[@key "name"]
Specify the name of the fielda : x [@key "name"]
will produce a field :
(req "name" x_enc)
[@title expr]
Specify the title of the fielda : x [@title expr]
will produce a field :
(req ~title:expr "a" x_enc)
[@description expr]
Specify the description of the fielda : x [@description expr]
will produce a field :
(req ~description:expr "a" x_enc)
[@exclude expr]
Exclude a field from an encoding{ a : x; b : y; [@exclude y_default] c : z; }
will produce :
conv (fun {a; _; c} -> (a, c)) (fun (a, c) -> {a; b = y_default; c}) (obj2 (req "a" x_enc) (req "c" z_enc))
[@merge]
Merge an field object instead of creating another field{ a : x; [@merge] b : z; }
will produce :
conv (fun {a; _; c} -> (a, c)) (fun (a, c) -> {a; b = y_default; c}) (merge_objs x_enc (obj1 (req "c" z_enc)))
[@camel]
or[@snake]
format the field in snake or camel case[@set <encoding>]
,[@map <key_encoding>]
create an encoding from Set or Map modulesmodule SMap = Map.Make(String) type x = { a : int SMap.t [@map string] } [@@deriving encoding]
will produce :
let x_enc = conv (fun { a } -> a) (fun a -> { a }) @@ (obj1 (req "a" (conv SMap.bindings (fun l -> List.fold_left (fun acc -> fun (k, v) -> SMap.add k v acc) SMap.empty l) (list (tup2 string int)))))
General options
[@assoc]
Create an assoc encoding
(string * x) list [@assoc]
will produce :
assoc x_enc
[@enum]
Create an string enum encoding
[ `A | `B | `C ]
will produce :
string_enum [ "a", `A ; "b" `B; "c", `C ]
For normal type constructor, you need to use the flag attribute:
type t = A | B | C [@@deriving encoding {enum}]
[@encoding expr]
Assign a generic encoding
[@obj1 "name"]
/[@wrap "name"]
Wrap an encoding inside a obj1 encoding
Tuple options
[@object]
Create an object encoding from a tuple
( w, x [@exclude x_default], y [@key "name"], z ) [@object]
will produce:
conv (fun (w, _, y, z) -> (w, y, z)) (fun (w, y, z) -> (w, x_default, y, z)) (obj3 (req "0" w_enc) (req "name" y_enc) (req "3" z_enc))
Variant options
If it is not a string enumeration, any constructor or polymorphic variant will produce a union encoding. Any case of the union can receive [@title expr]
, [@description expr]
, [@kind "kind"]
attributes.
[@kind "kind_name"]
will add the encoding
(obj1 (req "kind" (constant "kind_name")))
to allow several constructor with the same type to be well desctructed.
If the string literal is omitted, the kind name will be derived from the constructor name. The label can also be changed from "kind"
using [@kind_label "kind_label_name"]
.
For an empty constructor, the default behaviour will use the constant
encoding with the name derived from the name of the constructor. It can be set to empty
with the [@empty]
attribute.
type t =
| A of x [@kind "a"]
| B of y
| C of x [@kind]
| D of z [@kind "bla"] [@kind_label "category"]
| E
| F [@empty]
[@@deriving encoding]
will produce :
let enc =
union [
case
(conv (fun x -> (), x) (fun ((), x) -> x)
(merge_objs (obj1 (req "kind" (constant "a"))) x_enc))
(function A x -> Some x | _ -> None)
(fun x -> A x);
case
y_enc
(function B x -> Some x | _ -> None)
(fun x -> B x);
case
(conv (fun x -> (), x) (fun ((), x) -> x)
(merge_objs (obj1 (req "kind" (constant "c"))) x_enc))
(function C x -> Some x | _ -> None)
(fun x -> C x);
case
(conv (fun x -> (), x) (fun ((), x) -> x)
(merge_objs (obj1 (req "category" (constant "bla"))) z_enc))
(function D x -> Some x | _ -> None)
(fun x -> D x);
case
(constant "e")
(function E -> Some () | _ -> None)
(fun () -> E);
case
empty
(function F -> Some () | _ -> None)
(fun () -> F);
]
Top type options
ignore
wrap an object encoding to ignore other fieldstype t = { a : x; b : y; } [@@deriving encoding {ignore}]
will produce :
let enc = conv (fun x -> (), x) (fun ((), x) -> x) (merge_objs unit (conv (fun {a; b} -> (a, b)) (fun (a, b) -> {a; b}) (obj2 (req "a" x_enc) (req "b" y_enc))))
It can also be used as an attribute for records in constructor:
type x = | A of { a : y } [@ignore] | B of t
remove_prefix
Remove prefixes of record
type x = { xyza : a; xyzb : b; } [@@deriving encoding {remove_prefix = "xy"}] (* or {remove_prefix = 2} *)
will produce :
let x_enc = conv (fun {x_a; x_b} -> (x_a, x_b)) (fun (x_a, x_b) -> {x_a; x_b}) (obj2 (req "za" a_enc) (req "zb" b_enc))
By default, the ppx will try to remove the longest common chain. It the example above, if
remove_prefix
wasn't mentionned, the ppx would have removedxyz
. You can also remove this behaviour with[@@deriving encoding {remove_prefix=false}]
.recursive
Wrap an encoding in a recursive construction
type x = | A of x | B [@@deriving encoding {recursive}]
will produce :
let x_enc = mu "x" (fun enc -> union [ case enc (function A x -> Some x | _ -> None) (fun x -> A x); case empty (function B -> Some () | _ -> None) (fun () -> B) ])
title
,description
Wrap en encoding to add some description
type x = y [@@deriving encoding {title = "title"; description = "descr"}]
will produce :
let x_enc = def "x" ~title:"title" ~description:"descr" y_enc
schema
Wrap an encoding to add a schema
type x = y [@@deriving encoding {schema = sch}]
will produce :
let x_enc = conv (fun x -> x) (fun x -> x) ~schema:sch y_enc
option
By default an option field will be dealt as
dft "field_name" (option enc) None
to be able to catch undefined and null values, but it is sometime not the wanted behaviour and in some cases even not allowed (for example if the encoding dealing with the type is nullable:dft "name" (option any_ezjsonm) None
will break the execution). You can change the default behaviour:type x = { a : string option } [@@deriving encoding {option = "req"}] type y = { a : string option } [@@deriving encoding {option = "opt"}] type z = { a : string option } [@@deriving encoding {option = "dft"}]
will produce :
let x_enc = obj1 (req "a" (option string)) let y_enc = obj1 (opt "a" string) let z_enc = obj1 (dft "a" (option string) None)
debug
Force the printing of the produced encoding during compilation
name
By default the name of the encoding produced is
<typename>_enc
, Using thisname
option, you can choose to change it.module_name
This ppx deriver can be used with other module than
Json_encoding
if they follow the same interface thanJson_encoding
(or rather a sub part of it that you can get insrc/utils.ml
). This can be done by mentionning themodule_name
option. As a dummy example:open Json_encoding type x = int [@@deriving encoding {module_name=""}]
will work fine.
camel
orsnake
Flag to format all fields in camel or snake casewrap
Wrap the type in an obj1
Compilation environnement variables
Here are some environnement variables that can be useful:
PPX_ENCODING_DEBUG
:Can be set to true, false or some verbose level. It will print all the expression produced by the ppx.
PPX_ENCODING_MODULE
:Set the module name for all expression derived using the environnement.
PPX_ENCODING_FAKE
:Will not produce any encoding. It can be useful if you just wish to copy some file using this deriver but you don't have access to
json-data-encoding
at this time.