:insert-into should support abitrary functions for table fixes #402

This commit is contained in:
Sean Corfield 2022-04-23 15:12:55 -07:00
parent 13a8aa11b2
commit 124fac6f28
2 changed files with 79 additions and 57 deletions

View file

@ -299,13 +299,21 @@
(when (map? s)
(throw (ex-info "selectable cannot be statement!"
{:selectable s})))
(cond-> (format-entity s)
(let [[sql & params] (format-expr s)]
(into [(cond-> sql
pair?
(str (if (and (contains? *dialect* :as) (not (:as *dialect*))) " " " AS ")
(format-entity (second x) {:aliased true}))))
(format-entity (second x) {:aliased true})))]
params)))
:else
(format-entity x)))
[(format-entity x)]))
(comment
(format-expr :a)
(format-expr [:raw "My String"])
(format-entity-alias [[:raw "My String"]])
)
(declare format-selects-common)
@ -378,14 +386,16 @@
:else
(format-expr x)))
;; primary clauses
(defn- format-on-set-op [k xs]
(let [[sqls params]
(defn- reduce-sql [xs]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map #(format-dsl %) xs))]
xs))
;; primary clauses
(defn- format-on-set-op [k xs]
(let [[sqls params] (reduce-sql (map #(format-dsl %) xs))]
(into [(str/join (str " " (sql-kw k) " ") sqls)] params)))
(defn format-expr-list
@ -406,10 +416,7 @@
(throw (ex-info (str "format-expr-list expects a sequence of expressions, found: "
(type exprs))
{:exprs exprs})))
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map #(format-expr % opts) exprs)))
(reduce-sql (map #(format-expr % opts) exprs)))
(comment
(format-expr-list :?tags)
@ -421,11 +428,7 @@
(defn- format-selects-common [prefix as xs]
(if (sequential? xs)
(let [[sqls params]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map #(format-selectable-dsl % {:as as}) xs))]
(let [[sqls params] (reduce-sql (map #(format-selectable-dsl % {:as as}) xs))]
(when-not (= :none *checking*)
(when (empty? xs)
(throw (ex-info (str prefix " empty column list is illegal")
@ -502,10 +505,7 @@
;; TODO: a sequence of pairs -- X AS expr -- where X is either [entity expr]
;; or just entity, as far as I can tell...
(let [[sqls params]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map (fn [[x expr]]
(reduce-sql (map (fn [[x expr]]
(let [[sql & params] (format-with-part x)
[sql' & params'] (format-dsl expr)]
;; according to docs, CTE should _always_ be wrapped:
@ -526,24 +526,38 @@
(if (and (sequential? table) (sequential? (second table)))
table
[table])
[sql & params] (format-dsl statement)]
(into [(str (sql-kw k) " " (format-entity-alias table)
[sql & params] (format-dsl statement)
[t-sql & t-params] (format-entity-alias table)
[c-sqls c-params] (reduce-sql (map #'format-entity-alias cols))]
(-> [(str (sql-kw k) " " t-sql
" "
(when (seq cols)
(str "("
(str/join ", " (map #'format-entity-alias cols))
(str/join ", " c-sqls)
") "))
sql)]
params))
(into t-params)
(into c-params)
(into params)))
(sequential? (second table))
(let [[table cols] table]
[(str (sql-kw k) " " (format-entity-alias table)
(let [[table cols] table
[t-sql & t-params] (format-entity-alias table)
[c-sqls c-params] (reduce-sql (map #'format-entity-alias cols))]
(-> [(str (sql-kw k) " " t-sql
" ("
(str/join ", " (map #'format-entity-alias cols))
")")])
(str/join ", " c-sqls)
")")]
(into t-params)
(into c-params)))
:else
[(str (sql-kw k) " " (format-entity-alias table))])
[(str (sql-kw k) " " (format-entity-alias table))]))
(let [[sql & params] (format-entity-alias table)]
(into [(str (sql-kw k) " " sql)] params)))
(let [[sql & params] (format-entity-alias table)]
(into [(str (sql-kw k) " " sql)] params))))
(comment
(format-insert :insert-into [[[:raw ":foo"]] {:select :bar}])
)
(defn- format-join [k clauses]
(let [[sqls params]
@ -555,12 +569,14 @@
[j])
sqls (conj sqls sql-j)]
(if (and (sequential? e) (= :using (first e)))
(let [[u-sqls u-params]
(reduce-sql (map #'format-entity-alias (rest e)))]
[(conj sqls
"USING"
(str "("
(str/join ", " (map #'format-entity-alias (rest e)))
(str/join ", " u-sqls)
")"))
(into params params-j)]
(-> params (into params-j) (into u-params))])
(let [[sql & params'] (when e (format-expr e))]
[(cond-> sqls e (conj "ON" sql))
(-> params
@ -1326,11 +1342,7 @@
(remove nil? expr)
expr)
[sqls params]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql')
(if params' (into params params') params)])
[[] []]
(map #(format-expr % {:nested true})
(reduce-sql (map #(format-expr % {:nested true})
(rest x)))]
(into [(cond-> (str/join (str " " (sql-kw op) " ") sqls)
nested

View file

@ -172,6 +172,16 @@
(is (or (= res ["INSERT INTO foo (id, bar) VALUES (?, ?), (?, NULL)" 1 "quux" 2])
(= res ["INSERT INTO foo (bar, id) VALUES (?, ?), (NULL, ?)" "quux" 1 2])))))
(deftest insert-into-functions
;; needs [[:raw ..]] because it's the columns case:
(is (= (format {:insert-into [[[:raw "My-Table Name"]] {:select [:bar] :from [:baz]}]})
["INSERT INTO My-Table Name SELECT bar FROM baz"]))
;; this variant only needs [:raw ..]
(is (= (format {:insert-into [[:raw "My-Table Name"]] :values [{:foo/id 1}]})
["INSERT INTO My-Table Name (id) VALUES (?)" 1]))
(is (= (format {:insert-into [:foo :bar] :values [{:foo/id 1}]})
["INSERT INTO foo AS bar (id) VALUES (?)" 1])))
(deftest exists-test
;; EXISTS should never have been implemented as SQL syntax: it's an operator!
#_(is (= (format {:exists {:select [:a] :from [:foo]}})