From 9987d84210fff9ab4751e701dedef1f0dec98355 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Thu, 25 Jun 2020 19:22:59 -0700 Subject: [PATCH] Closes #77 by removing the experimental middleware code --- test/next/jdbc/middleware.clj | 115 ----------------------------- test/next/jdbc/middleware_test.clj | 76 ------------------- 2 files changed, 191 deletions(-) delete mode 100644 test/next/jdbc/middleware.clj delete mode 100644 test/next/jdbc/middleware_test.clj diff --git a/test/next/jdbc/middleware.clj b/test/next/jdbc/middleware.clj deleted file mode 100644 index c8e920a..0000000 --- a/test/next/jdbc/middleware.clj +++ /dev/null @@ -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))) diff --git a/test/next/jdbc/middleware_test.clj b/test/next/jdbc/middleware_test.clj deleted file mode 100644 index cdc1319..0000000 --- a/test/next/jdbc/middleware_test.clj +++ /dev/null @@ -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))))))