From d9282d9a3bcb1bc474d65cf81f4c9cfca0c0a489 Mon Sep 17 00:00:00 2001 From: Max Penet Date: Wed, 10 Dec 2025 16:19:39 +0100 Subject: [PATCH 1/3] refactor(core): Update query handling with customizable result-set-fn Modified the `q*` function to enable reducing results via `IReduceInit`. Added a `result-set-fn` option in `q` to allow customization of query result transformations, defaulting to a vector. --- src/sqlite4clj/core.clj | 47 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/sqlite4clj/core.clj b/src/sqlite4clj/core.clj index 0b0862a..07f50fa 100644 --- a/src/sqlite4clj/core.clj +++ b/src/sqlite4clj/core.clj @@ -80,26 +80,24 @@ (conj! cols (get-column-val stmt n))))))) (defn- q* [conn query] - (let [result - (let [{:keys [stmt]} (prepare-cached conn query)] - (with-stmt-reset [stmt stmt] - (let [n-cols (int - #_{:clj-kondo/ignore [:type-mismatch]} - (api/column-count stmt))] - (loop [rows (transient [])] - (let [code (int - #_{:clj-kondo/ignore [:type-mismatch]} - (api/step stmt))] - (case code - 100 (recur (conj! rows (column stmt n-cols))) - 101 (persistent! rows) - code))))))] - (cond - (vector? result) (when (seq result) result) - (= result 101) nil - :else (throw (api/sqlite-ex-info (:pdb conn) result - {:sql (first query) - :params (subvec query 1)}))))) + (let [{:keys [stmt]} (prepare-cached conn query)] + (with-stmt-reset [stmt stmt] + (let [n-cols (int + #_{:clj-kondo/ignore [:type-mismatch]} + (api/column-count stmt))] + (reify clojure.lang.IReduceInit + (reduce [_ f init] + (loop [ret init] + (let [code (int + #_{:clj-kondo/ignore [:type-mismatch]} + (api/step stmt))] + (case code + 100 (let [ret (f ret (column stmt n-cols))] + (if (reduced? ret) + @ret + (recur ret))) + 101 ret + code))))))))) (def default-pragma {:cache_size 15625 @@ -183,16 +181,17 @@ (defn q "Run a query against a db. Return nil when no results." - [{:keys [conn-pool] :as tx} query] + [{:keys [conn-pool result-set-fn] :as tx + :or {result-set-fn #(into [] %)}} query] (if conn-pool - (binding [*print-length* nil] + (binding [*print-length* nil] (let [conn (BlockingQueue/.take conn-pool)] (try - (q* conn query) + (result-set-fn (q* conn query)) ;; Always return the conn even on error (finally (BlockingQueue/.offer conn-pool conn))))) ;; If we don't have a connection pool then we have a tx. - (q* tx query))) + (result-set-fn (q* tx query)))) (defn optimize-db "Use for running optimise on long lived connections. For query_only From 1b1bdd173cee71f2cd38e8d2152315326cd89a6d Mon Sep 17 00:00:00 2001 From: Max Penet Date: Wed, 10 Dec 2025 16:25:44 +0100 Subject: [PATCH 2/3] refactor(core): extract default result-set function --- src/sqlite4clj/core.clj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sqlite4clj/core.clj b/src/sqlite4clj/core.clj index 07f50fa..2bb13a2 100644 --- a/src/sqlite4clj/core.clj +++ b/src/sqlite4clj/core.clj @@ -179,10 +179,14 @@ ;; garbage collected. :internal {:app-functions (atom {})}})) +(defn default-result-set-fn + [result-set] + (into [] result-set)) + (defn q "Run a query against a db. Return nil when no results." [{:keys [conn-pool result-set-fn] :as tx - :or {result-set-fn #(into [] %)}} query] + :or {result-set-fn default-result-set-fn}} query] (if conn-pool (binding [*print-length* nil] (let [conn (BlockingQueue/.take conn-pool)] From a0e63ba541d4b355470956a45c2d9455e30e0cb0 Mon Sep 17 00:00:00 2001 From: Max Penet Date: Wed, 10 Dec 2025 17:36:53 +0100 Subject: [PATCH 3/3] fix(core): throw detailed exception on unexpected SQLite step code Previously, unexpected step codes were ignored --- src/sqlite4clj/core.clj | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sqlite4clj/core.clj b/src/sqlite4clj/core.clj index 2bb13a2..2f18243 100644 --- a/src/sqlite4clj/core.clj +++ b/src/sqlite4clj/core.clj @@ -88,16 +88,18 @@ (reify clojure.lang.IReduceInit (reduce [_ f init] (loop [ret init] - (let [code (int - #_{:clj-kondo/ignore [:type-mismatch]} - (api/step stmt))] - (case code - 100 (let [ret (f ret (column stmt n-cols))] - (if (reduced? ret) - @ret - (recur ret))) - 101 ret - code))))))))) + (case (int + #_{:clj-kondo/ignore [:type-mismatch]} + (api/step stmt)) + 100 (let [ret (f ret (column stmt n-cols))] + (if (reduced? ret) + @ret + (recur ret))) + 101 ret + (throw (api/sqlite-ex-info (:pdb conn) + ret + {:sql (first query) + :params (subvec query 1)})))))))))) (def default-pragma {:cache_size 15625