simdjson bindings with streaming support
at main 6.1 kB view raw
1let test_quick_start () = 2 assert (Simdjsont.Validate.is_valid {|{"name": "Alice", "age": 30}|}); 3 let name = 4 Simdjsont.Extract.string {|{"user": {"name": "Bob"}}|} ~pointer:"/user/name" 5 in 6 assert (name = Ok "Bob"); 7 let numbers = 8 Simdjsont.Decode.decode_string Simdjsont.Decode.(list int) "[1, 2, 3]" 9 in 10 assert (numbers = Ok [ 1; 2; 3 ]); 11 let json = 12 Simdjsont.Encode.to_string Simdjsont.Decode.(list string) [ "a"; "b"; "c" ] 13 in 14 assert (json = {|["a","b","c"]|}) 15 16let test_validation () = 17 assert (Simdjsont.Validate.is_valid "[1, 2, 3]"); 18 assert (not (Simdjsont.Validate.is_valid "{invalid")); 19 match Simdjsont.Validate.check "null" with 20 | Ok () -> () 21 | Error _ -> assert false 22 23let test_extraction () = 24 let json = 25 {|{ 26 "users": [ 27 {"id": 1, "name": "Alice", "active": true}, 28 {"id": 2, "name": "Bob", "active": false} 29 ], 30 "count": 2 31 }|} 32 in 33 assert (Simdjsont.Extract.string json ~pointer:"/users/0/name" = Ok "Alice"); 34 assert (Simdjsont.Extract.int json ~pointer:"/count" = Ok 2); 35 assert (Simdjsont.Extract.int json ~pointer:"/users/1/id" = Ok 2); 36 assert (Simdjsont.Extract.bool json ~pointer:"/users/0/active" = Ok true); 37 assert ( 38 Simdjsont.Extract.is_null {|{"value": null}|} ~pointer:"/value" = Ok true) 39 40let test_decoding_primitives () = 41 assert (Simdjsont.Decode.decode_string Simdjsont.Decode.bool "true" = Ok true); 42 assert (Simdjsont.Decode.decode_string Simdjsont.Decode.int "42" = Ok 42); 43 assert ( 44 Simdjsont.Decode.decode_string Simdjsont.Decode.string {|"hello"|} 45 = Ok "hello"); 46 assert ( 47 Simdjsont.Decode.decode_string Simdjsont.Decode.(list int) "[1, 2, 3, 4, 5]" 48 = Ok [ 1; 2; 3; 4; 5 ]); 49 assert ( 50 Simdjsont.Decode.decode_string Simdjsont.Decode.(optional string) "null" 51 = Ok None) 52 53type point = { x : int; y : int } 54 55let point_codec = 56 let open Simdjsont.Decode in 57 Obj.field (fun x y -> { x; y }) 58 |> Obj.mem "x" int ~enc:(fun p -> p.x) 59 |> Obj.mem "y" int ~enc:(fun p -> p.y) 60 |> Obj.finish 61 62let test_decoding_records () = 63 match Simdjsont.Decode.decode_string point_codec {|{"x": 10, "y": 20}|} with 64 | Ok p -> assert (p.x = 10 && p.y = 20) 65 | Error _ -> assert false 66 67type user = { id : int; name : string; email : string option } 68 69let user_codec = 70 let open Simdjsont.Decode in 71 Obj.field (fun id name email -> { id; name; email }) 72 |> Obj.mem "id" int ~enc:(fun u -> u.id) 73 |> Obj.mem "name" string ~enc:(fun u -> u.name) 74 |> Obj.opt_mem "email" string ~enc:(fun u -> u.email) 75 |> Obj.finish 76 77let test_decoding_optional_fields () = 78 let json = {|{"id": 1, "name": "Alice", "email": null}|} in 79 match Simdjsont.Decode.decode_string user_codec json with 80 | Ok user -> 81 assert (user.id = 1); 82 assert (user.name = "Alice"); 83 assert (user.email = None) 84 | Error _ -> assert false 85 86let test_encoding () = 87 assert (Simdjsont.Encode.to_string Simdjsont.Decode.bool true = "true"); 88 assert (Simdjsont.Encode.to_string Simdjsont.Decode.int 42 = "42"); 89 assert ( 90 Simdjsont.Encode.to_string Simdjsont.Decode.string "hello" = {|"hello"|}); 91 assert ( 92 Simdjsont.Encode.to_string Simdjsont.Decode.(list int) [ 1; 2; 3 ] 93 = "[1,2,3]"); 94 let p = { x = 100; y = 200 } in 95 assert (Simdjsont.Encode.to_string point_codec p = {|{"x":100,"y":200}|}) 96 97type item = { name : string; price : float } 98 99let item_codec = 100 let open Simdjsont.Decode in 101 Obj.field (fun name price -> { name; price }) 102 |> Obj.mem "name" string ~enc:(fun i -> i.name) 103 |> Obj.mem "price" float ~enc:(fun i -> i.price) 104 |> Obj.finish 105 106let test_extract_with_codec () = 107 let json = 108 {|{ 109 "order": { 110 "items": [ 111 {"name": "Book", "price": 12.99}, 112 {"name": "Pen", "price": 1.50} 113 ] 114 } 115 }|} 116 in 117 match Simdjsont.Extract.at item_codec json ~pointer:"/order/items/0" with 118 | Ok item -> 119 assert (item.name = "Book"); 120 assert (abs_float (item.price -. 12.99) < 0.001) 121 | Error _ -> assert false 122 123let test_dynamic_json () = 124 let open Simdjsont.Json in 125 let json = 126 Object 127 [ 128 ("name", String "Alice"); 129 ("age", Int 30L); 130 ("scores", Array [ Int 95L; Int 87L; Int 92L ]); 131 ("active", Bool true); 132 ] 133 in 134 let s = to_string json in 135 assert (String.length s > 0); 136 assert (String.sub s 0 1 = "{") 137 138let test_dynamic_decode () = 139 match 140 Simdjsont.Decode.decode_string Simdjsont.Decode.value {|{"key": [1, 2, 3]}|} 141 with 142 | Ok v -> 143 let s = Simdjsont.Json.to_string v in 144 assert (s = {|{"key":[1,2,3]}|}) 145 | Error _ -> assert false 146 147let test_low_level () = 148 let open Simdjsont.Raw in 149 let parser = create_parser () in 150 match 151 parse_string parser {|{"users": [{"name": "Alice"}, {"name": "Bob"}]}|} 152 with 153 | Ok root -> ( 154 (match at_pointer root "/users/1/name" with 155 | Ok elt -> assert (string_exn elt = "Bob") 156 | Error e -> failwith e.message); 157 match at_pointer root "/users" with 158 | Ok elt -> 159 let arr = array_exn elt in 160 let count = ref 0 in 161 array_iter 162 (fun user -> 163 let obj = object_exn user in 164 match object_find obj "name" with 165 | Ok _ -> incr count 166 | Error _ -> ()) 167 arr; 168 assert (!count = 2) 169 | Error e -> failwith e.message) 170 | Error e -> failwith ("Parse error: " ^ e.message) 171 172let () = 173 Alcotest.run "readme" 174 [ 175 ( "examples", 176 [ 177 ("quick start", `Quick, test_quick_start); 178 ("validation", `Quick, test_validation); 179 ("extraction", `Quick, test_extraction); 180 ("decoding primitives", `Quick, test_decoding_primitives); 181 ("decoding records", `Quick, test_decoding_records); 182 ("decoding optional fields", `Quick, test_decoding_optional_fields); 183 ("encoding", `Quick, test_encoding); 184 ("extract with codec", `Quick, test_extract_with_codec); 185 ("dynamic json", `Quick, test_dynamic_json); 186 ("dynamic decode", `Quick, test_dynamic_decode); 187 ("low level", `Quick, test_low_level); 188 ] ); 189 ]