Remove the built-in jolt.sqlite / jdbc.core (libraries own native code)

The sqlite/jdbc functionality moves out of the host into the jolt-lang/db
library, which binds libsqlite3 (and libpq) itself via jolt.ffi. A baked
built-in jdbc.core would shadow the library's, so it's removed here. ring-app
gets jdbc.core from the db git dep instead.
This commit is contained in:
Yogthos 2026-06-22 11:23:45 -04:00
parent 537cb360b4
commit db9bed226f
3 changed files with 0 additions and 155 deletions

View file

@ -21,7 +21,6 @@
(load "host/chez/compile-eval.ss")
(load "host/chez/png.ss") ; jolt.png — a baked namespace before the snapshot
(load "host/chez/http-client.ss") ; jolt.http-client (libcurl)
(load "host/chez/sqlite.ss") ; jolt.sqlite + jdbc.core (libsqlite3)
(load "host/chez/http-server.ss") ; jolt.http.server (BSD sockets)
(load "host/chez/loader.ss")
;; jolt.ffi host primitives (memory / library loading) load AFTER the loader's

View file

@ -1,153 +0,0 @@
;; sqlite.ss (jolt-90sp) — jolt.sqlite + a jdbc.core API over the system
;; libsqlite3 via Chez's FFI. The sqlite3 C API is non-variadic, so it binds
;; directly (unlike libcurl). Enough of the surface for a small app: open/close,
;; exec (DDL/DML), a prepared query returning row maps, parameter binding
;; (text/int/double), and last_insert_rowid.
;;
;; def-var!'d into jolt.sqlite AND jdbc.core (jolt-lang/db's API: connection /
;; execute! / fetch / fetch-one / last-insert-id), so an app that requires
;; jdbc.core resolves it as a baked namespace.
(define sqlite-available?
(let loop ((names '("libsqlite3.0.dylib" "libsqlite3.so.0" "libsqlite3.dylib" "libsqlite3.so")))
(cond ((null? names) #f)
((guard (e (#t #f)) (load-shared-object (car names)) #t) #t)
(else (loop (cdr names))))))
(define sqlite3_open (foreign-procedure "sqlite3_open" (string void*) int))
(define sqlite3_close (foreign-procedure "sqlite3_close" (void*) int))
(define sqlite3_errmsg (foreign-procedure "sqlite3_errmsg" (void*) string))
(define sqlite3_prepare_v2 (foreign-procedure "sqlite3_prepare_v2" (void* string int void* uptr) int))
(define sqlite3_step (foreign-procedure "sqlite3_step" (void*) int))
(define sqlite3_finalize (foreign-procedure "sqlite3_finalize" (void*) int))
(define sqlite3_column_count (foreign-procedure "sqlite3_column_count" (void*) int))
(define sqlite3_column_name (foreign-procedure "sqlite3_column_name" (void* int) string))
(define sqlite3_column_type (foreign-procedure "sqlite3_column_type" (void* int) int))
(define sqlite3_column_text (foreign-procedure "sqlite3_column_text" (void* int) string))
(define sqlite3_column_int64 (foreign-procedure "sqlite3_column_int64" (void* int) integer-64))
(define sqlite3_column_double (foreign-procedure "sqlite3_column_double" (void* int) double))
(define sqlite3_bind_text (foreign-procedure "sqlite3_bind_text" (void* int string int iptr) int))
(define sqlite3_bind_int64 (foreign-procedure "sqlite3_bind_int64" (void* int integer-64) int))
(define sqlite3_bind_double (foreign-procedure "sqlite3_bind_double" (void* int double) int))
(define sqlite3_bind_null (foreign-procedure "sqlite3_bind_null" (void* int) int))
(define sqlite3_last_insert_rowid (foreign-procedure "sqlite3_last_insert_rowid" (void*) integer-64))
(define SQLITE_OK 0) (define SQLITE_ROW 100) (define SQLITE_DONE 101)
(define SQLITE_TRANSIENT -1)
;; a connection is a jhost "sqlite-conn" wrapping the sqlite3* (as an integer addr)
(define (sql-conn db) (make-jhost "sqlite-conn" (vector db)))
(define (sql-conn-db c) (vector-ref (jhost-state c) 0))
(define (sql-conn? x) (and (jhost? x) (string=? (jhost-tag x) "sqlite-conn")))
(define (sql-open path)
(unless sqlite-available? (error #f "jolt.sqlite: libsqlite3 not found"))
(let ((pp (foreign-alloc 8)))
(foreign-set! 'void* pp 0 0)
(let ((rc (sqlite3_open path pp)))
(let ((db (foreign-ref 'void* pp 0)))
(foreign-free pp)
(if (= rc SQLITE_OK) (sql-conn db)
(error #f (string-append "sqlite open failed: " path)))))))
(define (sql-close c) (sqlite3_close (sql-conn-db c)) jolt-nil)
(define (sql-prepare db sql)
(let ((pp (foreign-alloc 8)))
(foreign-set! 'void* pp 0 0)
(let ((rc (sqlite3_prepare_v2 db sql -1 pp 0)))
(let ((stmt (foreign-ref 'void* pp 0)))
(foreign-free pp)
(if (= rc SQLITE_OK) stmt
(error #f (string-append "sqlite prepare failed: " (sqlite3_errmsg db) " — " sql)))))))
;; bind a jolt value to parameter i (1-based)
(define (sql-bind! stmt i v)
(cond
((jolt-nil? v) (sqlite3_bind_null stmt i))
((and (number? v) (exact? v) (integer? v)) (sqlite3_bind_int64 stmt i v))
((number? v) (sqlite3_bind_double stmt i (inexact v)))
((string? v) (sqlite3_bind_text stmt i v -1 SQLITE_TRANSIENT))
(else (sqlite3_bind_text stmt i (jolt-str-render-one v) -1 SQLITE_TRANSIENT))))
;; read the current row as a jolt map {keyword-col -> value}
(define (sql-row stmt)
(let ((n (sqlite3_column_count stmt)) (m (jolt-hash-map)))
(do ((i 0 (+ i 1))) ((= i n) m)
(let* ((nm (sqlite3_column_name stmt i))
(ty (sqlite3_column_type stmt i))
(v (cond ((= ty 1) (sqlite3_column_int64 stmt i))
((= ty 2) (sqlite3_column_double stmt i))
((= ty 5) jolt-nil)
(else (sqlite3_column_text stmt i)))))
(set! m (jolt-assoc m (keyword #f nm) v))))))
;; run sql with params; return a vector of row maps (empty for a non-SELECT).
(define (sql-query c sql params)
(let ((db (sql-conn-db c)) (stmt (sql-prepare (sql-conn-db c) sql)))
(let bind ((i 1) (ps params)) (when (pair? ps) (sql-bind! stmt i (car ps)) (bind (+ i 1) (cdr ps))))
(let loop ((rows '()))
(let ((rc (sqlite3_step stmt)))
(cond
((= rc SQLITE_ROW) (loop (cons (sql-row stmt) rows)))
((= rc SQLITE_DONE) (sqlite3_finalize stmt) (apply jolt-vector (reverse rows)))
(else (let ((msg (sqlite3_errmsg db))) (sqlite3_finalize stmt)
(error #f (string-append "sqlite step failed: " msg)))))))))
;; --- jolt.sqlite (a small direct API) ---------------------------------------
(define (sqlite-vec-args a) (if (and (pair? a) (or (pvec? (car a)) (cseq? (car a)) (empty-list-t? (car a))))
(seq->list (car a)) a))
(def-var! "jolt.sqlite" "open" (lambda (path) (sql-open path)))
(def-var! "jolt.sqlite" "close" (lambda (c) (sql-close c)))
(def-var! "jolt.sqlite" "query" (lambda (c sql . ps) (sql-query c sql (sqlite-vec-args ps))))
(def-var! "jolt.sqlite" "execute!" (lambda (c sql . ps) (sql-query c sql (sqlite-vec-args ps)) jolt-nil))
(def-var! "jolt.sqlite" "last-insert-id" (lambda (c) (sqlite3_last_insert_rowid (sql-conn-db c))))
(def-var! "jolt.sqlite" "available?" (lambda () (if sqlite-available? #t #f)))
;; --- jdbc.core (jolt-lang/db API) -------------------------------------------
;; A honeysql sql-vector is [sql & params]; jdbc fns take that directly. The
;; connection string is "sqlite:<path>" (or "jdbc:sqlite:<path>").
(define (jdbc-strip-scheme url)
(let ((u (jolt-str-render-one url)))
(let strip ((prefixes '("jdbc:sqlite:" "sqlite:")))
(cond ((null? prefixes) u)
((and (>= (string-length u) (string-length (car prefixes)))
(string=? (substring u 0 (string-length (car prefixes))) (car prefixes)))
(substring u (string-length (car prefixes)) (string-length u)))
(else (strip (cdr prefixes)))))))
(define (jdbc-sqlvec v) ; [sql & params] -> (values sql params-list)
(let ((items (cond ((pvec? v) (seq->list v))
((or (cseq? v) (empty-list-t? v)) (seq->list v))
((string? v) (list v))
(else '()))))
(values (if (pair? items) (jolt-str-render-one (car items)) "")
(if (pair? items) (cdr items) '()))))
(def-var! "jdbc.core" "connection" (lambda (url) (sql-open (jdbc-strip-scheme url))))
(def-var! "jdbc.core" "execute!"
(lambda (c sqlvec) (let-values (((sql ps) (jdbc-sqlvec sqlvec))) (sql-query c sql ps) jolt-nil)))
;; jdbc.core (jolt-lang/db) returns kebab-cased column keys, so an `id_seq`
;; column reads as :id-seq — the Clojure jdbc convention the templates/queries
;; expect. (The lower jolt.sqlite/query keeps the raw column names.)
(define (kebab-keyword k)
(if (keyword-t? k)
(let ((nm (keyword-t-name k)))
(if (memv #\_ (string->list nm))
(keyword (keyword-t-ns k) (list->string (map (lambda (c) (if (char=? c #\_) #\- c)) (string->list nm))))
k))
k))
(define (kebab-row row)
(let loop ((s (jolt-seq row)) (m (jolt-hash-map)))
(if (jolt-nil? s) m
(let ((e (jolt-first s)))
(loop (jolt-seq (jolt-rest s)) (jolt-assoc m (kebab-keyword (jolt-nth e 0)) (jolt-nth e 1)))))))
(define (kebab-rows rows)
(let loop ((i 0) (out (jolt-vector)))
(if (>= i (pvec-count rows)) out
(loop (+ i 1) (jolt-conj out (kebab-row (pvec-nth-d rows i jolt-nil)))))))
(def-var! "jdbc.core" "fetch"
(lambda (c sqlvec) (let-values (((sql ps) (jdbc-sqlvec sqlvec))) (kebab-rows (sql-query c sql ps)))))
(def-var! "jdbc.core" "fetch-one"
(lambda (c sqlvec) (let-values (((sql ps) (jdbc-sqlvec sqlvec)))
(let ((rows (sql-query c sql ps)))
(if (> (pvec-count rows) 0) (kebab-row (pvec-nth-d rows 0 jolt-nil)) jolt-nil)))))
(def-var! "jdbc.core" "last-insert-id" (lambda (c) (sqlite3_last_insert_rowid (sql-conn-db c))))