Skip to content

Commit 1993263

Browse files
authored
Merge pull request #69 from jchavarri/support-json
feat: add JSON type support
2 parents bf55bb3 + 8252f60 commit 1993263

File tree

5 files changed

+98
-2
lines changed

5 files changed

+98
-2
lines changed

bindings/ffi_bindings.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ module Types (F: Ctypes.TYPE) = struct
9797
let date = constant "MYSQL_TYPE_DATE" int
9898
let datetime = constant "MYSQL_TYPE_DATETIME" int
9999
let timestamp = constant "MYSQL_TYPE_TIMESTAMP" int
100+
let json = constant "MYSQL_TYPE_JSON" int
100101
end
101102

102103
module Stmt_attr = struct

lib/bind.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type buffer_type =
1818
| `Year
1919
| `Short
2020
| `Int24
21+
| `Json
2122
| `Long
2223
| `Float
2324
| `Long_long
@@ -61,6 +62,7 @@ let buffer_type_of_int i =
6162
else if i = date then `Date
6263
else if i = datetime then `Datetime
6364
else if i = timestamp then `Timestamp
65+
else if i = json then `Json
6466
else invalid_arg @@ "unknown buffer type " ^ (string_of_int i)
6567

6668
let yes = '\001'

lib/common.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ module Stmt = struct
354354
| `Int24 | `Long | `Float -> 4
355355
| `Long_long | `Double -> 8
356356
| `Decimal | `New_decimal | `String | `Var_string
357-
| `Tiny_blob | `Blob | `Medium_blob | `Long_blob | `Bit -> -1
357+
| `Tiny_blob | `Blob | `Medium_blob | `Long_blob | `Bit | `Json -> -1
358358
| `Time | `Date | `Datetime | `Timestamp -> Ctypes.sizeof T.Time.t
359359

360360
let malloc count =

lib/field.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ let to_time field kind =
6666
}
6767

6868
type to_string = [`Decimal | `New_decimal | `String | `Var_string | `Bit]
69-
type to_blob = [`Tiny_blob | `Blob | `Medium_blob | `Long_blob]
69+
type to_blob = [`Tiny_blob | `Blob | `Medium_blob | `Long_blob | `Json]
7070
type to_time = [`Time | `Date | `Datetime | `Timestamp]
71+
(* MariaDB implements the JSON datatype as an alias for LONGTEXT. It's
72+
* therefore * included it in to_blob above, so that the representation is
73+
* consitent in the public API. *)
7174

7275
let convert field typ unsigned =
7376
let open Signed in

tests/nonblocking/nonblocking_testsuite.ml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,100 @@ struct
345345
in
346346
(test_integer, test_bigint)
347347

348+
let test_json () =
349+
connect () >>= or_die "connect" >>= fun dbh ->
350+
351+
(* Create a test table with JSON column *)
352+
M.prepare dbh
353+
"CREATE TEMPORARY TABLE ocaml_mariadb_json_test (id integer PRIMARY KEY AUTO_INCREMENT, data JSON)"
354+
>>= or_die "prepare create json table"
355+
>>= fun create_table_stmt ->
356+
execute_no_data create_table_stmt >>= fun () ->
357+
358+
(* Test inserting JSON data *)
359+
M.prepare dbh "INSERT INTO ocaml_mariadb_json_test (data) VALUES (?)"
360+
>>= or_die "prepare insert json"
361+
>>= fun insert_stmt ->
362+
363+
(* Test various JSON types *)
364+
let test_cases = [
365+
{|{"name": "John", "age": 30}|};
366+
{|[1, 2, 3, "four"]|};
367+
{|"simple string"|};
368+
{|42|};
369+
{|true|};
370+
{|null|}
371+
] in
372+
373+
(* Insert all test cases *)
374+
iter_s_list (fun json_data ->
375+
M.Stmt.execute insert_stmt [| `String json_data |] >>= or_die "insert json"
376+
>|= fun _ -> ()
377+
) test_cases >>= fun () ->
378+
379+
(* Select and verify we can retrieve JSON data *)
380+
M.prepare dbh "SELECT id, data FROM ocaml_mariadb_json_test ORDER BY id"
381+
>>= or_die "prepare select json"
382+
>>= fun select_stmt ->
383+
M.Stmt.execute select_stmt [||] >>= or_die "execute select json" >>= fun res ->
384+
385+
(* Verify we can fetch and access JSON fields *)
386+
let rec verify_rows count =
387+
M.Res.fetch (module M.Row.Array) res >>= or_die "fetch json row" >>= function
388+
| Some row ->
389+
assert (Array.length row = 2);
390+
(* Test that we can access the JSON field using different methods *)
391+
let json_value = match M.Field.value row.(1) with
392+
| `Bytes b -> Bytes.to_string b
393+
| _ -> failwith "Expected JSON field as Bytes"
394+
in
395+
(* Verify we got some data back *)
396+
assert (String.length json_value > 0);
397+
398+
(* Test accessor functions *)
399+
let json_direct = M.Field.bytes row.(1) in
400+
let json_opt = M.Field.bytes_opt row.(1) in
401+
assert (json_opt = Some json_direct);
402+
assert (Bytes.length json_direct > 0);
403+
404+
verify_rows (count + 1)
405+
| None ->
406+
(* We should have retrieved all our test cases *)
407+
assert (count = List.length test_cases);
408+
return ()
409+
in
410+
411+
verify_rows 0 >>= fun () ->
412+
413+
(* Test JSON functions if supported (optional) *)
414+
(try
415+
M.prepare dbh "SELECT JSON_TYPE(data) FROM ocaml_mariadb_json_test LIMIT 1"
416+
>>= or_die "prepare json type"
417+
>>= fun json_func_stmt ->
418+
M.Stmt.execute json_func_stmt [||] >>= or_die "execute json type" >>= fun res ->
419+
M.Res.fetch (module M.Row.Array) res >>= or_die "fetch json type" >>= function
420+
| Some row ->
421+
let json_type = match M.Field.value row.(0) with
422+
| `String s -> s
423+
| _ -> failwith "Expected String from JSON_TYPE"
424+
in
425+
(* JSON_TYPE should return something like "OBJECT", "ARRAY", etc. *)
426+
assert (String.length json_type > 0);
427+
M.Stmt.close json_func_stmt >>= or_die "close json func stmt"
428+
| None -> return ()
429+
with
430+
| _ -> return () (* JSON functions might not be supported in all versions *)
431+
) >>= fun () ->
432+
433+
M.Stmt.close select_stmt >>= or_die "close select stmt" >>= fun () ->
434+
M.Stmt.close insert_stmt >>= or_die "close insert stmt" >>= fun () ->
435+
M.close dbh
436+
348437
let main () =
349438
test_server_properties () >>= fun () ->
350439
test_insert_id () >>= fun () ->
351440
test_txn () >>= fun () ->
441+
test_json () >>= fun () ->
352442
test_many_select () >>= fun () ->
353443
test_integer () >>= fun () -> test_bigint ()
354444
end

0 commit comments

Comments
 (0)