(*--------------------------------------------------------------------------- Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (* Foo/get *) type get_args = { account_id : Proto_id.t; ids : Proto_id.t list option; properties : string list option; } let get_args ~account_id ?ids ?properties () = { account_id; ids; properties } let get_args_make account_id ids properties = { account_id; ids; properties } let get_args_jsont = let kind = "GetArgs" in Jsont.Object.map ~kind get_args_make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.opt_mem "ids" (Jsont.list Proto_id.jsont) ~enc:(fun a -> a.ids) |> Jsont.Object.opt_mem "properties" (Jsont.list Jsont.string) ~enc:(fun a -> a.properties) |> Jsont.Object.finish type 'a get_response = { account_id : Proto_id.t; state : string; list : 'a list; not_found : Proto_id.t list; } let get_response_jsont (type a) (obj_jsont : a Jsont.t) : a get_response Jsont.t = let kind = "GetResponse" in let make account_id state list not_found = { account_id; state; list; not_found } in Jsont.Object.map ~kind make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state) |> Jsont.Object.mem "list" (Jsont.list obj_jsont) ~enc:(fun r -> r.list) |> Jsont.Object.mem "notFound" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.not_found) |> Jsont.Object.finish (* Foo/changes *) type changes_args = { account_id : Proto_id.t; since_state : string; max_changes : int64 option; } let changes_args ~account_id ~since_state ?max_changes () = { account_id; since_state; max_changes } let changes_args_make account_id since_state max_changes = { account_id; since_state; max_changes } let changes_args_jsont = let kind = "ChangesArgs" in Jsont.Object.map ~kind changes_args_make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.mem "sinceState" Jsont.string ~enc:(fun a -> a.since_state) |> Jsont.Object.opt_mem "maxChanges" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.max_changes) |> Jsont.Object.finish type changes_response = { account_id : Proto_id.t; old_state : string; new_state : string; has_more_changes : bool; created : Proto_id.t list; updated : Proto_id.t list; destroyed : Proto_id.t list; } let changes_response_make account_id old_state new_state has_more_changes created updated destroyed = { account_id; old_state; new_state; has_more_changes; created; updated; destroyed } let changes_response_jsont = let kind = "ChangesResponse" in Jsont.Object.map ~kind changes_response_make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.mem "oldState" Jsont.string ~enc:(fun r -> r.old_state) |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state) |> Jsont.Object.mem "hasMoreChanges" Jsont.bool ~enc:(fun r -> r.has_more_changes) |> Jsont.Object.mem "created" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.created) |> Jsont.Object.mem "updated" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.updated) |> Jsont.Object.mem "destroyed" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.destroyed) |> Jsont.Object.finish (* Foo/set *) type 'a set_args = { account_id : Proto_id.t; if_in_state : string option; create : (Proto_id.t * 'a) list option; update : (Proto_id.t * Jsont.json) list option; destroy : Proto_id.t list option; } let set_args ~account_id ?if_in_state ?create ?update ?destroy () = { account_id; if_in_state; create; update; destroy } let set_args_jsont (type a) (obj_jsont : a Jsont.t) : a set_args Jsont.t = let kind = "SetArgs" in let make account_id if_in_state create update destroy = { account_id; if_in_state; create; update; destroy } in Jsont.Object.map ~kind make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state) |> Jsont.Object.opt_mem "create" (Proto_json_map.of_id obj_jsont) ~enc:(fun a -> a.create) |> Jsont.Object.opt_mem "update" (Proto_json_map.of_id Jsont.json) ~enc:(fun a -> a.update) |> Jsont.Object.opt_mem "destroy" (Jsont.list Proto_id.jsont) ~enc:(fun a -> a.destroy) |> Jsont.Object.finish type 'a set_response = { account_id : Proto_id.t; old_state : string option; new_state : string; created : (Proto_id.t * 'a) list option; updated : (Proto_id.t * 'a option) list option; destroyed : Proto_id.t list option; not_created : (Proto_id.t * Proto_error.set_error) list option; not_updated : (Proto_id.t * Proto_error.set_error) list option; not_destroyed : (Proto_id.t * Proto_error.set_error) list option; } let set_response_jsont (type a) (obj_jsont : a Jsont.t) : a set_response Jsont.t = let kind = "SetResponse" in (* All map/list fields in SetResponse can be null per RFC 8620 Section 5.3 *) (* opt_mem handles missing keys, Jsont.option handles explicit null values *) (* Option.join flattens option option -> option *) let join = Option.join in let make account_id old_state new_state created updated destroyed not_created not_updated not_destroyed = { account_id; old_state; new_state; created = join created; updated = join updated; destroyed = join destroyed; not_created = join not_created; not_updated = join not_updated; not_destroyed = join not_destroyed } in (* For updated values, the server may return null or an object - RFC 8620 Section 5.3 *) (* "Id[Foo|null]" means map values can be null, use Jsont.option to handle this *) let nullable_obj = Jsont.(option obj_jsont) in let opt enc = Option.map Option.some enc in Jsont.Object.map ~kind make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state) |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state) |> Jsont.Object.opt_mem "created" Jsont.(option (Proto_json_map.of_id obj_jsont)) ~enc:(fun r -> opt r.created) |> Jsont.Object.opt_mem "updated" Jsont.(option (Proto_json_map.of_id nullable_obj)) ~enc:(fun r -> opt r.updated) |> Jsont.Object.opt_mem "destroyed" Jsont.(option (list Proto_id.jsont)) ~enc:(fun r -> opt r.destroyed) |> Jsont.Object.opt_mem "notCreated" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_created) |> Jsont.Object.opt_mem "notUpdated" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_updated) |> Jsont.Object.opt_mem "notDestroyed" Jsont.(option (Proto_json_map.of_id Proto_error.set_error_jsont)) ~enc:(fun r -> opt r.not_destroyed) |> Jsont.Object.finish (* Foo/copy *) type 'a copy_args = { from_account_id : Proto_id.t; if_from_in_state : string option; account_id : Proto_id.t; if_in_state : string option; create : (Proto_id.t * 'a) list; on_success_destroy_original : bool; destroy_from_if_in_state : string option; } let copy_args_jsont (type a) (obj_jsont : a Jsont.t) : a copy_args Jsont.t = let kind = "CopyArgs" in let make from_account_id if_from_in_state account_id if_in_state create on_success_destroy_original destroy_from_if_in_state = { from_account_id; if_from_in_state; account_id; if_in_state; create; on_success_destroy_original; destroy_from_if_in_state } in Jsont.Object.map ~kind make |> Jsont.Object.mem "fromAccountId" Proto_id.jsont ~enc:(fun a -> a.from_account_id) |> Jsont.Object.opt_mem "ifFromInState" Jsont.string ~enc:(fun a -> a.if_from_in_state) |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state) |> Jsont.Object.mem "create" (Proto_json_map.of_id obj_jsont) ~enc:(fun a -> a.create) |> Jsont.Object.mem "onSuccessDestroyOriginal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.on_success_destroy_original) ~enc_omit:(fun b -> not b) |> Jsont.Object.opt_mem "destroyFromIfInState" Jsont.string ~enc:(fun a -> a.destroy_from_if_in_state) |> Jsont.Object.finish type 'a copy_response = { from_account_id : Proto_id.t; account_id : Proto_id.t; old_state : string option; new_state : string; created : (Proto_id.t * 'a) list option; not_created : (Proto_id.t * Proto_error.set_error) list option; } let copy_response_jsont (type a) (obj_jsont : a Jsont.t) : a copy_response Jsont.t = let kind = "CopyResponse" in let make from_account_id account_id old_state new_state created not_created = { from_account_id; account_id; old_state; new_state; created; not_created } in Jsont.Object.map ~kind make |> Jsont.Object.mem "fromAccountId" Proto_id.jsont ~enc:(fun r -> r.from_account_id) |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state) |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state) |> Jsont.Object.opt_mem "created" (Proto_json_map.of_id obj_jsont) ~enc:(fun r -> r.created) |> Jsont.Object.opt_mem "notCreated" (Proto_json_map.of_id Proto_error.set_error_jsont) ~enc:(fun r -> r.not_created) |> Jsont.Object.finish (* Foo/query *) type 'filter query_args = { account_id : Proto_id.t; filter : 'filter Proto_filter.filter option; sort : Proto_filter.comparator list option; position : int64; anchor : Proto_id.t option; anchor_offset : int64; limit : int64 option; calculate_total : bool; } let query_args ~account_id ?filter ?sort ?(position = 0L) ?anchor ?(anchor_offset = 0L) ?limit ?(calculate_total = false) () = { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total } let query_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_args Jsont.t = let kind = "QueryArgs" in let make account_id filter sort position anchor anchor_offset limit calculate_total = { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total } in Jsont.Object.map ~kind make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.opt_mem "filter" (Proto_filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter) |> Jsont.Object.opt_mem "sort" (Jsont.list Proto_filter.comparator_jsont) ~enc:(fun a -> a.sort) |> Jsont.Object.mem "position" Proto_int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.position) ~enc_omit:(fun p -> p = 0L) |> Jsont.Object.opt_mem "anchor" Proto_id.jsont ~enc:(fun a -> a.anchor) |> Jsont.Object.mem "anchorOffset" Proto_int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.anchor_offset) ~enc_omit:(fun o -> o = 0L) |> Jsont.Object.opt_mem "limit" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.limit) |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total) ~enc_omit:(fun b -> not b) |> Jsont.Object.finish type query_response = { account_id : Proto_id.t; query_state : string; can_calculate_changes : bool; position : int64; ids : Proto_id.t list; total : int64 option; } let query_response_make account_id query_state can_calculate_changes position ids total = { account_id; query_state; can_calculate_changes; position; ids; total } let query_response_jsont = let kind = "QueryResponse" in Jsont.Object.map ~kind query_response_make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.mem "queryState" Jsont.string ~enc:(fun r -> r.query_state) |> Jsont.Object.mem "canCalculateChanges" Jsont.bool ~enc:(fun r -> r.can_calculate_changes) |> Jsont.Object.mem "position" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.position) |> Jsont.Object.mem "ids" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.ids) |> Jsont.Object.opt_mem "total" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.total) |> Jsont.Object.finish (* Foo/queryChanges *) type 'filter query_changes_args = { account_id : Proto_id.t; filter : 'filter Proto_filter.filter option; sort : Proto_filter.comparator list option; since_query_state : string; max_changes : int64 option; up_to_id : Proto_id.t option; calculate_total : bool; } let query_changes_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_changes_args Jsont.t = let kind = "QueryChangesArgs" in let make account_id filter sort since_query_state max_changes up_to_id calculate_total = { account_id; filter; sort; since_query_state; max_changes; up_to_id; calculate_total } in Jsont.Object.map ~kind make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id) |> Jsont.Object.opt_mem "filter" (Proto_filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter) |> Jsont.Object.opt_mem "sort" (Jsont.list Proto_filter.comparator_jsont) ~enc:(fun a -> a.sort) |> Jsont.Object.mem "sinceQueryState" Jsont.string ~enc:(fun a -> a.since_query_state) |> Jsont.Object.opt_mem "maxChanges" Proto_int53.Unsigned.jsont ~enc:(fun a -> a.max_changes) |> Jsont.Object.opt_mem "upToId" Proto_id.jsont ~enc:(fun a -> a.up_to_id) |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total) ~enc_omit:(fun b -> not b) |> Jsont.Object.finish type query_changes_response = { account_id : Proto_id.t; old_query_state : string; new_query_state : string; total : int64 option; removed : Proto_id.t list; added : Proto_filter.added_item list; } let query_changes_response_make account_id old_query_state new_query_state total removed added = { account_id; old_query_state; new_query_state; total; removed; added } let query_changes_response_jsont = let kind = "QueryChangesResponse" in Jsont.Object.map ~kind query_changes_response_make |> Jsont.Object.mem "accountId" Proto_id.jsont ~enc:(fun r -> r.account_id) |> Jsont.Object.mem "oldQueryState" Jsont.string ~enc:(fun r -> r.old_query_state) |> Jsont.Object.mem "newQueryState" Jsont.string ~enc:(fun r -> r.new_query_state) |> Jsont.Object.opt_mem "total" Proto_int53.Unsigned.jsont ~enc:(fun r -> r.total) |> Jsont.Object.mem "removed" (Jsont.list Proto_id.jsont) ~enc:(fun r -> r.removed) |> Jsont.Object.mem "added" (Jsont.list Proto_filter.added_item_jsont) ~enc:(fun r -> r.added) |> Jsont.Object.finish