Page
Library
Module
Module type
Parameter
Class
Class type
Source
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.
[@dft expr]
Default field instead
a : 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 constructed
a : x [@ddft expr]
will produce a field :
(dft ~construct:true "a" x_enc expr)
[@req]
(for an option type) Nullable field instead of dft "..." (option enc) None
a : x option [@req]
will produce a field :
(req "a" (option x_enc))
[@key "name"]
Specify the name of the field
a : x [@key "name"]
will produce a field :
(req "name" x_enc)
[@title expr]
Specify the title of the field
a : x [@title expr]
will produce a field :
(req ~title:expr "a" x_enc)
[@description expr]
Specify the description of the field
a : 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 modules
module 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)))))
[@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
[@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))
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);
]
ignore
wrap an object encoding to ignore other fields
type 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 removed xyz
. 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 this name
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 than Json_encoding
(or rather a sub part of it that you can get in src/utils.ml
). This can be done by mentionning the module_name
option. As a dummy example:
open Json_encoding
type x = int [@@deriving encoding {module_name=""}]
will work fine.
camel
or snake
Flag to format all fields in camel or snake casewrap
Wrap the type in an obj1Here 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.