Minimal SQLite key-value store for OCaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(lint): update claude-skills, sle bind, and sqlite across linter changes

+53 -53
+13 -13
fuzz/fuzz_sqlite.ml
··· 18 18 let value = truncate value in 19 19 let db = Sqlite.in_memory () in 20 20 Sqlite.put db key value; 21 - let result = Sqlite.get db key in 21 + let result = Sqlite.find db key in 22 22 check_eq ~pp:Format.pp_print_string ~eq:( = ) (Option.get result) value 23 23 24 24 (** Delete removes key. *) ··· 28 28 let db = Sqlite.in_memory () in 29 29 Sqlite.put db key value; 30 30 Sqlite.delete db key; 31 - check (Option.is_none (Sqlite.get db key)) 31 + check (Option.is_none (Sqlite.find db key)) 32 32 33 33 (** mem consistent with get. *) 34 34 let test_mem_consistent key value = ··· 37 37 let db = Sqlite.in_memory () in 38 38 Sqlite.put db key value; 39 39 check_eq ~pp:Format.pp_print_bool (Sqlite.mem db key) 40 - (Option.is_some (Sqlite.get db key)) 40 + (Option.is_some (Sqlite.find db key)) 41 41 42 42 (** Overwrite replaces value - last put wins. *) 43 43 let test_overwrite key value1 value2 = ··· 48 48 Sqlite.put db key value1; 49 49 Sqlite.put db key value2; 50 50 check_eq ~pp:Format.pp_print_string ~eq:( = ) 51 - (Option.get (Sqlite.get db key)) 51 + (Option.get (Sqlite.find db key)) 52 52 value2 53 53 54 54 (* Table operations *) ··· 64 64 Sqlite.Table.put t1 key value1; 65 65 Sqlite.Table.put t2 key value2; 66 66 check_eq ~pp:Format.pp_print_string ~eq:( = ) 67 - (Option.get (Sqlite.Table.get t1 key)) 67 + (Option.get (Sqlite.Table.find t1 key)) 68 68 value1; 69 69 check_eq ~pp:Format.pp_print_string ~eq:( = ) 70 - (Option.get (Sqlite.Table.get t2 key)) 70 + (Option.get (Sqlite.Table.find t2 key)) 71 71 value2 72 72 73 73 (** Table roundtrip. *) ··· 78 78 let t = Sqlite.Table.create db ~name:"test" in 79 79 Sqlite.Table.put t key value; 80 80 check_eq ~pp:Format.pp_print_string ~eq:( = ) 81 - (Option.get (Sqlite.Table.get t key)) 81 + (Option.get (Sqlite.Table.find t key)) 82 82 value 83 83 84 84 (* Crash safety *) ··· 94 94 let test_get_crash key = 95 95 let key = truncate key in 96 96 let db = Sqlite.in_memory () in 97 - try ignore (Sqlite.get db key) with _ -> () 97 + try ignore (Sqlite.find db key) with _ -> () 98 98 99 99 (** Delete must not crash on arbitrary key. *) 100 100 let test_delete_crash key = ··· 116 116 let db = Sqlite.in_memory () in 117 117 Sqlite.put db "" value; 118 118 check_eq ~pp:Format.pp_print_string ~eq:( = ) 119 - (Option.get (Sqlite.get db "")) 119 + (Option.get (Sqlite.find db "")) 120 120 value 121 121 122 122 (** Empty value must work. *) ··· 125 125 let db = Sqlite.in_memory () in 126 126 Sqlite.put db key ""; 127 127 check_eq ~pp:Format.pp_print_string ~eq:( = ) 128 - (Option.get (Sqlite.get db key)) 128 + (Option.get (Sqlite.find db key)) 129 129 "" 130 130 131 131 (** Both empty must work. *) ··· 133 133 let db = Sqlite.in_memory () in 134 134 Sqlite.put db "" ""; 135 135 check_eq ~pp:Format.pp_print_string ~eq:( = ) 136 - (Option.get (Sqlite.get db "")) 136 + (Option.get (Sqlite.find db "")) 137 137 "" 138 138 139 139 (* Sequence operations *) ··· 148 148 List.iter (fun v -> Sqlite.put db key v) values; 149 149 let last = List.hd (List.rev values) in 150 150 check_eq ~pp:Format.pp_print_string ~eq:( = ) 151 - (Option.get (Sqlite.get db key)) 151 + (Option.get (Sqlite.find db key)) 152 152 last 153 153 end 154 154 ··· 162 162 Sqlite.delete db key; 163 163 Sqlite.put db key value2; 164 164 check_eq ~pp:Format.pp_print_string ~eq:( = ) 165 - (Option.get (Sqlite.get db key)) 165 + (Option.get (Sqlite.find db key)) 166 166 value2 167 167 168 168 (* Register all tests *)
+3 -3
lib/sqlite.ml
··· 99 99 in 100 100 { pager; index; tables = Hashtbl.create 8 } 101 101 102 - let get t key = 102 + let find t key = 103 103 let prefix = prefix key in 104 104 match Btree.Index.by_prefix t.index prefix with 105 105 | None -> None ··· 170 170 (* Check if table metadata exists in main index *) 171 171 let meta_key = "__table__" ^ name in 172 172 let index = 173 - match get parent meta_key with 173 + match find parent meta_key with 174 174 | Some meta_value when String.length meta_value >= 4 -> 175 175 let root = decode_u32_be meta_value 0 in 176 176 Btree.Index.open_ parent.pager ~root_page:root ··· 186 186 Hashtbl.replace parent.tables name (index, root); 187 187 { parent; name; index } 188 188 189 - let get t key = 189 + let find t key = 190 190 let prefix = prefix key in 191 191 match Btree.Index.by_prefix t.index prefix with 192 192 | None -> None
+4 -4
lib/sqlite.mli
··· 25 25 controls the lifetime of the underlying file handle. 26 26 @raise Failure if the file doesn't exist. *) 27 27 28 - val get : t -> string -> string option 29 - (** [get t key] returns the value for [key], or [None] if not found. *) 28 + val find : t -> string -> string option 29 + (** [find t key] returns the value for [key], or [None] if not found. *) 30 30 31 31 val put : t -> string -> string -> unit 32 32 (** [put t key value] stores [value] at [key], replacing any existing value. *) ··· 64 64 (** [create db ~name] creates or opens a table named [name] within [db]. The 65 65 table name must be a valid SQL identifier. *) 66 66 67 - val get : t -> string -> string option 68 - (** [get t key] returns the value for [key], or [None]. *) 67 + val find : t -> string -> string option 68 + (** [find t key] returns the value for [key], or [None]. *) 69 69 70 70 val put : t -> string -> string -> unit 71 71 (** [put t key value] stores [value] at [key]. *)
+33 -33
test/test_sqlite.ml
··· 21 21 let test_put_get () = 22 22 with_temp_db @@ fun _fs db -> 23 23 Sqlite.put db "key1" "value1"; 24 - let result = Sqlite.get db "key1" in 24 + let result = Sqlite.find db "key1" in 25 25 Alcotest.(check (option string)) 26 26 "get returns put value" (Some "value1") result 27 27 28 28 let test_get_missing () = 29 29 with_temp_db @@ fun _fs db -> 30 - let result = Sqlite.get db "nonexistent" in 30 + let result = Sqlite.find db "nonexistent" in 31 31 Alcotest.(check (option string)) "missing key returns None" None result 32 32 33 33 let test_put_overwrite () = 34 34 with_temp_db @@ fun _fs db -> 35 35 Sqlite.put db "key1" "value1"; 36 36 Sqlite.put db "key1" "value2"; 37 - let result = Sqlite.get db "key1" in 37 + let result = Sqlite.find db "key1" in 38 38 Alcotest.(check (option string)) "overwrite works" (Some "value2") result 39 39 40 40 let test_delete () = 41 41 with_temp_db @@ fun _fs db -> 42 42 Sqlite.put db "key1" "value1"; 43 43 Sqlite.delete db "key1"; 44 - let result = Sqlite.get db "key1" in 44 + let result = Sqlite.find db "key1" in 45 45 Alcotest.(check (option string)) "delete removes key" None result 46 46 47 47 let test_delete_missing () = ··· 83 83 with_temp_db @@ fun _fs db -> 84 84 let binary = "\x00\x01\x02\xff\xfe\xfd" in 85 85 Sqlite.put db "binary" binary; 86 - let result = Sqlite.get db "binary" in 86 + let result = Sqlite.find db "binary" in 87 87 Alcotest.(check (option string)) "binary data preserved" (Some binary) result 88 88 89 89 let test_empty_value () = 90 90 with_temp_db @@ fun _fs db -> 91 91 Sqlite.put db "empty" ""; 92 - let result = Sqlite.get db "empty" in 92 + let result = Sqlite.find db "empty" in 93 93 Alcotest.(check (option string)) "empty value works" (Some "") result 94 94 95 95 let test_large_value () = ··· 97 97 (* Note: B-tree has page splitting constraints limiting max entry size *) 98 98 let large = String.make 1000 'x' in 99 99 Sqlite.put db "large" large; 100 - let result = Sqlite.get db "large" in 100 + let result = Sqlite.find db "large" in 101 101 Alcotest.(check (option string)) "large value works" (Some large) result 102 102 103 103 (* Namespaced tables *) ··· 106 106 with_temp_db @@ fun _fs db -> 107 107 let table = Sqlite.Table.create db ~name:"blocks" in 108 108 Sqlite.Table.put table "cid1" "data1"; 109 - let result = Sqlite.Table.get table "cid1" in 109 + let result = Sqlite.Table.find table "cid1" in 110 110 Alcotest.(check (option string)) "table get/put works" (Some "data1") result 111 111 112 112 let test_table_isolation () = ··· 119 119 Sqlite.put db "key" "default"; 120 120 Alcotest.(check (option string)) 121 121 "t1 isolated" (Some "value1") 122 - (Sqlite.Table.get t1 "key"); 122 + (Sqlite.Table.find t1 "key"); 123 123 Alcotest.(check (option string)) 124 124 "t2 isolated" (Some "value2") 125 - (Sqlite.Table.get t2 "key"); 125 + (Sqlite.Table.find t2 "key"); 126 126 Alcotest.(check (option string)) 127 - "default isolated" (Some "default") (Sqlite.get db "key") 127 + "default isolated" (Some "default") (Sqlite.find db "key") 128 128 129 129 let test_table_mem_delete () = 130 130 with_temp_db @@ fun _fs db -> ··· 164 164 List.iter 165 165 (fun key -> 166 166 Sqlite.put db key "value"; 167 - let result = Sqlite.get db key in 167 + let result = Sqlite.find db key in 168 168 Alcotest.(check (option string)) 169 169 (Printf.sprintf "injection key %S safe" key) 170 170 (Some "value") result) ··· 178 178 List.iter 179 179 (fun value -> 180 180 Sqlite.put db "key" value; 181 - let result = Sqlite.get db "key" in 181 + let result = Sqlite.find db "key" in 182 182 Alcotest.(check (option string)) 183 183 (Printf.sprintf "injection value safe") 184 184 (Some value) result) ··· 214 214 (fun name -> 215 215 let table = Sqlite.Table.create db ~name in 216 216 Sqlite.Table.put table "key" "value"; 217 - let result = Sqlite.Table.get table "key" in 217 + let result = Sqlite.Table.find table "key" in 218 218 Alcotest.(check (option string)) 219 219 (Printf.sprintf "valid table %S works" name) 220 220 (Some "value") result) ··· 228 228 List.iter 229 229 (fun key -> 230 230 Sqlite.put db key "value"; 231 - let result = Sqlite.get db key in 231 + let result = Sqlite.find db key in 232 232 Alcotest.(check (option string)) 233 233 (Printf.sprintf "unicode key %S" key) 234 234 (Some "value") result) ··· 238 238 with_temp_db @@ fun _fs db -> 239 239 let unicode = "日本語テスト🎉" in 240 240 Sqlite.put db "key" unicode; 241 - let result = Sqlite.get db "key" in 241 + let result = Sqlite.find db "key" in 242 242 Alcotest.(check (option string)) "unicode value" (Some unicode) result 243 243 244 244 (* Sync *) ··· 248 248 Sqlite.put db "key" "value"; 249 249 (* sync should not raise *) 250 250 Sqlite.sync db; 251 - let result = Sqlite.get db "key" in 251 + let result = Sqlite.find db "key" in 252 252 Alcotest.(check (option string)) 253 253 "data persists after sync" (Some "value") result 254 254 ··· 271 271 (* Reopen and read *) 272 272 Eio.Switch.run (fun sw -> 273 273 let db = Sqlite.open_ ~sw path in 274 - let r1 = Sqlite.get db "key1" in 275 - let r2 = Sqlite.get db "key2" in 274 + let r1 = Sqlite.find db "key1" in 275 + let r2 = Sqlite.find db "key2" in 276 276 Alcotest.(check (option string)) "key1 persisted" (Some "value1") r1; 277 277 Alcotest.(check (option string)) "key2 persisted" (Some "value2") r2; 278 278 Sqlite.close db) ··· 296 296 (* Reopen and verify *) 297 297 Eio.Switch.run (fun sw -> 298 298 let db = Sqlite.open_ ~sw path in 299 - let r1 = Sqlite.get db "keep" in 300 - let r2 = Sqlite.get db "delete" in 299 + let r1 = Sqlite.find db "keep" in 300 + let r2 = Sqlite.find db "delete" in 301 301 Alcotest.(check (option string)) "kept key persisted" (Some "value1") r1; 302 302 Alcotest.(check (option string)) "deleted key gone" None r2; 303 303 Sqlite.close db) ··· 324 324 let db = Sqlite.open_ ~sw path in 325 325 let t1 = Sqlite.Table.create db ~name:"blocks" in 326 326 let t2 = Sqlite.Table.create db ~name:"refs" in 327 - let r1 = Sqlite.Table.get t1 "cid1" in 328 - let r2 = Sqlite.Table.get t2 "head" in 327 + let r1 = Sqlite.Table.find t1 "cid1" in 328 + let r2 = Sqlite.Table.find t2 "head" in 329 329 Alcotest.(check (option string)) "table1 data persisted" (Some "data1") r1; 330 330 Alcotest.(check (option string)) 331 331 "table2 data persisted" (Some "cid123") r2; ··· 336 336 let test_empty_key () = 337 337 with_temp_db @@ fun _fs db -> 338 338 Sqlite.put db "" "value_for_empty_key"; 339 - let result = Sqlite.get db "" in 339 + let result = Sqlite.find db "" in 340 340 Alcotest.(check (option string)) 341 341 "empty key works" (Some "value_for_empty_key") result 342 342 ··· 345 345 let key = "key\x00with\x00nulls" in 346 346 let value = "value\x00also\x00has\x00nulls" in 347 347 Sqlite.put db key value; 348 - let result = Sqlite.get db key in 348 + let result = Sqlite.find db key in 349 349 Alcotest.(check (option string)) "null bytes preserved" (Some value) result 350 350 351 351 let test_long_key () = ··· 354 354 let key = String.make 500 'k' in 355 355 let value = "value" in 356 356 Sqlite.put db key value; 357 - let result = Sqlite.get db key in 357 + let result = Sqlite.find db key in 358 358 Alcotest.(check (option string)) "long key works" (Some value) result 359 359 360 360 let test_all_byte_values () = ··· 362 362 (* Test all possible byte values in keys and values *) 363 363 let all_bytes = String.init 256 Char.chr in 364 364 Sqlite.put db all_bytes all_bytes; 365 - let result = Sqlite.get db all_bytes in 365 + let result = Sqlite.find db all_bytes in 366 366 Alcotest.(check (option string)) 367 367 "all byte values preserved" (Some all_bytes) result 368 368 ··· 375 375 let key = String.make len 'x' in 376 376 let value = Printf.sprintf "value_%d" len in 377 377 Sqlite.put db key value; 378 - let result = Sqlite.get db key in 378 + let result = Sqlite.find db key in 379 379 Alcotest.(check (option string)) 380 380 (Printf.sprintf "key length %d" len) 381 381 (Some value) result) ··· 392 392 done; 393 393 (* Verify all present *) 394 394 for i = 0 to n - 1 do 395 - let result = Sqlite.get db (Printf.sprintf "key_%05d" i) in 395 + let result = Sqlite.find db (Printf.sprintf "key_%05d" i) in 396 396 Alcotest.(check (option string)) 397 397 (Printf.sprintf "key %d present" i) 398 398 (Some (Printf.sprintf "value_%d" i)) ··· 406 406 for i = 0 to n - 1 do 407 407 Sqlite.put db "key" (Printf.sprintf "value_%d" i) 408 408 done; 409 - let result = Sqlite.get db "key" in 409 + let result = Sqlite.find db "key" in 410 410 Alcotest.(check (option string)) 411 411 "final value" 412 412 (Some (Printf.sprintf "value_%d" (n - 1))) ··· 446 446 (* Verify isolation *) 447 447 Array.iteri 448 448 (fun i t -> 449 - let result = Sqlite.Table.get t "key" in 449 + let result = Sqlite.Table.find t "key" in 450 450 Alcotest.(check (option string)) 451 451 (Printf.sprintf "table %d" i) 452 452 (Some (Printf.sprintf "value_%d" i)) ··· 460 460 (* Ensure large key doesn't cause integer overflow in length encoding *) 461 461 let key = String.make 500 'x' in 462 462 Sqlite.put db key "value"; 463 - let result = Sqlite.get db key in 463 + let result = Sqlite.find db key in 464 464 Alcotest.(check (option string)) "large key no overflow" (Some "value") result 465 465 466 466 let test_cve_like_boundary_conditions () = ··· 472 472 let key = Printf.sprintf "key_%d" size in 473 473 let value = String.make size 'v' in 474 474 Sqlite.put db key value; 475 - let result = Sqlite.get db key in 475 + let result = Sqlite.find db key in 476 476 Alcotest.(check (option string)) 477 477 (Printf.sprintf "boundary size %d" size) 478 478 (Some value) result)