Addresses #293 start work on DDL support
This commit is contained in:
parent
e157aec976
commit
83d4ccba38
4 changed files with 83 additions and 7 deletions
|
|
@ -11,6 +11,26 @@ a space (e.g., `:left-join` is formatted as `LEFT JOIN`).
|
||||||
Except as noted, these clauses apply to all the SQL
|
Except as noted, these clauses apply to all the SQL
|
||||||
dialects that HoneySQL supports.
|
dialects that HoneySQL supports.
|
||||||
|
|
||||||
|
## alter-table
|
||||||
|
|
||||||
|
## create-table
|
||||||
|
|
||||||
|
## create-view
|
||||||
|
|
||||||
|
## drop-table
|
||||||
|
|
||||||
|
`:drop-table` can accept a single table name or a sequence of
|
||||||
|
table names. If a sequence is provided and the first element
|
||||||
|
is `:if-exists` (or the symbol `if-exists`) then that conditional
|
||||||
|
clause is added before the table names:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format '{drop-table (if-exists foo bar)})
|
||||||
|
["DROP TABLE IF EXISTS foo, bar"]
|
||||||
|
user=> (sql/format {:drop-table [:foo :bar]})
|
||||||
|
["DROP TABLE foo, bar"]
|
||||||
|
```
|
||||||
|
|
||||||
## nest
|
## nest
|
||||||
|
|
||||||
This is pseudo-syntax that lets you wrap a substatement
|
This is pseudo-syntax that lets you wrap a substatement
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,10 @@
|
||||||
(declare clause-format)
|
(declare clause-format)
|
||||||
(def ^:private default-clause-order
|
(def ^:private default-clause-order
|
||||||
"The (default) order for known clauses. Can have items added and removed."
|
"The (default) order for known clauses. Can have items added and removed."
|
||||||
[:nest :with :with-recursive :intersect :union :union-all :except :except-all
|
[;; DDL comes first (these don't really have a precedence):
|
||||||
|
:alter-table :create-table :with-columns :create-view :drop-table
|
||||||
|
;; then SQL clauses in priority order:
|
||||||
|
:nest :with :with-recursive :intersect :union :union-all :except :except-all
|
||||||
:select :select-distinct :insert-into :update :delete :delete-from :truncate
|
:select :select-distinct :insert-into :update :delete :delete-from :truncate
|
||||||
:columns :set :from :using
|
:columns :set :from :using
|
||||||
:join :left-join :right-join :inner-join :outer-join :full-join
|
:join :left-join :right-join :inner-join :outer-join :full-join
|
||||||
|
|
@ -139,7 +142,12 @@
|
||||||
(defn- namespace-_ [x] (some-> (namespace x) (str/replace "-" "_")))
|
(defn- namespace-_ [x] (some-> (namespace x) (str/replace "-" "_")))
|
||||||
(defn- name-_ [x] (str/replace (name x) "-" "_"))
|
(defn- name-_ [x] (str/replace (name x) "-" "_"))
|
||||||
|
|
||||||
(defn- format-entity [x & [{:keys [aliased drop-ns]}]]
|
(defn format-entity
|
||||||
|
"Given a simple SQL entity (a keyword or symbol -- or string),
|
||||||
|
return the equivalent SQL fragment (as a string -- no parameters).
|
||||||
|
|
||||||
|
Handles quoting, splitting at / or ., replacing - with _ etc."
|
||||||
|
[x & [{:keys [aliased drop-ns]}]]
|
||||||
(let [nn (if (or *quoted* (string? x)) name name-_)
|
(let [nn (if (or *quoted* (string? x)) name name-_)
|
||||||
q (if (or *quoted* (string? x)) (:quote *dialect*) identity)
|
q (if (or *quoted* (string? x)) (:quote *dialect*) identity)
|
||||||
[t c] (if-let [n (when-not (or drop-ns (string? x))
|
[t c] (if-let [n (when-not (or drop-ns (string? x))
|
||||||
|
|
@ -458,6 +466,27 @@
|
||||||
[(str (sql-kw k) " " e " = EXCLUDED." e)])
|
[(str (sql-kw k) " " e " = EXCLUDED." e)])
|
||||||
(format-set-exprs k x)))
|
(format-set-exprs k x)))
|
||||||
|
|
||||||
|
(defn- format-alter-table [k [x]] ["ALTER TABLE"])
|
||||||
|
|
||||||
|
(defn- format-create-table [k table]
|
||||||
|
(let [[table if-not-exists] (if (sequential? table) table [table])]
|
||||||
|
[(str (sql-kw k) " "
|
||||||
|
(when if-not-exists (str (sql-kw :if-not-exists) " "))
|
||||||
|
(format-entity table))]))
|
||||||
|
|
||||||
|
(defn- format-create-view [k x]
|
||||||
|
[(str (sql-kw k) " " (format-entity x) " AS")])
|
||||||
|
|
||||||
|
(defn- format-drop-table
|
||||||
|
[k params]
|
||||||
|
(let [tables (if (sequential? params) params [params])
|
||||||
|
[if-exists & tables] (if (#{:if-exists 'if-exists} (first tables)) tables (cons nil tables))]
|
||||||
|
[(str (sql-kw k) " "
|
||||||
|
(when if-exists (str (sql-kw :if-exists) " "))
|
||||||
|
(str/join ", " (map #'format-entity tables)))]))
|
||||||
|
|
||||||
|
(defn- format-table-columns [k [x]] ["()"])
|
||||||
|
|
||||||
(def ^:private base-clause-order
|
(def ^:private base-clause-order
|
||||||
"The (base) order for known clauses. Can have items added and removed.
|
"The (base) order for known clauses. Can have items added and removed.
|
||||||
|
|
||||||
|
|
@ -473,7 +502,12 @@
|
||||||
(def ^:private clause-format
|
(def ^:private clause-format
|
||||||
"The (default) behavior for each known clause. Can also have items added
|
"The (default) behavior for each known clause. Can also have items added
|
||||||
and removed."
|
and removed."
|
||||||
(atom {:nest (fn [_ x] (format-expr x))
|
(atom {:alter-table #'format-alter-table
|
||||||
|
:create-table #'format-create-table
|
||||||
|
:with-columns #'format-table-columns
|
||||||
|
:create-view #'format-create-view
|
||||||
|
:drop-table #'format-drop-table
|
||||||
|
:nest (fn [_ x] (format-expr x))
|
||||||
:with #'format-with
|
:with #'format-with
|
||||||
:with-recursive #'format-with
|
:with-recursive #'format-with
|
||||||
:intersect #'format-on-set-op
|
:intersect #'format-on-set-op
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@
|
||||||
(assoc data k arg)
|
(assoc data k arg)
|
||||||
(assoc {} k data)))
|
(assoc {} k data)))
|
||||||
|
|
||||||
|
(defn alter-table [& args] (generic :nest args))
|
||||||
|
(defn create-table [& args] (generic :nest args))
|
||||||
|
(defn with-columns [& args] (generic :nest args))
|
||||||
|
(defn create-view [& args] (generic :nest args))
|
||||||
|
(defn drop-table [& args] (generic :nest args))
|
||||||
(defn nest [& args] (generic :nest args))
|
(defn nest [& args] (generic :nest args))
|
||||||
(defn with [& args] (generic :with args))
|
(defn with [& args] (generic :with args))
|
||||||
(defn with-recursive [& args] (generic :with-recursive args))
|
(defn with-recursive [& args] (generic :with-recursive args))
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
:cljs [cljs.test :refer-macros [deftest is testing]])
|
:cljs [cljs.test :refer-macros [deftest is testing]])
|
||||||
[honey.sql :as sql]
|
[honey.sql :as sql]
|
||||||
[honey.sql.helpers
|
[honey.sql.helpers
|
||||||
:refer [columns cross-join do-update-set from full-join
|
:refer [columns create-view
|
||||||
|
cross-join do-update-set from full-join
|
||||||
group-by having insert-into
|
group-by having insert-into
|
||||||
join left-join limit offset on-conflict order-by
|
join left-join limit offset on-conflict order-by
|
||||||
over partition-by
|
over partition-by
|
||||||
|
|
@ -278,7 +279,7 @@
|
||||||
" AND (location NOT LIKE '/1/%')")]
|
" AND (location NOT LIKE '/1/%')")]
|
||||||
(stack-overflow-282 2))))
|
(stack-overflow-282 2))))
|
||||||
|
|
||||||
(deftest issue-293
|
(deftest issue-293-sql
|
||||||
;; these tests are based on the README at https://github.com/nilenso/honeysql-postgres
|
;; these tests are based on the README at https://github.com/nilenso/honeysql-postgres
|
||||||
(is (= (-> (insert-into :distributors)
|
(is (= (-> (insert-into :distributors)
|
||||||
(values [{:did 5 :dname "Gizmo Transglobal"}
|
(values [{:did 5 :dname "Gizmo Transglobal"}
|
||||||
|
|
@ -328,8 +329,24 @@
|
||||||
[(str "SELECT id,"
|
[(str "SELECT id,"
|
||||||
" AVG(salary) OVER () AS Average,"
|
" AVG(salary) OVER () AS Average,"
|
||||||
" MAX(salary) OVER () AS MaxSalary"
|
" MAX(salary) OVER () AS MaxSalary"
|
||||||
" FROM employee")]))
|
" FROM employee")])))
|
||||||
)
|
|
||||||
|
(deftest issue-293-ddl
|
||||||
|
(is (= (sql/format {:create-view :metro :select [:*] :from [:cities] :where [:= :metroflag "y"]})
|
||||||
|
["CREATE VIEW metro AS SELECT * FROM cities WHERE metroflag = ?" "y"]))
|
||||||
|
(is (= (sql/format {:create-table :films
|
||||||
|
:with-columns []})
|
||||||
|
["CREATE TABLE films ()"]))
|
||||||
|
(is (= (sql/format {:drop-table :foo})
|
||||||
|
["DROP TABLE foo"]))
|
||||||
|
(is (= (sql/format {:drop-table [:if-exists :foo]})
|
||||||
|
["DROP TABLE IF EXISTS foo"]))
|
||||||
|
(is (= (sql/format '{drop-table (if-exists foo)})
|
||||||
|
["DROP TABLE IF EXISTS foo"]))
|
||||||
|
(is (= (sql/format {:drop-table [:foo :bar]})
|
||||||
|
["DROP TABLE foo, bar"]))
|
||||||
|
(is (= (sql/format {:drop-table [:if-exists :foo :bar]})
|
||||||
|
["DROP TABLE IF EXISTS foo, bar"])))
|
||||||
|
|
||||||
(deftest issue-293-insert-into-data
|
(deftest issue-293-insert-into-data
|
||||||
;; insert into as (and other tests) based on :insert-into
|
;; insert into as (and other tests) based on :insert-into
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue