XTDB 0 failures!

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2024-11-24 09:27:49 -08:00
parent 564c43bc79
commit 05cfe1f3fa
No known key found for this signature in database
7 changed files with 112 additions and 98 deletions

View file

@ -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."

View file

@ -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

View file

@ -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 % "-" "_")}))))

View file

@ -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}))))))

View file

@ -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)))
(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 (= "Apple" min-name))))
(is (thrown? IllegalArgumentException
(sql/aggregate-by-keys ds-opts :fruit "count(*)" :all {:columns []})))))

View file

@ -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 []

View file

@ -163,6 +163,7 @@
(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)))))))
(when-not (xtdb?) ; XTDB does not support this yet
(testing "execute! with :max-rows / :maxRows"
(let [rs (jdbc/execute!
ds-opts
@ -181,7 +182,7 @@
(is (every? meta rs))
(is (= 2 (count rs)))
(is (= 1 ((column :FRUIT/ID) (first rs))))
(is (= 2 ((column :FRUIT/ID) (last 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)))