Addresses #315 by expanding IN to handle nil

This commit is contained in:
Sean Corfield 2021-04-10 10:57:13 -07:00
parent f231151243
commit 8a1e2cca71
3 changed files with 71 additions and 8 deletions

View file

@ -1,5 +1,8 @@
# Changes # Changes
* 2.0.next in progress
* Tentative fix for #315 by expanding `:in` handling to deal with `nil` values.
* 2.0.0-beta1 (for testing; 2021-04-09) * 2.0.0-beta1 (for testing; 2021-04-09)
* Since Alpha 3, more documentation has been written and existing documentation clarified (addressing #300, #309, #313, #314). * Since Alpha 3, more documentation has been written and existing documentation clarified (addressing #300, #309, #313, #314).
* Fix #319 by ensuring `register-clause!` is idempotent. * Fix #319 by ensuring `register-clause!` is idempotent.

View file

@ -921,17 +921,34 @@
x)) x))
(defn- format-in [in [x y]] (defn- format-in [in [x y]]
(let [[sql-x & params-x] (format-expr x {:nested true}) (let [nil-check (and (sequential? y) (not (ident? (first y))))
[sql-y & params-y] (format-expr y {:nested true}) y' (if nil-check (remove nil? y) y)
[sql-x & params-x] (format-expr x {:nested true})
[sql-y & params-y] (format-expr y' {:nested true})
values (unwrap (first params-y) {})] values (unwrap (first params-y) {})]
(if (and (= "?" sql-y) (= 1 (count params-y)) (coll? values)) (if (and (= "?" sql-y) (= 1 (count params-y)) (coll? values))
(let [sql (str "(" (str/join ", " (repeat (count values) "?")) ")")] (let [values' (remove nil? values)
(-> [(str sql-x " " (sql-kw in) " " sql)] sql (str "(" (str/join ", " (repeat (count values') "?")) ")")
in (str sql-x " " (sql-kw in) " " sql)]
(-> [(if (not= (count values) (count values'))
(if (zero? (count values'))
(str sql-x " IS NULL")
(str "(" in " OR " sql-x " IS NULL)"))
(if (zero? (count values))
"FALSE"
in))]
(into params-x) (into params-x)
(into values))) (into values')))
(-> [(str sql-x " " (sql-kw in) " " sql-y)] (let [in (str sql-x " " (sql-kw in) " " sql-y)]
(-> [(if (and nil-check (not= (count y) (count y')))
(if (zero? (count y'))
(str sql-x " IS NULL")
(str "(" in " OR " sql-x " IS NULL)"))
(if (zero? (count y))
"FALSE"
in))]
(into params-x) (into params-x)
(into params-y))))) (into params-y))))))
(defn- function-0 [k xs] (defn- function-0 [k xs]
[(str (sql-kw k) [(str (sql-kw k)

View file

@ -274,6 +274,39 @@
:from [:customers] :from [:customers]
:where [:in :id values]}))) :where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE id IN (?)" 1] (is (= ["SELECT * FROM customers WHERE id IN (?)" 1]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id :?ids]}
{:params {:ids values}})))))
(testing (str "with just a nil value from a " (name cname))
(let [values (conj coll nil)]
(is (= ["SELECT * FROM customers WHERE id IS NULL"]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE id IS NULL"]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id :?ids]}
{:params {:ids values}})))))
(testing (str "with nil values from a " (name cname))
(let [values (conj coll 1 nil)]
(is (= ["SELECT * FROM customers WHERE (id IN (?) OR id IS NULL)" 1]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE (id IN (?) OR id IS NULL)" 1]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id :?ids]}
{:params {:ids values}})))))
(testing (str "with no values from a " (name cname))
(let [values coll]
(is (= ["SELECT * FROM customers WHERE FALSE"]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE FALSE"]
(sql/format {:select [:*] (sql/format {:select [:*]
:from [:customers] :from [:customers]
:where [:in :id :?ids]} :where [:in :id :?ids]}
@ -285,6 +318,16 @@
:from [:customers] :from [:customers]
:where [:in :id values]}))) :where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE id IN (?, ?)" 1 2] (is (= ["SELECT * FROM customers WHERE id IN (?, ?)" 1 2]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id :?ids]}
{:params {:ids values}}))))
(let [values [1 nil 2]]
(is (= ["SELECT * FROM customers WHERE (id IN (?, ?) OR id IS NULL)" 1 2]
(sql/format {:select [:*]
:from [:customers]
:where [:in :id values]})))
(is (= ["SELECT * FROM customers WHERE (id IN (?, ?) OR id IS NULL)" 1 2]
(sql/format {:select [:*] (sql/format {:select [:*]
:from [:customers] :from [:customers]
:where [:in :id :?ids]} :where [:in :id :?ids]}