Add optional MS SQL Server testing
This commit is contained in:
parent
774e08236f
commit
5b795f95a7
9 changed files with 156 additions and 89 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -14,3 +14,4 @@ pom.xml.asc
|
|||
/clojure_test*
|
||||
/example*db
|
||||
/derby.log
|
||||
/run-tests.sh
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Only accretive/fixative changes will be made from now on.
|
|||
|
||||
The following changes have been committed to the **master** branch since the 1.0.10 release:
|
||||
|
||||
* Add testing against Microsoft SQL Server (run tests with environment variables `NEXT_JDBC_TEST_MSSQL=yes` and `MSSQL_SA_PASSWORD` set to your local SQL Server `sa` user password; assumes that it can create and drop `fruit` and `fruit_time` tables in the `model` database).
|
||||
* Add testing against MySQL (run tests with environment variables `NEXT_JDBC_TEST_MYSQL=yes` and `MYSQL_ROOT_PASSWORD` set to your local MySQL `root` user password; assumes you have already created an empty database called `clojure_test`).
|
||||
* Bump several JDBC driver versions for up-to-date testing.
|
||||
* Minor documentation fixes.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
(:require [clojure.test :refer [deftest is testing use-fixtures]]
|
||||
[next.jdbc :as jdbc]
|
||||
[next.jdbc.date-time] ; to extend SettableParameter to date/time
|
||||
[next.jdbc.test-fixtures :refer [with-test-db db ds]]
|
||||
[next.jdbc.test-fixtures :refer [with-test-db db ds
|
||||
mssql?]]
|
||||
[next.jdbc.specs :as specs])
|
||||
(:import (java.sql ResultSet)))
|
||||
|
||||
|
|
@ -21,26 +22,28 @@
|
|||
|
||||
(deftest issue-73
|
||||
(try
|
||||
(jdbc/execute-one! (ds) ["drop table temp_table"])
|
||||
(jdbc/execute-one! (ds) ["drop table fruit_time"])
|
||||
(catch Throwable _))
|
||||
(jdbc/execute-one! (ds) ["create table temp_table (id int not null, deadline timestamp not null)"])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)])
|
||||
(jdbc/execute-one! (ds) [(str "create table fruit_time (id int not null, deadline "
|
||||
(if (mssql?) "datetime" "timestamp")
|
||||
" not null)")])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)])
|
||||
(try
|
||||
(jdbc/execute-one! (ds) ["drop table temp_table"])
|
||||
(jdbc/execute-one! (ds) ["drop table fruit_time"])
|
||||
(catch Throwable _))
|
||||
(jdbc/execute-one! (ds) ["create table temp_table (id int not null, deadline time not null)"])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)])
|
||||
(jdbc/execute-one! (ds) ["create table fruit_time (id int not null, deadline time not null)"])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)])
|
||||
(try
|
||||
(jdbc/execute-one! (ds) ["drop table temp_table"])
|
||||
(jdbc/execute-one! (ds) ["drop table fruit_time"])
|
||||
(catch Throwable _))
|
||||
(jdbc/execute-one! (ds) ["create table temp_table (id int not null, deadline date not null)"])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into temp_table (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)]))
|
||||
(jdbc/execute-one! (ds) ["create table fruit_time (id int not null, deadline date not null)"])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 1 (java.util.Date.)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 2 (java.time.Instant/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 3 (java.time.LocalDate/now)])
|
||||
(jdbc/execute-one! (ds) ["insert into fruit_time (id, deadline) values (?,?)" 4 (java.time.LocalDateTime/now)]))
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
[next.jdbc.connection :as c]
|
||||
[next.jdbc.middleware :as mw]
|
||||
[next.jdbc.test-fixtures :refer [with-test-db db ds
|
||||
default-options
|
||||
derby? postgres?]]
|
||||
[next.jdbc.prepare :as prep]
|
||||
[next.jdbc.result-set :as rs]
|
||||
|
|
@ -25,10 +26,11 @@
|
|||
sql-p ["select * from fruit where id in (?,?) order by id desc" 1 4]]
|
||||
(jdbc/execute! (mw/wrapper (ds))
|
||||
sql-p
|
||||
{:builder-fn rs/as-lower-maps
|
||||
:sql-params-fn logger
|
||||
:row!-fn logger
|
||||
:rs!-fn logger})
|
||||
(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
|
||||
|
|
@ -46,7 +48,8 @@
|
|||
{:builder-fn rs/as-lower-maps
|
||||
:sql-params-fn logger
|
||||
:rs!-fn logger})
|
||||
sql-p)
|
||||
sql-p
|
||||
(default-options))
|
||||
;; should log two things
|
||||
(is (= 2 (-> @logging count)))
|
||||
;; :next.jdbc/sql-params value
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
[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]])
|
||||
[next.jdbc.test-fixtures :refer [with-test-db ds column
|
||||
default-options]])
|
||||
(:import (java.sql ResultSet ResultSetMetaData)))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
|
@ -17,7 +18,8 @@
|
|||
(testing "default row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 1]
|
||||
{:builder-fn opt/as-maps})]
|
||||
(assoc (default-options)
|
||||
:builder-fn opt/as-maps))]
|
||||
(is (map? row))
|
||||
(is (not (contains? row (column :FRUIT/GRADE))))
|
||||
(is (= 1 ((column :FRUIT/ID) row)))
|
||||
|
|
@ -33,7 +35,8 @@
|
|||
(testing "lower-case row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn opt/as-lower-maps})]
|
||||
(assoc (default-options)
|
||||
:builder-fn opt/as-lower-maps))]
|
||||
(is (map? row))
|
||||
(is (not (contains? row :fruit/appearance)))
|
||||
(is (= 3 (:fruit/id row)))
|
||||
|
|
@ -48,9 +51,10 @@
|
|||
(testing "custom row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn opt/as-modified-maps
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity})]
|
||||
(assoc (default-options)
|
||||
:builder-fn opt/as-modified-maps
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity))]
|
||||
(is (map? row))
|
||||
(is (not (contains? row (column :FRUIT/appearance))))
|
||||
(is (= 3 ((column :FRUIT/id) row)))
|
||||
|
|
@ -64,9 +68,10 @@
|
|||
(testing "default row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 1]
|
||||
{:builder-fn (opt/as-maps-adapter
|
||||
opt/as-maps
|
||||
default-column-reader)})]
|
||||
(assoc (default-options)
|
||||
:builder-fn (opt/as-maps-adapter
|
||||
opt/as-maps
|
||||
default-column-reader)))]
|
||||
(is (map? row))
|
||||
(is (not (contains? row (column :FRUIT/GRADE))))
|
||||
(is (= 1 ((column :FRUIT/ID) row)))
|
||||
|
|
@ -84,9 +89,10 @@
|
|||
(testing "lower-case row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn (opt/as-maps-adapter
|
||||
opt/as-lower-maps
|
||||
default-column-reader)})]
|
||||
(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)))
|
||||
|
|
@ -103,11 +109,12 @@
|
|||
(testing "custom row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn (opt/as-maps-adapter
|
||||
opt/as-modified-maps
|
||||
default-column-reader)
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity})]
|
||||
(assoc (default-options)
|
||||
:builder-fn (opt/as-maps-adapter
|
||||
opt/as-modified-maps
|
||||
default-column-reader)
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity))]
|
||||
(is (map? row))
|
||||
(is (not (contains? row (column :FRUIT/appearance))))
|
||||
(is (= 3 ((column :FRUIT/id) row)))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
[next.jdbc.protocols :as p]
|
||||
[next.jdbc.result-set :as rs]
|
||||
[next.jdbc.test-fixtures :refer [with-test-db ds column
|
||||
mysql? postgres?]])
|
||||
default-options
|
||||
mssql? mysql? postgres?]])
|
||||
(:import (java.sql ResultSet ResultSetMetaData)))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
|
@ -22,7 +23,8 @@
|
|||
(deftest test-datafy-nav
|
||||
(testing "default schema"
|
||||
(let [connectable (ds)
|
||||
test-row (rs/datafiable-row {:TABLE/FRUIT_ID 1} connectable {})
|
||||
test-row (rs/datafiable-row {:TABLE/FRUIT_ID 1} connectable
|
||||
(default-options))
|
||||
data (d/datafy test-row)
|
||||
v (get data :TABLE/FRUIT_ID)]
|
||||
;; check datafication is sane
|
||||
|
|
@ -34,7 +36,8 @@
|
|||
(testing "custom schema *-to-1"
|
||||
(let [connectable (ds)
|
||||
test-row (rs/datafiable-row {:foo/bar 2} connectable
|
||||
{:schema {:foo/bar :fruit/id}})
|
||||
(assoc (default-options)
|
||||
:schema {:foo/bar :fruit/id}))
|
||||
data (d/datafy test-row)
|
||||
v (get data :foo/bar)]
|
||||
;; check datafication is sane
|
||||
|
|
@ -46,7 +49,8 @@
|
|||
(testing "custom schema *-to-many"
|
||||
(let [connectable (ds)
|
||||
test-row (rs/datafiable-row {:foo/bar 3} connectable
|
||||
{:schema {:foo/bar [:fruit/id]}})
|
||||
(assoc (default-options)
|
||||
:schema {:foo/bar [:fruit/id]}))
|
||||
data (d/datafy test-row)
|
||||
v (get data :foo/bar)]
|
||||
;; check datafication is sane
|
||||
|
|
@ -59,7 +63,8 @@
|
|||
(testing "legacy schema tuples"
|
||||
(let [connectable (ds)
|
||||
test-row (rs/datafiable-row {:foo/bar 2} connectable
|
||||
{:schema {:foo/bar [:fruit :id]}})
|
||||
(assoc (default-options)
|
||||
:schema {:foo/bar [:fruit :id]}))
|
||||
data (d/datafy test-row)
|
||||
v (get data :foo/bar)]
|
||||
;; check datafication is sane
|
||||
|
|
@ -70,7 +75,8 @@
|
|||
(is (= "Banana" ((column :FRUIT/NAME) object)))))
|
||||
(let [connectable (ds)
|
||||
test-row (rs/datafiable-row {:foo/bar 3} connectable
|
||||
{:schema {:foo/bar [:fruit :id :many]}})
|
||||
(assoc (default-options)
|
||||
:schema {:foo/bar [:fruit :id :many]}))
|
||||
data (d/datafy test-row)
|
||||
v (get data :foo/bar)]
|
||||
;; check datafication is sane
|
||||
|
|
@ -85,7 +91,7 @@
|
|||
(testing "default row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 1]
|
||||
{})]
|
||||
(default-options))]
|
||||
(is (map? row))
|
||||
(is (contains? row (column :FRUIT/GRADE)))
|
||||
(is (nil? ((column :FRUIT/GRADE) row)))
|
||||
|
|
@ -93,7 +99,7 @@
|
|||
(is (= "Apple" ((column :FRUIT/NAME) row))))
|
||||
(let [rs (p/-execute-all (ds)
|
||||
["select * from fruit order by id"]
|
||||
{})]
|
||||
(default-options))]
|
||||
(is (every? map? rs))
|
||||
(is (= 1 ((column :FRUIT/ID) (first rs))))
|
||||
(is (= "Apple" ((column :FRUIT/NAME) (first rs))))
|
||||
|
|
@ -111,7 +117,8 @@
|
|||
(testing "lower-case row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn rs/as-lower-maps})]
|
||||
(assoc (default-options)
|
||||
:builder-fn rs/as-lower-maps))]
|
||||
(is (map? row))
|
||||
(is (contains? row :fruit/appearance))
|
||||
(is (nil? (:fruit/appearance row)))
|
||||
|
|
@ -127,9 +134,10 @@
|
|||
(testing "custom row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn rs/as-modified-maps
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity})]
|
||||
(assoc (default-options)
|
||||
:builder-fn rs/as-modified-maps
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity))]
|
||||
(is (map? row))
|
||||
(is (contains? row (column :FRUIT/appearance)))
|
||||
(is (nil? ((column :FRUIT/appearance) row)))
|
||||
|
|
@ -138,7 +146,9 @@
|
|||
(testing "adapted row builder"
|
||||
(let [row (p/-execute-one (ds)
|
||||
["select * from fruit where id = ?" 3]
|
||||
{:builder-fn (rs/as-maps-adapter
|
||||
(assoc
|
||||
(default-options)
|
||||
:builder-fn (rs/as-maps-adapter
|
||||
rs/as-modified-maps
|
||||
(fn [^ResultSet rs
|
||||
^ResultSetMetaData rsmeta
|
||||
|
|
@ -150,7 +160,7 @@
|
|||
(.getLong rs i)
|
||||
(.getObject rs i))))
|
||||
:label-fn str/lower-case
|
||||
:qualifier-fn identity})]
|
||||
:qualifier-fn identity))]
|
||||
(is (map? row))
|
||||
(is (contains? row (column :FRUIT/appearance)))
|
||||
(is (nil? ((column :FRUIT/appearance) row)))
|
||||
|
|
@ -205,11 +215,13 @@
|
|||
(is (map? (reduce (fn [_ row] (reduced
|
||||
(dissoc row (column :FRUIT/NAME))))
|
||||
nil
|
||||
(p/-execute (ds) ["select * from fruit"] {}))))
|
||||
(p/-execute (ds) ["select * from fruit"]
|
||||
(default-options)))))
|
||||
(is (= 4 (count (reduce (fn [_ row] (reduced
|
||||
(dissoc row (column :FRUIT/NAME))))
|
||||
nil
|
||||
(p/-execute (ds) ["select * from fruit"] {})))))
|
||||
(p/-execute (ds) ["select * from fruit"]
|
||||
(default-options))))))
|
||||
(is (seq? (reduce (fn [_ row] (reduced (seq row)))
|
||||
nil
|
||||
(p/-execute (ds) ["select * from fruit"] {}))))
|
||||
|
|
@ -286,7 +298,7 @@
|
|||
metadata))))
|
||||
|
||||
(deftest clob-reading
|
||||
(when-not (or (mysql?) (postgres?)) ; no clob in mysql or embedded postgres
|
||||
(when-not (or (mssql?) (mysql?) (postgres?)) ; no clob in these
|
||||
(with-open [con (p/get-connection (ds) {})]
|
||||
(try
|
||||
(p/-execute-one con ["DROP TABLE CLOBBER"] {})
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
[next.jdbc.specs :as specs]
|
||||
[next.jdbc.sql :as sql]
|
||||
[next.jdbc.test-fixtures
|
||||
:refer [with-test-db ds column derby? mysql? postgres? sqlite?]]))
|
||||
:refer [with-test-db ds column default-options
|
||||
derby? mssql? mysql? postgres? sqlite?]]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
|
|
@ -78,7 +79,8 @@
|
|||
["INSERT INTO [user] (`id`, `status`) VALUES (?, ?), (?, ?), (?, ?)" 42 "hello" 35 "world" 64 "dollars"]))))
|
||||
|
||||
(deftest test-query
|
||||
(let [rs (sql/query (ds) ["select * from fruit order by id"])]
|
||||
(let [rs (sql/query (ds) ["select * from fruit order by id"]
|
||||
(default-options))]
|
||||
(is (= 4 (count rs)))
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
|
|
@ -89,7 +91,8 @@
|
|||
(let [rs (sql/find-by-keys (ds) :fruit {:appearance "neon-green"})]
|
||||
(is (vector? rs))
|
||||
(is (= [] rs)))
|
||||
(let [rs (sql/find-by-keys (ds) :fruit {:appearance "yellow"})]
|
||||
(let [rs (sql/find-by-keys (ds) :fruit {:appearance "yellow"}
|
||||
(default-options))]
|
||||
(is (= 1 (count rs)))
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
|
|
@ -97,14 +100,14 @@
|
|||
|
||||
(deftest test-get-by-id
|
||||
(is (nil? (sql/get-by-id (ds) :fruit -1)))
|
||||
(let [row (sql/get-by-id (ds) :fruit 3)]
|
||||
(let [row (sql/get-by-id (ds) :fruit 3 (default-options))]
|
||||
(is (map? row))
|
||||
(is (= "Peach" ((column :FRUIT/NAME) row))))
|
||||
(let [row (sql/get-by-id (ds) :fruit "juicy" :appearance {})]
|
||||
(let [row (sql/get-by-id (ds) :fruit "juicy" :appearance (default-options))]
|
||||
(is (map? row))
|
||||
(is (= 4 ((column :FRUIT/ID) row)))
|
||||
(is (= "Orange" ((column :FRUIT/NAME) row))))
|
||||
(let [row (sql/get-by-id (ds) :fruit "Banana" :FRUIT/NAME {})]
|
||||
(let [row (sql/get-by-id (ds) :fruit "Banana" :FRUIT/NAME (default-options))]
|
||||
(is (map? row))
|
||||
(is (= 2 ((column :FRUIT/ID) row)))))
|
||||
|
||||
|
|
@ -113,7 +116,7 @@
|
|||
(is (= {:next.jdbc/update-count 1}
|
||||
(sql/update! (ds) :fruit {:appearance "brown"} {:id 2})))
|
||||
(is (= "brown" ((column :FRUIT/APPEARANCE)
|
||||
(sql/get-by-id (ds) :fruit 2))))
|
||||
(sql/get-by-id (ds) :fruit 2 (default-options)))))
|
||||
(finally
|
||||
(sql/update! (ds) :fruit {:appearance "yellow"} {:id 2})))
|
||||
(try
|
||||
|
|
@ -121,21 +124,21 @@
|
|||
(sql/update! (ds) :fruit {:appearance "green"}
|
||||
["name = ?" "Banana"])))
|
||||
(is (= "green" ((column :FRUIT/APPEARANCE)
|
||||
(sql/get-by-id (ds) :fruit 2))))
|
||||
(sql/get-by-id (ds) :fruit 2 (default-options)))))
|
||||
(finally
|
||||
(sql/update! (ds) :fruit {:appearance "yellow"} {:id 2}))))
|
||||
|
||||
(deftest test-insert-delete
|
||||
(let [new-key (cond (derby?) :1
|
||||
(mssql?) :GENERATED_KEYS
|
||||
(mysql?) :GENERATED_KEY
|
||||
(postgres?) :fruit/id
|
||||
(sqlite?) (keyword "last_insert_rowid()")
|
||||
:else :FRUIT/ID)]
|
||||
(testing "single insert/delete"
|
||||
(is (= (if (derby?) 5M 5)
|
||||
(new-key (sql/insert! (ds) :fruit
|
||||
{:name "Kiwi" :appearance "green & fuzzy"
|
||||
:cost 100 :grade 99.9}))))
|
||||
(is (== 5 (new-key (sql/insert! (ds) :fruit
|
||||
{:name "Kiwi" :appearance "green & fuzzy"
|
||||
:cost 100 :grade 99.9}))))
|
||||
(is (= 5 (count (sql/query (ds) ["select * from fruit"]))))
|
||||
(is (= {:next.jdbc/update-count 1}
|
||||
(sql/delete! (ds) :fruit {:id 5})))
|
||||
|
|
@ -143,6 +146,8 @@
|
|||
(testing "multiple insert/delete"
|
||||
(is (= (cond (derby?)
|
||||
[nil] ; WTF Apache Derby?
|
||||
(mssql?)
|
||||
[8M]
|
||||
(sqlite?)
|
||||
[8]
|
||||
:else
|
||||
|
|
@ -163,6 +168,8 @@
|
|||
(testing "multiple insert/delete with sequential cols/rows" ; per #43
|
||||
(is (= (cond (derby?)
|
||||
[nil] ; WTF Apache Derby?
|
||||
(mssql?)
|
||||
[11M]
|
||||
(sqlite?)
|
||||
[11]
|
||||
:else
|
||||
|
|
|
|||
|
|
@ -30,14 +30,22 @@
|
|||
{:dbtype "mysql" :dbname "clojure_test" :useSSL false
|
||||
:user "root" :password (System/getenv "MYSQL_ROOT_PASSWORD")}))
|
||||
|
||||
(def ^:private test-mssql
|
||||
(when (System/getenv "NEXT_JDBC_TEST_MSSQL")
|
||||
{:dbtype "mssql" :dbname "model"
|
||||
:user "sa" :password (System/getenv "MSSQL_SA_PASSWORD")}))
|
||||
|
||||
(def ^:private test-db-specs
|
||||
(cond-> [test-derby test-h2-mem test-h2 test-hsql test-sqlite test-postgres]
|
||||
test-mysql (conj test-mysql)))
|
||||
test-mysql (conj test-mysql)
|
||||
test-mssql (conj test-mssql)))
|
||||
|
||||
(def ^:private test-db-spec (atom nil))
|
||||
|
||||
(defn derby? [] (= "derby" (:dbtype @test-db-spec)))
|
||||
|
||||
(defn mssql? [] (= "mssql" (:dbtype @test-db-spec)))
|
||||
|
||||
(defn mysql? [] (= "mysql" (:dbtype @test-db-spec)))
|
||||
|
||||
(defn postgres? [] (= "embedded-postgres" (:dbtype @test-db-spec)))
|
||||
|
|
@ -47,11 +55,17 @@
|
|||
(defn column [k]
|
||||
(let [n (namespace k)]
|
||||
(keyword (when n (cond (postgres?) (str/lower-case n)
|
||||
(mssql?) (str/lower-case n)
|
||||
(mysql?) (str/lower-case n)
|
||||
:else n))
|
||||
(cond (postgres?) (str/lower-case (name k))
|
||||
:else (name k)))))
|
||||
|
||||
(defn default-options []
|
||||
(if (mssql?) ; so that we get table names back from queries
|
||||
{:result-type :scroll-insensitive :concurrency :read-only}
|
||||
{}))
|
||||
|
||||
(def ^:private test-datasource (atom nil))
|
||||
|
||||
(defn db
|
||||
|
|
@ -86,6 +100,8 @@
|
|||
(postgres?)
|
||||
(str "GENERATED ALWAYS AS IDENTITY"
|
||||
" PRIMARY KEY")
|
||||
(mssql?)
|
||||
"IDENTITY PRIMARY KEY"
|
||||
(sqlite?)
|
||||
"PRIMARY KEY AUTOINCREMENT"
|
||||
:else
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
[next.jdbc :as jdbc]
|
||||
[next.jdbc.connection :as c]
|
||||
[next.jdbc.test-fixtures :refer [with-test-db db ds column
|
||||
derby? mysql? postgres?]]
|
||||
default-options
|
||||
derby? mssql? mysql? postgres?]]
|
||||
[next.jdbc.prepare :as prep]
|
||||
[next.jdbc.result-set :as rs]
|
||||
[next.jdbc.specs :as specs])
|
||||
|
|
@ -34,7 +35,8 @@
|
|||
(is (= "Apple" ((column :FRUIT/NAME)
|
||||
(jdbc/execute-one!
|
||||
(ds)
|
||||
["select * from fruit where appearance = ?" "red"])))))
|
||||
["select * from fruit where appearance = ?" "red"]
|
||||
(default-options))))))
|
||||
(testing "execute!"
|
||||
(let [rs (jdbc/execute!
|
||||
(ds)
|
||||
|
|
@ -43,13 +45,14 @@
|
|||
(is (= [] rs)))
|
||||
(let [rs (jdbc/execute!
|
||||
(ds)
|
||||
["select * from fruit where appearance = ?" "red"])]
|
||||
["select * from fruit where appearance = ?" "red"]
|
||||
(default-options))]
|
||||
(is (= 1 (count rs)))
|
||||
(is (= 1 ((column :FRUIT/ID) (first rs)))))
|
||||
(let [rs (jdbc/execute!
|
||||
(ds)
|
||||
["select * from fruit order by id"]
|
||||
{:builder-fn rs/as-maps})]
|
||||
(assoc (default-options) :builder-fn rs/as-maps))]
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
(is (= 4 (count rs)))
|
||||
|
|
@ -58,7 +61,7 @@
|
|||
(let [rs (jdbc/execute!
|
||||
(ds)
|
||||
["select * from fruit order by id"]
|
||||
{:builder-fn rs/as-arrays})]
|
||||
(assoc (default-options) :builder-fn rs/as-arrays))]
|
||||
(is (every? vector? rs))
|
||||
(is (= 5 (count rs)))
|
||||
(is (every? #(= 5 (count %)) rs))
|
||||
|
|
@ -72,10 +75,11 @@
|
|||
(let [rs (jdbc/execute! ; test again, with adapter and lower columns
|
||||
(ds)
|
||||
["select * from fruit order by id"]
|
||||
{:builder-fn (rs/as-arrays-adapter
|
||||
rs/as-lower-arrays
|
||||
(fn [^ResultSet rs _ ^Integer i]
|
||||
(.getObject rs i)))})]
|
||||
(assoc (default-options)
|
||||
:builder-fn (rs/as-arrays-adapter
|
||||
rs/as-lower-arrays
|
||||
(fn [^ResultSet rs _ ^Integer i]
|
||||
(.getObject rs i)))))]
|
||||
(is (every? vector? rs))
|
||||
(is (= 5 (count rs)))
|
||||
(is (every? #(= 5 (count %)) rs))
|
||||
|
|
@ -113,7 +117,8 @@
|
|||
(let [rs (with-open [con (jdbc/get-connection (ds))
|
||||
ps (jdbc/prepare
|
||||
con
|
||||
["select * from fruit order by id"])]
|
||||
["select * from fruit order by id"]
|
||||
(default-options))]
|
||||
(jdbc/execute! ps))]
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
|
|
@ -123,7 +128,8 @@
|
|||
(let [rs (with-open [con (jdbc/get-connection (ds))
|
||||
ps (jdbc/prepare
|
||||
con
|
||||
["select * from fruit where id = ?"])]
|
||||
["select * from fruit where id = ?"]
|
||||
(default-options))]
|
||||
(jdbc/execute! (prep/set-parameters ps [4]) nil {}))]
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
|
|
@ -136,15 +142,19 @@
|
|||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
(is (= 4 (count rs)))
|
||||
(is (= 1 ((column :FRUIT/ID) (first rs))))
|
||||
(is (= 4 ((column :FRUIT/ID) (last rs)))))
|
||||
;; SQL Server only returns table name if result-type/concurrency
|
||||
;; provided, which we can only for a PreparedStatement
|
||||
(is (= 1 ((if (mssql?) :ID (column :FRUIT/ID)) (first rs))))
|
||||
(is (= 4 ((if (mssql?) :ID (column :FRUIT/ID)) (last rs)))))
|
||||
(let [rs (with-open [con (jdbc/get-connection (ds))]
|
||||
(jdbc/execute! (.createStatement con)
|
||||
["select * from fruit where id = 4"]))]
|
||||
(is (every? map? rs))
|
||||
(is (every? meta rs))
|
||||
(is (= 1 (count rs)))
|
||||
(is (= 4 ((column :FRUIT/ID) (first rs))))))
|
||||
;; SQL Server only returns table name if result-type/concurrency
|
||||
;; provided, which we can only for a PreparedStatement
|
||||
(is (= 4 ((if (mssql?) :ID (column :FRUIT/ID)) (first rs))))))
|
||||
(testing "transact"
|
||||
(is (= [{:next.jdbc/update-count 1}]
|
||||
(jdbc/transact (ds)
|
||||
|
|
@ -210,10 +220,14 @@ VALUES ('Pear', 'green', 49, 47)
|
|||
(let [[url etc] (#'c/spec->url+etc (db))
|
||||
ds (jdbc/get-datasource (assoc etc :jdbcUrl url))]
|
||||
(cond (derby?) (is (= {:create true} etc))
|
||||
(mssql?) (is (= #{:user :password} (set (keys etc))))
|
||||
(mysql?) (is (= #{:user :password :useSSL} (set (keys etc))))
|
||||
:else (is (= {} etc)))
|
||||
(is (instance? javax.sql.DataSource ds))
|
||||
(is (str/index-of (pr-str ds) (str "jdbc:" (:dbtype (db)))))
|
||||
(is (str/index-of (pr-str ds) (str "jdbc:"
|
||||
(if (mssql?)
|
||||
"sqlserver" ; mssql is the alias
|
||||
(:dbtype (db))))))
|
||||
;; checks get-datasource on a DataSource is identity
|
||||
(is (identical? ds (jdbc/get-datasource ds)))
|
||||
(with-open [con (jdbc/get-connection ds {})]
|
||||
|
|
@ -227,12 +241,15 @@ VALUES ('Pear', 'green', 49, 47)
|
|||
;; this may succeed or not, depending on how the driver handles things
|
||||
;; most drivers will error because the ResultSet was closed before pr-str
|
||||
;; is invoked (which will attempt to print each row)
|
||||
(let [s (pr-str (into [] (take 3) (jdbc/plan (ds) ["select * from fruit"])))]
|
||||
(let [s (pr-str (into [] (take 3) (jdbc/plan (ds) ["select * from fruit"]
|
||||
(default-options))))]
|
||||
(is (or (re-find #"missing `map` or `reduce`" s)
|
||||
(re-find #"(?i)^\[#:fruit\{.*:id.*\}\]$" s))))
|
||||
(is (every? #(re-find #"(?i)^#:fruit\{.*:id.*\}$" %)
|
||||
(into [] (map str) (jdbc/plan (ds) ["select * from fruit"]))))
|
||||
(into [] (map str) (jdbc/plan (ds) ["select * from fruit"]
|
||||
(default-options)))))
|
||||
(is (every? #(re-find #"(?i)^#:fruit\{.*:id.*\}$" %)
|
||||
(into [] (map pr-str) (jdbc/plan (ds) ["select * from fruit"]))))
|
||||
(into [] (map pr-str) (jdbc/plan (ds) ["select * from fruit"]
|
||||
(default-options)))))
|
||||
(is (thrown? IllegalArgumentException
|
||||
(doall (take 3 (jdbc/plan (ds) ["select * from fruit"]))))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue