62 lines
2.3 KiB
Fennel
62 lines
2.3 KiB
Fennel
; This small library is based on https://github.com/Wiladams/LJIT2SQLite
|
|
; It is meant to be an _extremely_ thin wrapper around the SQLite API.
|
|
|
|
(local sqlffi (require :diet-sqlite.sqlite3_ffi))
|
|
(local ffi (require :ffi))
|
|
(local util (require :lib.util))
|
|
(local {: SQLITE_OK : SQLITE_INTEGER : SQLITE_FLOAT : SQLITE_NULL : SQLITE_BLOB : SQLITE_TEXT : SQLITE_TRANSIENT} (require :diet-sqlite.codes))
|
|
|
|
(local sql {:step sqlffi.sqlite3_step
|
|
:reset sqlffi.sqlite3_reset})
|
|
|
|
(fn sql.open [dbname]
|
|
(let [lpdb (ffi.new "sqlite3*[1]")
|
|
rc (sqlffi.sqlite3_open dbname lpdb)
|
|
db (. lpdb 0)]
|
|
(when (not= db nil) (ffi.gc db sqlffi.sqlite3_close_v2))
|
|
(values rc (. lpdb 0))))
|
|
|
|
(fn sql.close [db]
|
|
(ffi.gc db nil)
|
|
(sqlffi.sqlite3_close_v2 db))
|
|
|
|
(fn sql.prepare [db sql ?flags]
|
|
(let [ppStmt (ffi.new "sqlite3_stmt *[1]")
|
|
rc (sqlffi.sqlite3_prepare_v3 db sql -1 (or ?flags 0) ppStmt nil)
|
|
stmt (. ppStmt 0)]
|
|
(when (not= stmt nil) (ffi.gc stmt sqlffi.sqlite3_finalize))
|
|
(values rc stmt)))
|
|
|
|
; this exists just to have a unique object identity you can shove into a table
|
|
(set sql.null {})
|
|
|
|
(fn sql.bind [stmt i ?val]
|
|
(match (type i)
|
|
:table (each [ival val (ipairs i)] (sql.assert (sql.bind stmt ival val)))
|
|
:number
|
|
(match (type ?val)
|
|
:string (sqlffi.sqlite3_bind_text stmt i ?val (length ?val) SQLITE_TRANSIENT)
|
|
:number (sqlffi.sqlite3_bind_double stmt i ?val)
|
|
:nil (sqlffi.sqlite3_bind_null stmt i)
|
|
(where :table (= ?val sql.null)) (sqlffi.sqlite3_bind_null stmt i)
|
|
_ (error (.. "Don't know how to bind value " (fv ?val))))))
|
|
|
|
(fn sql.column [stmt icol]
|
|
(let [i (- icol 1)] ; column indexes are 0-based
|
|
(match (sqlffi.sqlite3_column_type stmt i)
|
|
SQLITE_INTEGER (sqlffi.sqlite3_column_double stmt i)
|
|
SQLITE_FLOAT (sqlffi.sqlite3_column_double stmt i)
|
|
SQLITE_NULL nil
|
|
SQLITE_TEXT (ffi.string (sqlffi.sqlite3_column_text stmt i))
|
|
SQLITE_BLOB (error "no blob support right now")
|
|
?unknown (error (.. "unrecognized type " ?unknown)))))
|
|
|
|
(fn sql.columns [stmt]
|
|
(icollect [i (util.countiter (sqlffi.sqlite3_column_count stmt))] (or (sql.column stmt i) sql.null)))
|
|
|
|
(fn sql.assert-rc [rc-expect rc ...]
|
|
(if (= rc-expect rc) ... (error (.. "Expected " rc-expect ", got " rc))))
|
|
(fn sql.assert [...] (sql.assert-rc SQLITE_OK ...))
|
|
|
|
sql
|