Closes #77 by removing the experimental middleware code
This commit is contained in:
parent
a4a8602af4
commit
9987d84210
2 changed files with 0 additions and 191 deletions
|
|
@ -1,115 +0,0 @@
|
|||
;; copyright (c) 2019-2020 Sean Corfield, all rights reserved
|
||||
|
||||
(ns next.jdbc.middleware
|
||||
"This is just an experimental sketch of what it might look like to be
|
||||
able to provide middleware that can wrap SQL execution in a way that
|
||||
behavior can be extended in interesting ways, to support logging, timing.
|
||||
and other cross-cutting things.
|
||||
|
||||
Since it's just an experiment, there's no guarantee that this -- or
|
||||
anything like it -- will actually end up in a next.jdbc release. You've
|
||||
been warned!
|
||||
|
||||
So far these execution points can be hooked into:
|
||||
* start -- pre-process the SQL & parameters and options
|
||||
* (execute SQL)
|
||||
* ????? -- process the options (and something else?)
|
||||
* row -- post-process each row and options
|
||||
* rs -- post-process the whole result set and options
|
||||
|
||||
For the rows and result set, it's 'obvious' that the functions should
|
||||
take the values and return them (or updated versions). For the start
|
||||
function with SQL & parameters, it also makes sense to take and return
|
||||
that vector.
|
||||
|
||||
For timing middleware, you'd need to pass data through the call chain
|
||||
somehow -- unless you control the whole middleware and this isn't sufficient
|
||||
for that yet. Hence the decision to allow processing of the options and
|
||||
passing data through those -- which leads to a rather odd call chain:
|
||||
start can return the vector or a map of updated options (with a payload),
|
||||
and the ????? point can process the options again (e.g., to update timing
|
||||
data etc). And that's all kind of horrible."
|
||||
(:require [next.jdbc.protocols :as p]
|
||||
[next.jdbc.result-set :as rs]))
|
||||
|
||||
(defn post-processing-adapter
|
||||
"Given a builder function (e.g., `as-lower-maps`), return a new builder
|
||||
function that post-processes rows and the result set. The options may
|
||||
contain post-processing functions that are called on each row and on the
|
||||
the result set. The options map is provided as a second parameter to these
|
||||
functions, which should include `:next.jdbc/sql-params` (the vector of SQL
|
||||
and parameters, in case post-processing needs it):
|
||||
|
||||
* `:execute-fn` -- called immediately after the SQL operation completes
|
||||
^ This is a horrible name and it needs to return the options which
|
||||
is weird so I don't like this approach overall...
|
||||
* `:row!-fn` -- called on each row as it is fully-realized
|
||||
* `:rs!-fn` -- called on the whole result set once it is fully-realized
|
||||
|
||||
The results of these functions are returned as the rows/result set."
|
||||
[builder-fn]
|
||||
(fn [rs opts]
|
||||
(let [id2 (fn [x _] x)
|
||||
id2' (fn [_ x] x)
|
||||
exec-fn (get opts :execute-fn id2')
|
||||
opts (exec-fn rs opts)
|
||||
mrsb (builder-fn rs opts)
|
||||
row!-fn (get opts :row!-fn id2)
|
||||
rs!-fn (get opts :rs!-fn id2)]
|
||||
(reify
|
||||
rs/RowBuilder
|
||||
(->row [this] (rs/->row mrsb))
|
||||
(column-count [this] (rs/column-count mrsb))
|
||||
(with-column [this row i] (rs/with-column mrsb row i))
|
||||
(row! [this row] (row!-fn (rs/row! mrsb row) opts))
|
||||
rs/ResultSetBuilder
|
||||
(->rs [this] (rs/->rs mrsb))
|
||||
(with-row [this mrs row] (rs/with-row mrsb mrs row))
|
||||
(rs! [this mrs] (rs!-fn (rs/rs! mrsb mrs) opts))))))
|
||||
|
||||
(defrecord JdbcMiddleware [db global-opts]
|
||||
p/Executable
|
||||
(-execute [this sql-params opts]
|
||||
(let [opts (merge global-opts opts)
|
||||
id2 (fn [x _] x)
|
||||
builder-fn (get opts :builder-fn rs/as-maps)
|
||||
sql-params-fn (get opts :sql-params-fn id2)
|
||||
result (sql-params-fn sql-params opts)
|
||||
sql-params' (if (map? result)
|
||||
(or (:next.jdbc/sql-params result) sql-params)
|
||||
result)]
|
||||
(p/-execute db sql-params'
|
||||
(assoc (if (map? result) result opts)
|
||||
:builder-fn (post-processing-adapter builder-fn)
|
||||
:next.jdbc/sql-params sql-params'))))
|
||||
(-execute-one [this sql-params opts]
|
||||
(let [opts (merge global-opts opts)
|
||||
id2 (fn [x _] x)
|
||||
builder-fn (get opts :builder-fn rs/as-maps)
|
||||
sql-params-fn (get opts :sql-params-fn id2)
|
||||
result (sql-params-fn sql-params opts)
|
||||
sql-params' (if (map? result)
|
||||
(or (:next.jdbc/sql-params result) sql-params)
|
||||
result)]
|
||||
(p/-execute-one db sql-params'
|
||||
(assoc (if (map? result) result opts)
|
||||
:builder-fn (post-processing-adapter builder-fn)
|
||||
:next.jdbc/sql-params sql-params'))))
|
||||
(-execute-all [this sql-params opts]
|
||||
(let [opts (merge global-opts opts)
|
||||
id2 (fn [x _] x)
|
||||
builder-fn (get opts :builder-fn rs/as-maps)
|
||||
sql-params-fn (get opts :sql-params-fn id2)
|
||||
result (sql-params-fn sql-params opts)
|
||||
sql-params' (if (map? result)
|
||||
(or (:next.jdbc/sql-params result) sql-params)
|
||||
result)]
|
||||
(p/-execute-all db sql-params'
|
||||
(assoc (if (map? result) result opts)
|
||||
:builder-fn (post-processing-adapter builder-fn)
|
||||
:next.jdbc/sql-params sql-params')))))
|
||||
|
||||
(defn wrapper
|
||||
""
|
||||
([db] (JdbcMiddleware. db {}))
|
||||
([db opts] (JdbcMiddleware. db opts)))
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
;; copyright (c) 2019-2020 Sean Corfield, all rights reserved
|
||||
|
||||
(ns next.jdbc.middleware-test
|
||||
(:require [clojure.test :refer [deftest is use-fixtures]]
|
||||
[next.jdbc :as jdbc]
|
||||
[next.jdbc.middleware :as mw]
|
||||
[next.jdbc.test-fixtures :refer [with-test-db db ds
|
||||
default-options]]
|
||||
[next.jdbc.result-set :as rs]
|
||||
[next.jdbc.specs :as specs]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(use-fixtures :once with-test-db)
|
||||
|
||||
(specs/instrument)
|
||||
|
||||
(deftest logging-test
|
||||
(let [logging (atom [])
|
||||
logger (fn [data _] (swap! logging conj data) data)
|
||||
|
||||
sql-p ["select * from fruit where id in (?,?) order by id desc" 1 4]]
|
||||
(jdbc/execute! (mw/wrapper (ds))
|
||||
sql-p
|
||||
(assoc (default-options)
|
||||
:builder-fn rs/as-lower-maps
|
||||
:sql-params-fn logger
|
||||
:row!-fn logger
|
||||
:rs!-fn logger))
|
||||
;; should log four things
|
||||
(is (= 4 (-> @logging count)))
|
||||
;; :next.jdbc/sql-params value
|
||||
(is (= sql-p (-> @logging (nth 0))))
|
||||
;; first row (with PK 4)
|
||||
(is (= 4 (-> @logging (nth 1) :fruit/id)))
|
||||
;; second row (with PK 1)
|
||||
(is (= 1 (-> @logging (nth 2) :fruit/id)))
|
||||
;; full result set with two rows
|
||||
(is (= 2 (-> @logging (nth 3) count)))
|
||||
(is (= [4 1] (-> @logging (nth 3) (->> (map :fruit/id)))))
|
||||
;; now repeat without the row logging
|
||||
(reset! logging [])
|
||||
(jdbc/execute! (mw/wrapper (ds)
|
||||
{:builder-fn rs/as-lower-maps
|
||||
:sql-params-fn logger
|
||||
:rs!-fn logger})
|
||||
sql-p
|
||||
(default-options))
|
||||
;; should log two things
|
||||
(is (= 2 (-> @logging count)))
|
||||
;; :next.jdbc/sql-params value
|
||||
(is (= sql-p (-> @logging (nth 0))))
|
||||
;; full result set with two rows
|
||||
(is (= 2 (-> @logging (nth 1) count)))
|
||||
(is (= [4 1] (-> @logging (nth 1) (->> (map :fruit/id)))))))
|
||||
|
||||
(deftest timing-test
|
||||
(let [timing (atom {:calls 0 :total 0.0})
|
||||
start-fn (fn [_ opts]
|
||||
(swap! (:timing opts) update :calls inc)
|
||||
(assoc opts :start (System/nanoTime)))
|
||||
exec-fn (fn [_ opts]
|
||||
(let [end (System/nanoTime)]
|
||||
(swap! (:timing opts) update :total + (- end (:start opts)))
|
||||
opts))
|
||||
sql-p ["select * from fruit where id in (?,?) order by id desc" 1 4]]
|
||||
(jdbc/execute! (mw/wrapper (ds) {:timing timing
|
||||
:sql-params-fn start-fn
|
||||
:execute-fn exec-fn})
|
||||
sql-p)
|
||||
(jdbc/execute! (mw/wrapper (ds) {:timing timing
|
||||
:sql-params-fn start-fn
|
||||
:execute-fn exec-fn})
|
||||
sql-p)
|
||||
(println (format "%6s %d calls took %,10d nanoseconds"
|
||||
(:dbtype (db)) (:calls @timing) (long (:total @timing))))))
|
||||
Loading…
Reference in a new issue