···124124125125let jsont =
126126 let kind = "Mailbox" in
127127+ (* parentId and role can be null - RFC 8621 Section 2 *)
128128+ let nullable_id = Jsont.(option Jmap_proto.Id.jsont) in
129129+ let nullable_role = Jsont.(option role_jsont) in
127130 Jsont.Object.map ~kind make
128131 |> Jsont.Object.mem "id" Jmap_proto.Id.jsont ~enc:id
129132 |> Jsont.Object.mem "name" Jsont.string ~enc:name
130130- |> Jsont.Object.opt_mem "parentId" Jmap_proto.Id.jsont ~enc:parent_id
131131- |> Jsont.Object.opt_mem "role" role_jsont ~enc:role
133133+ |> Jsont.Object.mem "parentId" nullable_id
134134+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:parent_id
135135+ |> Jsont.Object.mem "role" nullable_role
136136+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:role
132137 |> Jsont.Object.mem "sortOrder" Jmap_proto.Int53.Unsigned.jsont ~dec_absent:0L ~enc:sort_order
133138 |> Jsont.Object.mem "totalEmails" Jmap_proto.Int53.Unsigned.jsont ~enc:total_emails
134139 |> Jsont.Object.mem "unreadEmails" Jmap_proto.Int53.Unsigned.jsont ~enc:unread_emails
···152157153158 let jsont =
154159 let kind = "MailboxFilterCondition" in
155155- (* parentId can be null (meaning top-level) or an id *)
156156- let nullable_id = Jsont.(some Jmap_proto.Id.jsont) in
157157- let nullable_role = Jsont.(some role_jsont) in
160160+ (* parentId and role can be absent, null, or have a value - RFC 8621 Section 2.1 *)
161161+ (* Use opt_mem with Jsont.option to get option option type:
162162+ - None = field absent (don't filter)
163163+ - Some None = field present with null (filter for no parent/role)
164164+ - Some (Some x) = field present with value (filter for specific value) *)
165165+ let nullable_id = Jsont.(option Jmap_proto.Id.jsont) in
166166+ let nullable_role = Jsont.(option role_jsont) in
158167 Jsont.Object.map ~kind make
159168 |> Jsont.Object.opt_mem "parentId" nullable_id ~enc:(fun f -> f.parent_id)
160169 |> Jsont.Object.opt_mem "name" Jsont.string ~enc:(fun f -> f.name)
+6-2
proto/mail/search_snippet.ml
···17171818let jsont =
1919 let kind = "SearchSnippet" in
2020+ (* subject and preview can be null per RFC 8621 Section 5 *)
2121+ let nullable_string = Jsont.(option string) in
2022 Jsont.Object.map ~kind make
2123 |> Jsont.Object.mem "emailId" Jmap_proto.Id.jsont ~enc:email_id
2222- |> Jsont.Object.opt_mem "subject" Jsont.string ~enc:subject
2323- |> Jsont.Object.opt_mem "preview" Jsont.string ~enc:preview
2424+ |> Jsont.Object.mem "subject" nullable_string
2525+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:subject
2626+ |> Jsont.Object.mem "preview" nullable_string
2727+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:preview
2428 |> Jsont.Object.finish
···137137 { account_id; old_state; new_state; created; updated; destroyed;
138138 not_created; not_updated; not_destroyed }
139139 in
140140- (* For updated values, the server may return null or an object *)
141141- let nullable_obj = Jsont.(some obj_jsont) in
140140+ (* For updated values, the server may return null or an object - RFC 8620 Section 5.3 *)
141141+ (* "Id[Foo|null]" means map values can be null, use Jsont.option to handle this *)
142142+ let nullable_obj = Jsont.(option obj_jsont) in
142143 Jsont.Object.map ~kind make
143144 |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
144145 |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)