2020-01-01 21:13:41 +00:00
|
|
|
;; copyright (c) 2019-2020 Sean Corfield, all rights reserved
|
2019-04-18 21:15:15 +00:00
|
|
|
|
|
|
|
|
(ns next.jdbc.sql-test
|
2019-12-12 00:42:28 +00:00
|
|
|
"Tests for the syntactic sugar SQL functions."
|
2019-04-20 06:25:03 +00:00
|
|
|
(:require [clojure.test :refer [deftest is testing use-fixtures]]
|
2019-05-22 04:45:05 +00:00
|
|
|
[next.jdbc.specs :as specs]
|
2019-04-20 06:25:03 +00:00
|
|
|
[next.jdbc.sql :as sql]
|
2019-04-22 00:10:29 +00:00
|
|
|
[next.jdbc.test-fixtures
|
2019-11-16 06:37:42 +00:00
|
|
|
:refer [with-test-db ds column default-options
|
2020-03-16 22:19:21 +00:00
|
|
|
derby? maria? mssql? mysql? postgres? sqlite?]]))
|
2019-04-20 06:25:03 +00:00
|
|
|
|
2019-05-29 16:04:21 +00:00
|
|
|
(set! *warn-on-reflection* true)
|
|
|
|
|
|
2019-04-20 06:25:03 +00:00
|
|
|
(use-fixtures :once with-test-db)
|
2019-04-19 01:31:15 +00:00
|
|
|
|
2019-05-22 04:45:05 +00:00
|
|
|
(specs/instrument)
|
|
|
|
|
|
2019-04-20 06:25:03 +00:00
|
|
|
(deftest test-query
|
2019-11-16 06:37:42 +00:00
|
|
|
(let [rs (sql/query (ds) ["select * from fruit order by id"]
|
|
|
|
|
(default-options))]
|
2019-04-20 06:25:03 +00:00
|
|
|
(is (= 4 (count rs)))
|
|
|
|
|
(is (every? map? rs))
|
|
|
|
|
(is (every? meta rs))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= 1 ((column :FRUIT/ID) (first rs))))
|
|
|
|
|
(is (= 4 ((column :FRUIT/ID) (last rs))))))
|
2019-04-20 06:25:03 +00:00
|
|
|
|
|
|
|
|
(deftest test-find-by-keys
|
2019-11-01 16:34:14 +00:00
|
|
|
(let [rs (sql/find-by-keys (ds) :fruit {:appearance "neon-green"})]
|
|
|
|
|
(is (vector? rs))
|
|
|
|
|
(is (= [] rs)))
|
2019-11-16 06:37:42 +00:00
|
|
|
(let [rs (sql/find-by-keys (ds) :fruit {:appearance "yellow"}
|
|
|
|
|
(default-options))]
|
2019-04-20 06:25:03 +00:00
|
|
|
(is (= 1 (count rs)))
|
|
|
|
|
(is (every? map? rs))
|
|
|
|
|
(is (every? meta rs))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= 2 ((column :FRUIT/ID) (first rs))))))
|
2019-04-20 06:25:03 +00:00
|
|
|
|
|
|
|
|
(deftest test-get-by-id
|
2019-11-01 16:34:14 +00:00
|
|
|
(is (nil? (sql/get-by-id (ds) :fruit -1)))
|
2019-11-16 06:37:42 +00:00
|
|
|
(let [row (sql/get-by-id (ds) :fruit 3 (default-options))]
|
2019-04-20 06:25:03 +00:00
|
|
|
(is (map? row))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= "Peach" ((column :FRUIT/NAME) row))))
|
2019-11-16 06:37:42 +00:00
|
|
|
(let [row (sql/get-by-id (ds) :fruit "juicy" :appearance (default-options))]
|
2019-04-20 06:25:03 +00:00
|
|
|
(is (map? row))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= 4 ((column :FRUIT/ID) row)))
|
|
|
|
|
(is (= "Orange" ((column :FRUIT/NAME) row))))
|
2019-11-16 06:37:42 +00:00
|
|
|
(let [row (sql/get-by-id (ds) :fruit "Banana" :FRUIT/NAME (default-options))]
|
2019-04-20 06:25:03 +00:00
|
|
|
(is (map? row))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= 2 ((column :FRUIT/ID) row)))))
|
2019-04-20 06:25:03 +00:00
|
|
|
|
|
|
|
|
(deftest test-update!
|
|
|
|
|
(try
|
|
|
|
|
(is (= {:next.jdbc/update-count 1}
|
|
|
|
|
(sql/update! (ds) :fruit {:appearance "brown"} {:id 2})))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= "brown" ((column :FRUIT/APPEARANCE)
|
2019-11-16 06:37:42 +00:00
|
|
|
(sql/get-by-id (ds) :fruit 2 (default-options)))))
|
2019-04-20 06:25:03 +00:00
|
|
|
(finally
|
|
|
|
|
(sql/update! (ds) :fruit {:appearance "yellow"} {:id 2})))
|
|
|
|
|
(try
|
|
|
|
|
(is (= {:next.jdbc/update-count 1}
|
|
|
|
|
(sql/update! (ds) :fruit {:appearance "green"}
|
|
|
|
|
["name = ?" "Banana"])))
|
2019-11-15 23:38:51 +00:00
|
|
|
(is (= "green" ((column :FRUIT/APPEARANCE)
|
2019-11-16 06:37:42 +00:00
|
|
|
(sql/get-by-id (ds) :fruit 2 (default-options)))))
|
2019-04-20 06:25:03 +00:00
|
|
|
(finally
|
|
|
|
|
(sql/update! (ds) :fruit {:appearance "yellow"} {:id 2}))))
|
|
|
|
|
|
|
|
|
|
(deftest test-insert-delete
|
2019-07-25 00:32:58 +00:00
|
|
|
(let [new-key (cond (derby?) :1
|
2019-11-16 06:37:42 +00:00
|
|
|
(mssql?) :GENERATED_KEYS
|
2020-03-16 22:19:21 +00:00
|
|
|
(maria?) :insert_id
|
2019-11-15 23:38:51 +00:00
|
|
|
(mysql?) :GENERATED_KEY
|
2019-07-25 00:32:58 +00:00
|
|
|
(postgres?) :fruit/id
|
|
|
|
|
(sqlite?) (keyword "last_insert_rowid()")
|
|
|
|
|
:else :FRUIT/ID)]
|
|
|
|
|
(testing "single insert/delete"
|
2019-11-16 06:37:42 +00:00
|
|
|
(is (== 5 (new-key (sql/insert! (ds) :fruit
|
|
|
|
|
{:name "Kiwi" :appearance "green & fuzzy"
|
|
|
|
|
:cost 100 :grade 99.9}))))
|
2019-07-25 00:32:58 +00:00
|
|
|
(is (= 5 (count (sql/query (ds) ["select * from fruit"]))))
|
|
|
|
|
(is (= {:next.jdbc/update-count 1}
|
|
|
|
|
(sql/delete! (ds) :fruit {:id 5})))
|
|
|
|
|
(is (= 4 (count (sql/query (ds) ["select * from fruit"])))))
|
|
|
|
|
(testing "multiple insert/delete"
|
|
|
|
|
(is (= (cond (derby?)
|
|
|
|
|
[nil] ; WTF Apache Derby?
|
2019-11-16 06:37:42 +00:00
|
|
|
(mssql?)
|
|
|
|
|
[8M]
|
2019-07-25 00:32:58 +00:00
|
|
|
(sqlite?)
|
|
|
|
|
[8]
|
|
|
|
|
:else
|
|
|
|
|
[6 7 8])
|
|
|
|
|
(mapv new-key
|
|
|
|
|
(sql/insert-multi! (ds) :fruit
|
|
|
|
|
[:name :appearance :cost :grade]
|
|
|
|
|
[["Kiwi" "green & fuzzy" 100 99.9]
|
|
|
|
|
["Grape" "black" 10 50]
|
|
|
|
|
["Lemon" "yellow" 20 9.9]]))))
|
|
|
|
|
(is (= 7 (count (sql/query (ds) ["select * from fruit"]))))
|
|
|
|
|
(is (= {:next.jdbc/update-count 1}
|
|
|
|
|
(sql/delete! (ds) :fruit {:id 6})))
|
|
|
|
|
(is (= 6 (count (sql/query (ds) ["select * from fruit"]))))
|
|
|
|
|
(is (= {:next.jdbc/update-count 2}
|
|
|
|
|
(sql/delete! (ds) :fruit ["id > ?" 4])))
|
|
|
|
|
(is (= 4 (count (sql/query (ds) ["select * from fruit"])))))
|
|
|
|
|
(testing "multiple insert/delete with sequential cols/rows" ; per #43
|
|
|
|
|
(is (= (cond (derby?)
|
|
|
|
|
[nil] ; WTF Apache Derby?
|
2019-11-16 06:37:42 +00:00
|
|
|
(mssql?)
|
|
|
|
|
[11M]
|
2019-07-25 00:32:58 +00:00
|
|
|
(sqlite?)
|
|
|
|
|
[11]
|
|
|
|
|
:else
|
|
|
|
|
[9 10 11])
|
|
|
|
|
(mapv new-key
|
|
|
|
|
(sql/insert-multi! (ds) :fruit
|
|
|
|
|
'(:name :appearance :cost :grade)
|
|
|
|
|
'(("Kiwi" "green & fuzzy" 100 99.9)
|
|
|
|
|
("Grape" "black" 10 50)
|
|
|
|
|
("Lemon" "yellow" 20 9.9))))))
|
|
|
|
|
(is (= 7 (count (sql/query (ds) ["select * from fruit"]))))
|
|
|
|
|
(is (= {:next.jdbc/update-count 1}
|
|
|
|
|
(sql/delete! (ds) :fruit {:id 9})))
|
|
|
|
|
(is (= 6 (count (sql/query (ds) ["select * from fruit"]))))
|
|
|
|
|
(is (= {:next.jdbc/update-count 2}
|
|
|
|
|
(sql/delete! (ds) :fruit ["id > ?" 4])))
|
|
|
|
|
(is (= 4 (count (sql/query (ds) ["select * from fruit"])))))
|
|
|
|
|
(testing "empty insert-multi!" ; per #44
|
|
|
|
|
(is (= [] (sql/insert-multi! (ds) :fruit
|
|
|
|
|
[:name :appearance :cost :grade]
|
|
|
|
|
[]))))))
|
2019-07-03 01:50:25 +00:00
|
|
|
|
|
|
|
|
(deftest no-empty-example-maps
|
|
|
|
|
(is (thrown? clojure.lang.ExceptionInfo
|
|
|
|
|
(sql/find-by-keys (ds) :fruit {})))
|
|
|
|
|
(is (thrown? clojure.lang.ExceptionInfo
|
|
|
|
|
(sql/update! (ds) :fruit {} {})))
|
|
|
|
|
(is (thrown? clojure.lang.ExceptionInfo
|
|
|
|
|
(sql/delete! (ds) :fruit {}))))
|
2019-07-11 19:11:32 +00:00
|
|
|
|
2019-07-11 19:52:36 +00:00
|
|
|
(deftest no-empty-columns
|
|
|
|
|
(is (thrown? clojure.lang.ExceptionInfo
|
|
|
|
|
(sql/insert-multi! (ds) :fruit [] [[] [] []]))))
|
|
|
|
|
|
2019-07-11 19:11:32 +00:00
|
|
|
(deftest no-empty-order-by
|
|
|
|
|
(is (thrown? clojure.lang.ExceptionInfo
|
|
|
|
|
(sql/find-by-keys (ds) :fruit
|
|
|
|
|
{:name "Apple"}
|
|
|
|
|
{:order-by []}))))
|
2019-09-05 01:43:30 +00:00
|
|
|
|
|
|
|
|
(deftest array-in
|
|
|
|
|
(when (postgres?)
|
|
|
|
|
(let [data (sql/find-by-keys (ds) :fruit ["id = any(?)" (int-array [1 2 3 4])])]
|
|
|
|
|
(is (= 4 (count data))))))
|