diff --git a/src/next/jdbc/result_set.clj b/src/next/jdbc/result_set.clj index e709cce..962d66d 100644 --- a/src/next/jdbc/result_set.clj +++ b/src/next/jdbc/result_set.clj @@ -275,6 +275,10 @@ :qualifier-fn ->kebab-case :label-fn ->kebab-case))) +(comment + (->kebab-case "_id") ;;=> "id"!! + ) + (defn as-unqualified-kebab-maps "Given a `ResultSet` and options, return a `RowBuilder` / `ResultSetBuilder` that produces bare vectors of hash map rows, with simple, kebab-case keys." diff --git a/test/next/jdbc/optional_test.clj b/test/next/jdbc/optional_test.clj index 50444cf..1a71f43 100644 --- a/test/next/jdbc/optional_test.clj +++ b/test/next/jdbc/optional_test.clj @@ -6,9 +6,10 @@ [clojure.test :refer [deftest is testing use-fixtures]] [next.jdbc.optional :as opt] [next.jdbc.protocols :as p] - [next.jdbc.test-fixtures :refer [with-test-db ds column - default-options]]) - (:import (java.sql ResultSet ResultSetMetaData))) + [next.jdbc.test-fixtures :refer [col-kw column default-options ds index + with-test-db]]) + (:import + (java.sql ResultSet ResultSetMetaData))) (set! *warn-on-reflection* true) @@ -17,7 +18,7 @@ (deftest test-map-row-builder (testing "default row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 1] + [(str "select * from fruit where " (index) " = ?") 1] (assoc (default-options) :builder-fn opt/as-maps))] (is (map? row)) @@ -26,7 +27,7 @@ (is (= "Apple" ((column :FRUIT/NAME) row))))) (testing "unqualified row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 2] + [(str "select * from fruit where " (index) " = ?") 2] {:builder-fn opt/as-unqualified-maps})] (is (map? row)) (is (not (contains? row (column :COST)))) @@ -34,23 +35,23 @@ (is (= "Banana" ((column :NAME) row))))) (testing "lower-case row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 3] + [(str "select * from fruit where " (index) " = ?") 3] (assoc (default-options) :builder-fn opt/as-lower-maps))] (is (map? row)) - (is (not (contains? row :fruit/appearance))) - (is (= 3 (:fruit/id row))) - (is (= "Peach" (:fruit/name row))))) + (is (not (contains? row (col-kw :fruit/appearance)))) + (is (= 3 ((col-kw :fruit/id) row))) + (is (= "Peach" ((col-kw :fruit/name) row))))) (testing "unqualified lower-case row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 4] + [(str "select * from fruit where " (index) " = ?") 4] {:builder-fn opt/as-unqualified-lower-maps})] (is (map? row)) - (is (= 4 (:id row))) - (is (= "Orange" (:name row))))) + (is (= 4 ((col-kw :id) row))) + (is (= "Orange" ((col-kw :name) row))))) (testing "custom row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 3] + [(str "select * from fruit where " (index) " = ?") 3] (assoc (default-options) :builder-fn opt/as-modified-maps :label-fn str/lower-case @@ -67,7 +68,7 @@ (deftest test-map-row-adapter (testing "default row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 1] + [(str "select * from fruit where " (index) " = ?") 1] (assoc (default-options) :builder-fn (opt/as-maps-adapter opt/as-maps @@ -78,7 +79,7 @@ (is (= "Apple" ((column :FRUIT/NAME) row))))) (testing "unqualified row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 2] + [(str "select * from fruit where " (index) " = ?") 2] {:builder-fn (opt/as-maps-adapter opt/as-unqualified-maps default-column-reader)})] @@ -88,27 +89,27 @@ (is (= "Banana" ((column :NAME) row))))) (testing "lower-case row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 3] + [(str "select * from fruit where " (index) " = ?") 3] (assoc (default-options) :builder-fn (opt/as-maps-adapter opt/as-lower-maps default-column-reader)))] (is (map? row)) - (is (not (contains? row :fruit/appearance))) - (is (= 3 (:fruit/id row))) - (is (= "Peach" (:fruit/name row))))) + (is (not (contains? row (col-kw :fruit/appearance)))) + (is (= 3 ((col-kw :fruit/id) row))) + (is (= "Peach" ((col-kw :fruit/name) row))))) (testing "unqualified lower-case row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 4] + [(str "select * from fruit where " (index) " = ?") 4] {:builder-fn (opt/as-maps-adapter opt/as-unqualified-lower-maps default-column-reader)})] (is (map? row)) - (is (= 4 (:id row))) - (is (= "Orange" (:name row))))) + (is (= 4 ((col-kw :id) row))) + (is (= "Orange" ((col-kw :name) row))))) (testing "custom row builder" (let [row (p/-execute-one (ds) - ["select * from fruit where id = ?" 3] + [(str "select * from fruit where " (index) " = ?") 3] (assoc (default-options) :builder-fn (opt/as-maps-adapter opt/as-modified-maps diff --git a/test/next/jdbc/plan_test.clj b/test/next/jdbc/plan_test.clj index 51012f0..c477a8f 100644 --- a/test/next/jdbc/plan_test.clj +++ b/test/next/jdbc/plan_test.clj @@ -6,7 +6,7 @@ [next.jdbc.plan :as plan] [next.jdbc.specs :as specs] [next.jdbc.test-fixtures - :refer [with-test-db ds]] + :refer [with-test-db ds col-kw index]] [clojure.string :as str])) (set! *warn-on-reflection* true) @@ -17,56 +17,56 @@ (specs/instrument) (deftest select-one!-tests - (is (= {:id 1} - (plan/select-one! (ds) [:id] ["select * from fruit order by id"]))) + (is (= {(col-kw :id) 1} + (plan/select-one! (ds) [(col-kw :id)] [(str "select * from fruit order by " (index))]))) (is (= 1 - (plan/select-one! (ds) :id ["select * from fruit order by id"]))) + (plan/select-one! (ds) (col-kw :id) [(str "select * from fruit order by " (index))]))) (is (= "Banana" - (plan/select-one! (ds) :name ["select * from fruit where id = ?" 2]))) + (plan/select-one! (ds) :name [(str "select * from fruit where " (index) " = ?") 2]))) (is (= [1 "Apple"] - (plan/select-one! (ds) (juxt :id :name) - ["select * from fruit order by id"]))) - (is (= {:id 1 :name "Apple"} - (plan/select-one! (ds) #(select-keys % [:id :name]) - ["select * from fruit order by id"])))) + (plan/select-one! (ds) (juxt (col-kw :id) :name) + [(str "select * from fruit order by " (index))]))) + (is (= {(col-kw :id) 1 :name "Apple"} + (plan/select-one! (ds) #(select-keys % [(col-kw :id) :name]) + [(str "select * from fruit order by " (index))])))) (deftest select-vector-tests - (is (= [{:id 1} {:id 2} {:id 3} {:id 4}] - (plan/select! (ds) [:id] ["select * from fruit order by id"]))) + (is (= [{(col-kw :id) 1} {(col-kw :id) 2} {(col-kw :id) 3} {(col-kw :id) 4}] + (plan/select! (ds) [(col-kw :id)] [(str "select * from fruit order by " (index))]))) (is (= [1 2 3 4] - (plan/select! (ds) :id ["select * from fruit order by id"]))) + (plan/select! (ds) (col-kw :id) [(str "select * from fruit order by " (index))]))) (is (= ["Banana"] - (plan/select! (ds) :name ["select * from fruit where id = ?" 2]))) + (plan/select! (ds) :name [(str "select * from fruit where " (index) " = ?") 2]))) (is (= [[2 "Banana"]] - (plan/select! (ds) (juxt :id :name) - ["select * from fruit where id = ?" 2]))) - (is (= [{:id 2 :name "Banana"}] - (plan/select! (ds) [:id :name] - ["select * from fruit where id = ?" 2])))) + (plan/select! (ds) (juxt (col-kw :id) :name) + [(str "select * from fruit where " (index) " = ?") 2]))) + (is (= [{(col-kw :id) 2 :name "Banana"}] + (plan/select! (ds) [(col-kw :id) :name] + [(str "select * from fruit where " (index) " = ?") 2])))) (deftest select-set-tests - (is (= #{{:id 1} {:id 2} {:id 3} {:id 4}} - (plan/select! (ds) [:id] ["select * from fruit order by id"] + (is (= #{{(col-kw :id) 1} {(col-kw :id) 2} {(col-kw :id) 3} {(col-kw :id) 4}} + (plan/select! (ds) [(col-kw :id)] [(str "select * from fruit order by " (index))] {:into #{}}))) (is (= #{1 2 3 4} - (plan/select! (ds) :id ["select * from fruit order by id"] + (plan/select! (ds) (col-kw :id) [(str "select * from fruit order by " (index))] {:into #{}})))) (deftest select-map-tests (is (= {1 "Apple", 2 "Banana", 3 "Peach", 4 "Orange"} - (plan/select! (ds) (juxt :id :name) ["select * from fruit order by id"] + (plan/select! (ds) (juxt (col-kw :id) :name) [(str "select * from fruit order by " (index))] {:into {}})))) (deftest select-issue-227 (is (= ["Apple"] - (plan/select! (ds) :name ["select * from fruit where id = ?" 1] + (plan/select! (ds) :name [(str "select * from fruit where " (index) " = ?") 1] {:column-fn #(str/replace % "-" "_")}))) (is (= ["Apple"] - (plan/select! (ds) :foo/name ["select * from fruit where id = ?" 1] + (plan/select! (ds) :foo/name [(str "select * from fruit where " (index) " = ?") 1] {:column-fn #(str/replace % "-" "_")}))) (is (= ["Apple"] - (plan/select! (ds) #(get % "name") ["select * from fruit where id = ?" 1] + (plan/select! (ds) #(get % "name") [(str "select * from fruit where " (index) " = ?") 1] {:column-fn #(str/replace % "-" "_")}))) (is (= [["Apple"]] - (plan/select! (ds) (juxt :name) ["select * from fruit where id = ?" 1] + (plan/select! (ds) (juxt :name) [(str "select * from fruit where " (index) " = ?") 1] {:column-fn #(str/replace % "-" "_")})))) diff --git a/test/next/jdbc/result_set_test.clj b/test/next/jdbc/result_set_test.clj index ea9b803..8d893ac 100644 --- a/test/next/jdbc/result_set_test.clj +++ b/test/next/jdbc/result_set_test.clj @@ -27,7 +27,9 @@ (testing "default schema" (let [connectable (ds) test-row (rs/datafiable-row {:TABLE/FRUIT_ID 1} connectable - (default-options)) + (cond-> (default-options) + (xtdb?) + (assoc :schema-opts {:pk "_id"}))) data (d/datafy test-row) v (get data :TABLE/FRUIT_ID)] ;; check datafication is sane @@ -40,7 +42,10 @@ (let [connectable (ds) test-row (rs/datafiable-row {:foo/bar 2} connectable (assoc (default-options) - :schema {:foo/bar :fruit/id})) + :schema {:foo/bar + (if (xtdb?) + :fruit/_id + :fruit/id)})) data (d/datafy test-row) v (get data :foo/bar)] ;; check datafication is sane @@ -53,7 +58,10 @@ (let [connectable (ds) test-row (rs/datafiable-row {:foo/bar 3} connectable (assoc (default-options) - :schema {:foo/bar [:fruit/id]})) + :schema {:foo/bar + [(if (xtdb?) + :fruit/_id + :fruit/id)]})) data (d/datafy test-row) v (get data :foo/bar)] ;; check datafication is sane @@ -67,7 +75,7 @@ (let [connectable (ds) test-row (rs/datafiable-row {:foo/bar 2} connectable (assoc (default-options) - :schema {:foo/bar [:fruit :id]})) + :schema {:foo/bar [:fruit (col-kw :id)]})) data (d/datafy test-row) v (get data :foo/bar)] ;; check datafication is sane @@ -79,7 +87,7 @@ (let [connectable (ds) test-row (rs/datafiable-row {:foo/bar 3} connectable (assoc (default-options) - :schema {:foo/bar [:fruit :id :many]})) + :schema {:foo/bar [:fruit (col-kw :id) :many]})) data (d/datafy test-row) v (get data :foo/bar)] ;; check datafication is sane @@ -123,17 +131,17 @@ (assoc (default-options) :builder-fn rs/as-lower-maps))] (is (map? row)) - (is (contains? row :fruit/appearance)) - (is (nil? (:fruit/appearance row))) - (is (= 3 (:fruit/id row))) - (is (= "Peach" (:fruit/name row))))) + (is (contains? row (col-kw :fruit/appearance))) + (is (nil? ((col-kw :fruit/appearance) row))) + (is (= 3 ((col-kw :fruit/id) row))) + (is (= "Peach" ((col-kw :fruit/name) row))))) (testing "unqualified lower-case row builder" (let [row (p/-execute-one (ds) [(str "select * from fruit where " (index) " = ?") 4] {:builder-fn rs/as-unqualified-lower-maps})] (is (map? row)) - (is (= 4 (:id row))) - (is (= "Orange" (:name row))))) + (is (= 4 ((col-kw :id) row))) + (is (= "Orange" ((col-kw :name) row))))) (testing "kebab-case row builder" (let [row (p/-execute-one (ds) [(str "select " (index) ",name,appearance as looks_like from fruit where " (index) " = ?") 3] @@ -142,7 +150,8 @@ (is (map? row)) (is (contains? row (col-kw :fruit/looks-like))) (is (nil? ((col-kw :fruit/looks-like) row))) - (is (= 3 ((col-kw :fruit/id) row))) + ;; kebab-case strips leading _ from _id (XTDB): + (is (= 3 ((if (xtdb?) :id :fruit/id) row))) (is (= "Peach" ((col-kw :fruit/name) row))))) (testing "unqualified kebab-case row builder" (let [row (p/-execute-one (ds) @@ -151,7 +160,7 @@ (is (map? row)) (is (contains? row :looks-like)) (is (= "juicy" (:looks-like row))) - (is (= 4 ((col-kw :id) row))) + (is (= 4 (:id row))) (is (= "Orange" (:name row))))) (testing "custom row builder 1" (let [row (p/-execute-one (ds) @@ -176,7 +185,7 @@ (is (map? row)) (is (contains? row :vegetable/appearance)) (is (nil? (:vegetable/appearance row))) - (is (= 3 (:vegetable/id row))) + (is (= 3 ((if (xtdb?) :vegetable/_id :vegetable/id) row))) (is (= 103 (:vegetable/newid row))) ; constant qualifier here (is (= "Peach" (:vegetable/name row))))) (testing "adapted row builder" @@ -310,15 +319,15 @@ #(find % :name))) ; get MapEntry works (p/-execute (ds) [(str "select * from fruit where " (index) " = ?") 2] {:builder-fn (constantly nil)})))) - (is (= [{:id 3 :name "Peach"}] - (into [] (map #(select-keys % [:id :name])) ; select-keys works + (is (= [{(col-kw :id) 3 :name "Peach"}] + (into [] (map #(select-keys % [(col-kw :id) :name])) ; select-keys works (p/-execute (ds) [(str "select * from fruit where " (index) " = ?") 3] {:builder-fn (constantly nil)})))) (is (= [[:orange 4]] (into [] (map #(vector (if (contains? % :name) ; contains works (keyword (str/lower-case (:name %))) :unnamed) - (get % :id 0))) ; get with not-found works + (get % (col-kw :id) 0))) ; get with not-found works (p/-execute (ds) [(str "select * from fruit where " (index) " = ?") 4] {:builder-fn (constantly nil)})))) (is (= [{}] @@ -434,7 +443,7 @@ (valAt [this k] (get this k nil)) (valAt [this k not-found] (case k - :cols [:id :name :appearance :cost :grade] + :cols [(col-kw :id) :name :appearance :cost :grade] :rsmeta rsmeta not-found)))) @@ -497,10 +506,10 @@ CREATE TABLE CLOBBER ( (testing "get n on bare abstraction over arrays" (is (= [1 2 3] (into [] (map #(get % 0)) - (p/-execute (ds) [(str "select " (index) " from fruit where " (index) " < ?") 4] + (p/-execute (ds) [(str "select " (index) " from fruit where " (index) " < ? order by " (index)) 4] {:builder-fn rs/as-arrays}))))) (testing "nth on bare abstraction over arrays" (is (= [1 2 3] (into [] (map #(nth % 0)) - (p/-execute (ds) [(str "select " (index) " from fruit where " (index) " < ?") 4] + (p/-execute (ds) [(str "select " (index) " from fruit where " (index) " < ? order by " (index)) 4] {:builder-fn rs/as-arrays})))))) diff --git a/test/next/jdbc/sql_test.clj b/test/next/jdbc/sql_test.clj index 78b4ef3..ad92433 100644 --- a/test/next/jdbc/sql_test.clj +++ b/test/next/jdbc/sql_test.clj @@ -20,7 +20,7 @@ (deftest test-query (let [ds-opts (jdbc/with-options (ds) (default-options)) - rs (sql/query ds-opts ["select * from fruit order by id"])] + rs (sql/query ds-opts [(str "select * from fruit order by " (index))])] (is (= 4 (count rs))) (is (every? map? rs)) (is (every? meta rs)) @@ -35,10 +35,10 @@ (if (or (mysql?) (sqlite?)) {:limit 2 :offset 1} {:offset 1 :fetch 2}) - :columns [:ID + :columns [(col-kw :ID) ["CASE WHEN grade > 91 THEN 'ok ' ELSE 'bad' END" :QUALITY]] - :order-by [:id]))] + :order-by [(col-kw :id)]))] (is (= 2 (count rs))) (is (every? map? rs)) (is (every? meta rs)) @@ -68,10 +68,11 @@ (is (= 1 count-v))) (let [count-v (sql/aggregate-by-keys ds-opts :fruit "count(*)" :all)] (is (= 4 count-v))) - (let [max-id (sql/aggregate-by-keys ds-opts :fruit "max(id)" :all)] + (let [max-id (sql/aggregate-by-keys ds-opts :fruit (str "max(" (index) ")") :all)] (is (= 4 max-id))) - (let [min-name (sql/aggregate-by-keys ds-opts :fruit "min(name)" :all)] - (is (= "Apple" min-name))) + (when-not (xtdb?) ; XTDB does not support min/max on strings? + (let [min-name (sql/aggregate-by-keys ds-opts :fruit "min(name)" :all)] + (is (= "Apple" min-name)))) (is (thrown? IllegalArgumentException (sql/aggregate-by-keys ds-opts :fruit "count(*)" :all {:columns []}))))) diff --git a/test/next/jdbc/test_fixtures.clj b/test/next/jdbc/test_fixtures.clj index fa5f6af..f472206 100644 --- a/test/next/jdbc/test_fixtures.clj +++ b/test/next/jdbc/test_fixtures.clj @@ -117,7 +117,7 @@ (defn col-kw [k] (if (xtdb?) (let [n (name k)] - (if (= "id" n) :_id (keyword n))) + (if (= "id" (str/lower-case n)) :_id (keyword n))) k)) (defn default-options [] diff --git a/test/next/jdbc_test.clj b/test/next/jdbc_test.clj index 4e486e1..6a6cb64 100644 --- a/test/next/jdbc_test.clj +++ b/test/next/jdbc_test.clj @@ -163,25 +163,26 @@ (is (every? int? (map first (rest rs)))) (let [n (max (.indexOf ^java.util.List (first rs) :name) 1)] (is (every? string? (map #(nth % n) (rest rs))))))) - (testing "execute! with :max-rows / :maxRows" - (let [rs (jdbc/execute! - ds-opts - [(str "select * from fruit order by " (index))] - {:max-rows 2})] - (is (every? map? rs)) - (is (every? meta rs)) - (is (= 2 (count rs))) - (is (= 1 ((column :FRUIT/ID) (first rs)))) - (is (= 2 ((column :FRUIT/ID) (last rs))))) - (let [rs (jdbc/execute! - ds-opts - [(str "select * from fruit order by " (index))] - {:statement {:maxRows 2}})] - (is (every? map? rs)) - (is (every? meta rs)) - (is (= 2 (count rs))) - (is (= 1 ((column :FRUIT/ID) (first rs)))) - (is (= 2 ((column :FRUIT/ID) (last rs))))))) + (when-not (xtdb?) ; XTDB does not support this yet + (testing "execute! with :max-rows / :maxRows" + (let [rs (jdbc/execute! + ds-opts + [(str "select * from fruit order by " (index))] + {:max-rows 2})] + (is (every? map? rs)) + (is (every? meta rs)) + (is (= 2 (count rs))) + (is (= 1 ((column :FRUIT/ID) (first rs)))) + (is (= 2 ((column :FRUIT/ID) (last rs))))) + (let [rs (jdbc/execute! + ds-opts + [(str "select * from fruit order by " (index))] + {:statement {:maxRows 2}})] + (is (every? map? rs)) + (is (every? meta rs)) + (is (= 2 (count rs))) + (is (= 1 ((column :FRUIT/ID) (first rs)))) + (is (= 2 ((column :FRUIT/ID) (last rs)))))))) (testing "prepare" ;; default options do not flow over get-connection (let [rs (with-open [con (jdbc/get-connection (ds)) @@ -211,7 +212,6 @@ (let [rs (with-open [con (jdbc/get-connection (ds))] (jdbc/execute! (prep/statement con (default-options)) [(str "select * from fruit order by " (index))]))] - (when (xtdb?) (println rs)) (is (every? map? rs)) (is (every? meta rs)) (is (= 4 (count rs))) @@ -221,7 +221,6 @@ (let [rs (with-open [con (jdbc/get-connection (ds))] (jdbc/execute! (prep/statement con (default-options)) [(str "select * from fruit where " (index) " = 4")]))] - (when (xtdb?) (println rs)) (is (every? map? rs)) (is (every? meta rs)) (is (= 1 (count rs)))