···2222 (fun () ->
2323 Sqlite.put db key value;
2424 let result = Sqlite.get db key in
2525- check_eq ~pp:Format.pp_print_string
2626- ~eq:( = )
2727- (Option.get result) value)
2525+ check_eq ~pp:Format.pp_print_string ~eq:( = ) (Option.get result) value)
28262927(* Test that delete actually removes the key *)
3028let test_delete_removes key value =
···8482 Sqlite.put db key value1;
8583 Sqlite.put db key value2;
8684 let result = Sqlite.get db key in
8787- check_eq ~pp:Format.pp_print_string
8888- ~eq:( = )
8989- (Option.get result) value2)
8585+ check_eq ~pp:Format.pp_print_string ~eq:( = ) (Option.get result) value2)
90869187(* Test table isolation: same key in different tables *)
9288let test_table_isolation key value1 value2 =
···118114 add_test ~name:"sqlite: delete removes" [ bytes; bytes ] test_delete_removes;
119115 add_test ~name:"sqlite: mem consistent" [ bytes; bytes ] test_mem_consistent;
120116 add_test ~name:"sqlite: overwrite" [ bytes; bytes; bytes ] test_overwrite;
121121- add_test ~name:"sqlite: table isolation" [ bytes; bytes; bytes ] test_table_isolation
117117+ add_test ~name:"sqlite: table isolation" [ bytes; bytes; bytes ]
118118+ test_table_isolation
+20-10
lib/sqlite.ml
···3030 (* Prepare statements *)
3131 let get_stmt = Sqlite3.prepare db "SELECT value FROM kv WHERE key = ?" in
3232 let put_stmt =
3333- Sqlite3.prepare db
3434- "INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)"
3333+ Sqlite3.prepare db "INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)"
3534 in
3635 let delete_stmt = Sqlite3.prepare db "DELETE FROM kv WHERE key = ?" in
3736 let mem_stmt = Sqlite3.prepare db "SELECT 1 FROM kv WHERE key = ?" in
···4544 match Sqlite3.step stmt with
4645 | Sqlite3.Rc.ROW -> Some (Sqlite3.column_blob stmt 0)
4746 | Sqlite3.Rc.DONE -> None
4848- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
4747+ | rc ->
4848+ failwith
4949+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
49505051let put t key value =
5152 let stmt = t.put_stmt in
···6768 match Sqlite3.step stmt with
6869 | Sqlite3.Rc.ROW -> true
6970 | Sqlite3.Rc.DONE -> false
7070- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
7171+ | rc ->
7272+ failwith
7373+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
71747275let iter t ~f =
7376 let stmt = t.iter_stmt in
···8083 f key value;
8184 loop ()
8285 | Sqlite3.Rc.DONE -> ()
8383- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
8686+ | rc ->
8787+ failwith
8888+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
8489 in
8590 loop ()
8691···155160 (Printf.sprintf "SELECT 1 FROM %s WHERE key = ?" table_name)
156161 in
157162 let iter_stmt =
158158- Sqlite3.prepare db
159159- (Printf.sprintf "SELECT key, value FROM %s" table_name)
163163+ Sqlite3.prepare db (Printf.sprintf "SELECT key, value FROM %s" table_name)
160164 in
161165 { parent; name; get_stmt; put_stmt; delete_stmt; mem_stmt; iter_stmt }
162166···167171 match Sqlite3.step stmt with
168172 | Sqlite3.Rc.ROW -> Some (Sqlite3.column_blob stmt 0)
169173 | Sqlite3.Rc.DONE -> None
170170- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
174174+ | rc ->
175175+ failwith
176176+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
171177172178 let put t key value =
173179 let stmt = t.put_stmt in
···189195 match Sqlite3.step stmt with
190196 | Sqlite3.Rc.ROW -> true
191197 | Sqlite3.Rc.DONE -> false
192192- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
198198+ | rc ->
199199+ failwith
200200+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
193201194202 let iter t ~f =
195203 let stmt = t.iter_stmt in
···202210 f key value;
203211 loop ()
204212 | Sqlite3.Rc.DONE -> ()
205205- | rc -> failwith (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
213213+ | rc ->
214214+ failwith
215215+ (Printf.sprintf "SQLite step error: %s" (Sqlite3.Rc.to_string rc))
206216 in
207217 loop ()
208218end
+4-4
lib/sqlite.mli
···1212(** A SQLite-backed key-value store. *)
13131414val create : Eio.Fs.dir_ty Eio.Path.t -> t
1515-(** [create path] opens or creates a SQLite database at [path].
1616- Enables WAL mode for concurrent access. *)
1515+(** [create path] opens or creates a SQLite database at [path]. Enables WAL mode
1616+ for concurrent access. *)
17171818val get : t -> string -> string option
1919(** [get t key] returns the value for [key], or [None] if not found. *)
···5151 (** A namespaced table within a database. *)
52525353 val create : db -> name:string -> t
5454- (** [create db ~name] creates or opens a table named [name] within [db].
5555- The table name must be a valid SQL identifier. *)
5454+ (** [create db ~name] creates or opens a table named [name] within [db]. The
5555+ table name must be a valid SQL identifier. *)
56565757 val get : t -> string -> string option
5858 (** [get t key] returns the value for [key], or [None]. *)
+33
sqlite.opam
···11+# This file is generated by dune, edit dune-project instead
22+opam-version: "2.0"
33+synopsis: "Minimal SQLite key-value store for OCaml"
44+description:
55+ "A simple key-value store backed by SQLite with support for namespaced tables, WAL mode, and efficient batch operations."
66+maintainer: ["Thomas Gazagnaire"]
77+authors: ["Thomas Gazagnaire"]
88+license: "MIT"
99+depends: [
1010+ "dune" {>= "3.0"}
1111+ "ocaml" {>= "5.1"}
1212+ "eio" {>= "1.0"}
1313+ "sqlite3" {>= "5.0"}
1414+ "alcotest" {with-test}
1515+ "eio_main" {with-test}
1616+ "crowbar" {with-test}
1717+ "odoc" {with-doc}
1818+]
1919+build: [
2020+ ["dune" "subst"] {dev}
2121+ [
2222+ "dune"
2323+ "build"
2424+ "-p"
2525+ name
2626+ "-j"
2727+ jobs
2828+ "@install"
2929+ "@runtest" {with-test}
3030+ "@doc" {with-doc}
3131+ ]
3232+]
3333+dev-repo: "https://tangled.org/gazagnaire.org/ocaml-sqlite"