Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions ppx/test/classify_drop_option.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
We can classify the JSON produced by `to_json` for a record with a dropped optional field:
$ echo '
> open Melange_json.Primitives
> type t = {a: int option; [@json.option] [@json.drop_default]} [@@deriving to_json]
> let () =
> match Melange_json.classify (to_json {a = None}) with
> | `Assoc xs -> xs |> List.iter (fun (k, v) ->
> let _ = k in
> let _v = Melange_json.classify v in
> ());
> print_endline "OK"
> | _ -> print_endline "ERROR: Expected an object"
> ' | ./run.sh
=== ppx output:native ===
open Melange_json.Primitives
type t = {
a: int option [@json.option ][@json.drop_default ]}[@@deriving to_json]
include
struct
let _ = fun (_ : t) -> ()
[@@@ocaml.warning "-39-11-27"]
let rec to_json =
(fun x ->
match x with
| { a = x_a } ->
`Assoc
(let bnds__001_ = [] in
let bnds__001_ =
match x_a with
| Stdlib.Option.None -> bnds__001_
| Stdlib.Option.Some _ ->
("a", ((option_to_json int_to_json) x_a)) :: bnds__001_ in
bnds__001_) : t -> Yojson.Basic.t)
let _ = to_json
end[@@ocaml.doc "@inline"][@@merlin.hide ]
let () =
match Melange_json.classify (to_json { a = None }) with
| `Assoc xs ->
(xs |>
(List.iter
(fun (k, v) ->
let _ = k in let _v = Melange_json.classify v in ()));
print_endline "OK")
| _ -> print_endline "ERROR: Expected an object"
=== ppx output:browser ===
open Melange_json.Primitives
type t = {
a: int option [@json.option ][@json.drop_default ]}[@@deriving to_json]
include
struct
let _ = fun (_ : t) -> ()
[@@@ocaml.warning "-39-11-27"]
let rec to_json =
(fun x ->
match x with
| { a = x_a } ->
(Obj.magic
([%mel.obj
{
a =
(match x_a with
| Stdlib.Option.None -> Js.Undefined.empty
| Stdlib.Option.Some _ ->
Js.Undefined.return
((option_to_json int_to_json) x_a))
}]) : Js.Json.t) : t -> Js.Json.t)
let _ = to_json
end[@@ocaml.doc "@inline"][@@merlin.hide ]
let () =
match Melange_json.classify (to_json { a = None }) with
| `Assoc xs ->
(xs |>
(List.iter
(fun (k, v) ->
let _ = k in let _v = Melange_json.classify v in ()));
print_endline "OK")
| _ -> print_endline "ERROR: Expected an object"
=== stdout:native ===
OK
=== stdout:js ===
OK
17 changes: 15 additions & 2 deletions src/classify.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ module J = Js.Json

type t = J.t

let dict_to_list_without_undefined dict =
let keys = Js.Dict.keys dict in
let l = Array.length keys in
let xs = ref [] in
for i = l - 1 downto 0 do
let key = Array.unsafe_get keys i in
let value = Js.Dict.unsafeGet dict key in
if not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined) then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably the same reason of the other comment, but why not Js.typeof value <> "undefined" in this case instead of Obj.magic?

xs := (key, value) :: !xs
done;
!xs
Comment on lines +5 to +15

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably there is some performance issues, but why don't do this:

let dict_to_list_without_undefined dict =
  Js.Dict.entries dict
  |> Array.to_list
  |> List.filter (fun (_, value) ->
         not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or

let dict_to_list_without_undefined dict =
  Array.fold_right
    (fun (key, value) acc ->
      if not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined) then
        (key, value) :: acc
      else acc)
    (Js.Dict.entries dict) []

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I wanted to reduce number of allocations as much as possible, so no intermediate lists/arrays.


let classify :
t ->
[ `Null
Expand All @@ -27,8 +39,9 @@ let classify :
let xs = Array.to_list (Obj.magic json : t array) in
`List xs
else
let xs = Js.Dict.entries (Obj.magic json : t Js.Dict.t) in
`Assoc (Array.to_list xs)
`Assoc
(dict_to_list_without_undefined
(Obj.magic json : t Js.Dict.t))
| typ -> failwith ("unknown JSON value type: " ^ typ)

let declassify :
Expand Down