Support materialization control in WITH
Adds an optional third value to `with` vectors, which can be the following: * `:materialized` -> SQL is `WITH cte AS MATERIALIZED (...)` * `:not-materialized` -> SQL is `WITH cte AS NOT MATERIALIZED (...)` * omitted or anything else -> SQL is `WITH cte AS (...)` Note that materialization control is not available on WITH RECURSIVE CTEs, so `format-with` was modified to take a third argument that returns the `AS ...` separator, which is constantly `"AS"` for WITH RECURSIVE, and obeys the aforementioned rules for non-recursive CTEs. Resolves #392.
This commit is contained in:
parent
d31600d2c0
commit
204f6fa72a
2 changed files with 26 additions and 11 deletions
|
|
@ -521,15 +521,17 @@
|
||||||
(into [(str (format-entity (first x)) " " sql)] params))
|
(into [(str (format-entity (first x)) " " sql)] params))
|
||||||
[(format-entity x)]))
|
[(format-entity x)]))
|
||||||
|
|
||||||
(defn- format-with [k xs]
|
(defn- format-with [k xs as-fn]
|
||||||
;; TODO: a sequence of pairs -- X AS expr -- where X is either [entity expr]
|
;; TODO: a sequence of pairs -- X AS expr -- where X is either [entity expr]
|
||||||
;; or just entity, as far as I can tell...
|
;; or just entity, as far as I can tell...
|
||||||
(let [[sqls params]
|
(let [[sqls params]
|
||||||
(reduce-sql (map (fn [[x expr]]
|
(reduce-sql
|
||||||
|
(map
|
||||||
|
(fn [[x expr :as with]]
|
||||||
(let [[sql & params] (format-with-part x)
|
(let [[sql & params] (format-with-part x)
|
||||||
[sql' & params'] (format-dsl expr)]
|
[sql' & params'] (format-dsl expr)]
|
||||||
;; according to docs, CTE should _always_ be wrapped:
|
;; according to docs, CTE should _always_ be wrapped:
|
||||||
(cond-> [(str sql " AS " (str "(" sql' ")"))]
|
(cond-> [(str sql " " (as-fn with) " " (str "(" sql' ")"))]
|
||||||
params (into params)
|
params (into params)
|
||||||
params' (into params'))))
|
params' (into params'))))
|
||||||
xs))]
|
xs))]
|
||||||
|
|
@ -989,8 +991,15 @@
|
||||||
:nest (fn [_ x]
|
:nest (fn [_ x]
|
||||||
(let [[sql & params] (format-dsl x {:nested true})]
|
(let [[sql & params] (format-dsl x {:nested true})]
|
||||||
(into [sql] params)))
|
(into [sql] params)))
|
||||||
:with #'format-with
|
:with (let [as-fn
|
||||||
:with-recursive #'format-with
|
(fn [[_ _ materialization]]
|
||||||
|
(condp = materialization
|
||||||
|
:materialized "AS MATERIALIZED"
|
||||||
|
:not-materialized "AS NOT MATERIALIZED"
|
||||||
|
"AS"))]
|
||||||
|
(fn [k xs] (format-with k xs as-fn)))
|
||||||
|
:with-recursive (let [as-fn (constantly "AS")]
|
||||||
|
(fn [k xs] (format-with k xs as-fn)))
|
||||||
:intersect #'format-on-set-op
|
:intersect #'format-on-set-op
|
||||||
:union #'format-on-set-op
|
:union #'format-on-set-op
|
||||||
:union-all #'format-on-set-op
|
:union-all #'format-on-set-op
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,12 @@
|
||||||
(deftest test-cte
|
(deftest test-cte
|
||||||
(is (= (format {:with [[:query {:select [:foo] :from [:bar]}]]})
|
(is (= (format {:with [[:query {:select [:foo] :from [:bar]}]]})
|
||||||
["WITH query AS (SELECT foo FROM bar)"]))
|
["WITH query AS (SELECT foo FROM bar)"]))
|
||||||
|
(is (= (format {:with [[:query {:select [:foo] :from [:bar]} :materialized]]})
|
||||||
|
["WITH query AS MATERIALIZED (SELECT foo FROM bar)"]))
|
||||||
|
(is (= (format {:with [[:query {:select [:foo] :from [:bar]} :not-materialized]]})
|
||||||
|
["WITH query AS NOT MATERIALIZED (SELECT foo FROM bar)"]))
|
||||||
|
(is (= (format {:with [[:query {:select [:foo] :from [:bar]} :unknown]]})
|
||||||
|
["WITH query AS (SELECT foo FROM bar)"]))
|
||||||
(is (= (format {:with [[:query1 {:select [:foo] :from [:bar]}]
|
(is (= (format {:with [[:query1 {:select [:foo] :from [:bar]}]
|
||||||
[:query2 {:select [:bar] :from [:quux]}]]
|
[:query2 {:select [:bar] :from [:quux]}]]
|
||||||
:select [:query1.id :query2.name]
|
:select [:query1.id :query2.name]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue