forked from
anil.recoil.org/ocaml-jmap
this repo has no description
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(* Foo/get *)
7
8type get_args = {
9 account_id : Proto_id.t;
10 ids : Proto_id.t list option;
11 properties : string list option;
12}
13
14let get_args ~account_id ?ids ?properties () =
15 { account_id; ids; properties }
16
17let get_args_make account_id ids properties =
18 { account_id; ids; properties }
19
20let get_args_jsont =
21 let kind = "GetArgs" in
22 Jsont.Object.map ~kind get_args_make
23 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
24 |> Jsont.Object.opt_mem "ids" (Jsont.list Proto_id.jsont) ~enc:(fun a -> a.ids)
25 |> Jsont.Object.opt_mem "properties" (Jsont.list Jsont.string) ~enc:(fun a -> a.properties)
26 |> Jsont.Object.finish
27
28type 'a get_response = {
29 account_id : Proto_id.t;
30 state : string;
31 list : 'a list;
32 not_found : Proto_id.t list;
33}
34
35let get_response_jsont (type a) (obj_jsont : a Jsont.t) : a get_response Jsont.t =
36 let kind = "GetResponse" in
37 let make account_id state list not_found =
38 { account_id; state; list; not_found }
39 in
40 Jsont.Object.map ~kind make
41 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
42 |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state)
43 |> Jsont.Object.mem "list" (Jsont.list obj_jsont) ~enc:(fun r -> r.list)
44 |> Jsont.Object.mem "notFound" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.not_found)
45 |> Jsont.Object.finish
46
47(* Foo/changes *)
48
49type changes_args = {
50 account_id : Proto_id.t;
51 since_state : string;
52 max_changes : int64 option;
53}
54
55let changes_args ~account_id ~since_state ?max_changes () =
56 { account_id; since_state; max_changes }
57
58let changes_args_make account_id since_state max_changes =
59 { account_id; since_state; max_changes }
60
61let changes_args_jsont =
62 let kind = "ChangesArgs" in
63 Jsont.Object.map ~kind changes_args_make
64 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
65 |> Jsont.Object.mem "sinceState" Jsont.string ~enc:(fun a -> a.since_state)
66 |> Jsont.Object.opt_mem "maxChanges" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.max_changes)
67 |> Jsont.Object.finish
68
69type changes_response = {
70 account_id : Proto_id.t;
71 old_state : string;
72 new_state : string;
73 has_more_changes : bool;
74 created : Proto_id.t list;
75 updated : Proto_id.t list;
76 destroyed : Proto_id.t list;
77}
78
79let changes_response_make account_id old_state new_state has_more_changes
80 created updated destroyed =
81 { account_id; old_state; new_state; has_more_changes; created; updated; destroyed }
82
83let changes_response_jsont =
84 let kind = "ChangesResponse" in
85 Jsont.Object.map ~kind changes_response_make
86 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
87 |> Jsont.Object.mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
88 |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
89 |> Jsont.Object.mem "hasMoreChanges" Jsont.bool ~enc:(fun r -> r.has_more_changes)
90 |> Jsont.Object.mem "created" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.created)
91 |> Jsont.Object.mem "updated" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.updated)
92 |> Jsont.Object.mem "destroyed" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.destroyed)
93 |> Jsont.Object.finish
94
95(* Foo/set *)
96
97type 'a set_args = {
98 account_id : Proto_id.t;
99 if_in_state : string option;
100 create : (Proto_id.t * 'a) list option;
101 update : (Proto_id.t * Jsont.json) list option;
102 destroy : Proto_id.t list option;
103}
104
105let set_args ~account_id ?if_in_state ?create ?update ?destroy () =
106 { account_id; if_in_state; create; update; destroy }
107
108let set_args_jsont (type a) (obj_jsont : a Jsont.t) : a set_args Jsont.t =
109 let kind = "SetArgs" in
110 let make account_id if_in_state create update destroy =
111 { account_id; if_in_state; create; update; destroy }
112 in
113 Jsont.Object.map ~kind make
114 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
115 |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state)
116 |> Jsont.Object.opt_mem "create" (Proto_json_map.of_id obj_jsont) ~enc:(fun a -> a.create)
117 |> Jsont.Object.opt_mem "update" (Proto_json_map.of_id Jsont.json) ~enc:(fun a -> a.update)
118 |> Jsont.Object.opt_mem "destroy" (Jsont.list Proto_id.jsont) ~enc:(fun a -> a.destroy)
119 |> Jsont.Object.finish
120
121type 'a set_response = {
122 account_id : Proto_id.t;
123 old_state : string option;
124 new_state : string;
125 created : (Proto_id.t * 'a) list option;
126 updated : (Proto_id.t * 'a option) list option;
127 destroyed : Proto_id.t list option;
128 not_created : (Proto_id.t * Proto_error.set_error) list option;
129 not_updated : (Proto_id.t * Proto_error.set_error) list option;
130 not_destroyed : (Proto_id.t * Proto_error.set_error) list option;
131}
132
133let set_response_jsont (type a) (obj_jsont : a Jsont.t) : a set_response Jsont.t =
134 let kind = "SetResponse" in
135 (* All map/list fields in SetResponse can be null per RFC 8620 Section 5.3 *)
136 (* opt_mem handles missing keys, Jsont.option handles explicit null values *)
137 (* Option.join flattens option option -> option *)
138 let join = Option.join in
139 let make account_id old_state new_state created updated destroyed
140 not_created not_updated not_destroyed =
141 { account_id; old_state; new_state;
142 created = join created;
143 updated = join updated;
144 destroyed = join destroyed;
145 not_created = join not_created;
146 not_updated = join not_updated;
147 not_destroyed = join not_destroyed }
148 in
149 (* For updated values, the server may return null or an object - RFC 8620 Section 5.3 *)
150 (* "Id[Foo|null]" means map values can be null, use Jsont.option to handle this *)
151 let nullable_obj = Jsont.(option obj_jsont) in
152 let opt enc = Option.map Option.some enc in
153 Jsont.Object.map ~kind make
154 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
155 |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
156 |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
157 |> Jsont.Object.opt_mem "created" Jsont.(option (Proto_json_map.of_id obj_jsont)) ~enc:(fun r -> opt r.created)
158 |> Jsont.Object.opt_mem "updated" Jsont.(option (Proto_json_map.of_id nullable_obj)) ~enc:(fun r -> opt r.updated)
159 |> Jsont.Object.opt_mem "destroyed" Jsont.(option (list Proto_id.jsont)) ~enc:(fun r -> opt r.destroyed)
160 |> Jsont.Object.opt_mem "notCreated" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_created)
161 |> Jsont.Object.opt_mem "notUpdated" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_updated)
162 |> Jsont.Object.opt_mem "notDestroyed" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_destroyed)
163 |> Jsont.Object.finish
164
165(* Foo/copy *)
166
167type 'a copy_args = {
168 from_account_id : Proto_id.t;
169 if_from_in_state : string option;
170 account_id : Proto_id.t;
171 if_in_state : string option;
172 create : (Proto_id.t * 'a) list;
173 on_success_destroy_original : bool;
174 destroy_from_if_in_state : string option;
175}
176
177let copy_args_jsont (type a) (obj_jsont : a Jsont.t) : a copy_args Jsont.t =
178 let kind = "CopyArgs" in
179 let make from_account_id if_from_in_state account_id if_in_state create
180 on_success_destroy_original destroy_from_if_in_state =
181 { from_account_id; if_from_in_state; account_id; if_in_state; create;
182 on_success_destroy_original; destroy_from_if_in_state }
183 in
184 Jsont.Object.map ~kind make
185 |> Jsont.Object.mem "fromAccountId" Proto_id.jsont ~enc:(fun a -> a.from_account_id)
186 |> Jsont.Object.opt_mem "ifFromInState" Jsont.string ~enc:(fun a -> a.if_from_in_state)
187 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
188 |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state)
189 |> Jsont.Object.mem "create" (Proto_json_map.of_id obj_jsont) ~enc:(fun a -> a.create)
190 |> Jsont.Object.mem "onSuccessDestroyOriginal" Jsont.bool ~dec_absent:false
191 ~enc:(fun a -> a.on_success_destroy_original)
192 ~enc_omit:(fun b -> not b)
193 |> Jsont.Object.opt_mem "destroyFromIfInState" Jsont.string ~enc:(fun a -> a.destroy_from_if_in_state)
194 |> Jsont.Object.finish
195
196type 'a copy_response = {
197 from_account_id : Proto_id.t;
198 account_id : Proto_id.t;
199 old_state : string option;
200 new_state : string;
201 created : (Proto_id.t * 'a) list option;
202 not_created : (Proto_id.t * Proto_error.set_error) list option;
203}
204
205let copy_response_jsont (type a) (obj_jsont : a Jsont.t) : a copy_response Jsont.t =
206 let kind = "CopyResponse" in
207 let make from_account_id account_id old_state new_state created not_created =
208 { from_account_id; account_id; old_state; new_state; created; not_created }
209 in
210 Jsont.Object.map ~kind make
211 |> Jsont.Object.mem "fromAccountId" Proto_id.jsont ~enc:(fun r -> r.from_account_id)
212 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
213 |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
214 |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
215 |> Jsont.Object.opt_mem "created" (Proto_json_map.of_id obj_jsont) ~enc:(fun r -> r.created)
216 |> Jsont.Object.opt_mem "notCreated" (Proto_json_map.of_id Proto_error.set_error_jsont) ~enc:(fun r -> r.not_created)
217 |> Jsont.Object.finish
218
219(* Foo/query *)
220
221type 'filter query_args = {
222 account_id : Proto_id.t;
223 filter : 'filter Proto_filter.filter option;
224 sort : Proto_filter.comparator list option;
225 position : int64;
226 anchor : Proto_id.t option;
227 anchor_offset : int64;
228 limit : int64 option;
229 calculate_total : bool;
230}
231
232let query_args ~account_id ?filter ?sort ?(position = 0L) ?anchor
233 ?(anchor_offset = 0L) ?limit ?(calculate_total = false) () =
234 { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total }
235
236let query_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_args Jsont.t =
237 let kind = "QueryArgs" in
238 let make account_id filter sort position anchor anchor_offset limit calculate_total =
239 { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total }
240 in
241 Jsont.Object.map ~kind make
242 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
243 |> Jsont.Object.opt_mem "filter" (Proto_filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter)
244 |> Jsont.Object.opt_mem "sort" (Jsont.list Proto_filter.comparator_jsont) ~enc:(fun a -> a.sort)
245 |> Jsont.Object.mem "position" Proto_int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.position)
246 ~enc_omit:(fun p -> p = 0L)
247 |> Jsont.Object.opt_mem "anchor" Proto_id.jsont ~enc:(fun a -> a.anchor)
248 |> Jsont.Object.mem "anchorOffset" Proto_int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.anchor_offset)
249 ~enc_omit:(fun o -> o = 0L)
250 |> Jsont.Object.opt_mem "limit" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.limit)
251 |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total)
252 ~enc_omit:(fun b -> not b)
253 |> Jsont.Object.finish
254
255type query_response = {
256 account_id : Proto_id.t;
257 query_state : string;
258 can_calculate_changes : bool;
259 position : int64;
260 ids : Proto_id.t list;
261 total : int64 option;
262}
263
264let query_response_make account_id query_state can_calculate_changes position ids total =
265 { account_id; query_state; can_calculate_changes; position; ids; total }
266
267let query_response_jsont =
268 let kind = "QueryResponse" in
269 Jsont.Object.map ~kind query_response_make
270 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
271 |> Jsont.Object.mem "queryState" Jsont.string ~enc:(fun r -> r.query_state)
272 |> Jsont.Object.mem "canCalculateChanges" Jsont.bool ~enc:(fun r -> r.can_calculate_changes)
273 |> Jsont.Object.mem "position" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.position)
274 |> Jsont.Object.mem "ids" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.ids)
275 |> Jsont.Object.opt_mem "total" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.total)
276 |> Jsont.Object.finish
277
278(* Foo/queryChanges *)
279
280type 'filter query_changes_args = {
281 account_id : Proto_id.t;
282 filter : 'filter Proto_filter.filter option;
283 sort : Proto_filter.comparator list option;
284 since_query_state : string;
285 max_changes : int64 option;
286 up_to_id : Proto_id.t option;
287 calculate_total : bool;
288}
289
290let query_changes_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_changes_args Jsont.t =
291 let kind = "QueryChangesArgs" in
292 let make account_id filter sort since_query_state max_changes up_to_id calculate_total =
293 { account_id; filter; sort; since_query_state; max_changes; up_to_id; calculate_total }
294 in
295 Jsont.Object.map ~kind make
296 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
297 |> Jsont.Object.opt_mem "filter" (Proto_filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter)
298 |> Jsont.Object.opt_mem "sort" (Jsont.list Proto_filter.comparator_jsont) ~enc:(fun a -> a.sort)
299 |> Jsont.Object.mem "sinceQueryState" Jsont.string ~enc:(fun a -> a.since_query_state)
300 |> Jsont.Object.opt_mem "maxChanges" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.max_changes)
301 |> Jsont.Object.opt_mem "upToId" Proto_id.jsont ~enc:(fun a -> a.up_to_id)
302 |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total)
303 ~enc_omit:(fun b -> not b)
304 |> Jsont.Object.finish
305
306type query_changes_response = {
307 account_id : Proto_id.t;
308 old_query_state : string;
309 new_query_state : string;
310 total : int64 option;
311 removed : Proto_id.t list;
312 added : Proto_filter.added_item list;
313}
314
315let query_changes_response_make account_id old_query_state new_query_state total removed added =
316 { account_id; old_query_state; new_query_state; total; removed; added }
317
318let query_changes_response_jsont =
319 let kind = "QueryChangesResponse" in
320 Jsont.Object.map ~kind query_changes_response_make
321 |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id)
322 |> Jsont.Object.mem "oldQueryState" Jsont.string ~enc:(fun r -> r.old_query_state)
323 |> Jsont.Object.mem "newQueryState" Jsont.string ~enc:(fun r -> r.new_query_state)
324 |> Jsont.Object.opt_mem "total" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.total)
325 |> Jsont.Object.mem "removed" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.removed)
326 |> Jsont.Object.mem "added" (Jsont.list Proto_filter.added_item_jsont) ~enc:(fun r -> r.added)
327 |> Jsont.Object.finish