add general using-* index support

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2025-03-26 10:28:57 -07:00
parent 78f7d5282f
commit b4b2ca7d79
No known key found for this signature in database
4 changed files with 35 additions and 20 deletions

View file

@ -1,6 +1,7 @@
# Changes # Changes
* 2.7.next in progress * 2.7.next in progress
* Support `USING HASH` as well as `USING GIN`.
* Fix [#571](https://github.com/seancorfield/honeysql/issues/571) by allowing `:order-by` to take an empty sequence of columns (and be omitted). * Fix [#571](https://github.com/seancorfield/honeysql/issues/571) by allowing `:order-by` to take an empty sequence of columns (and be omitted).
* Update dev/build deps. * Update dev/build deps.

View file

@ -149,6 +149,14 @@ user=> (sql/format {:create-index [:my-idx [:fruit :using-gin :appearance]]})
["CREATE INDEX my_idx ON fruit USING GIN (appearance)"] ["CREATE INDEX my_idx ON fruit USING GIN (appearance)"]
``` ```
As of 2.7.next, `USING HASH` index creation is also possible using the keyword
`:using-hash` after the table name (or the symbol `using-hash`):
```clojure
user=> (sql/format {:create-index [:my-idx [:fruit :using-hash :appearance]]})
["CREATE INDEX my_idx ON fruit USING HASH (appearance)"]
```
### rename-table ### rename-table
Used with `:alter-table`, Used with `:alter-table`,

View file

@ -370,6 +370,20 @@
(keyword (name s))) (keyword (name s)))
s)) s))
(defn- kw->sym
"Given a keyword, produce a symbol, retaining the namespace
qualifier, if any."
[k]
(if (keyword? k)
#?(:bb (if-let [n (namespace k)]
(symbol n (name k))
(symbol (name k)))
:clj (.sym ^clojure.lang.Keyword k)
:default (if-let [n (namespace k)]
(symbol n (name k))
(symbol (name k))))
k))
(defn- inline-map [x & [open close]] (defn- inline-map [x & [open close]]
(str (or open "{") (str (or open "{")
(join ", " (map (fn [[k v]] (join ", " (map (fn [[k v]]
@ -1418,10 +1432,12 @@
(defn- format-create-index [k clauses] (defn- format-create-index [k clauses]
(let [[index-spec [table & exprs]] clauses (let [[index-spec [table & exprs]] clauses
[pre entity ine & more] (destructure-ddl-item index-spec (str (sql-kw k) " options")) [pre entity ine & more] (destructure-ddl-item index-spec (str (sql-kw k) " options"))
[using & exprs] (if (contains? #{:using-gin 'using-gin} [using & exprs]
(first exprs)) (let [item (first exprs)]
(if (and (ident? item)
(str/starts-with? (str (kw->sym item)) "using-"))
exprs exprs
(cons nil exprs)) (cons nil exprs)))
[sqls params] (format-expr-list exprs)] [sqls params] (format-expr-list exprs)]
(into [(join " " (remove empty?) (into [(join " " (remove empty?)
(-> ["CREATE" pre "INDEX" ine entity (-> ["CREATE" pre "INDEX" ine entity
@ -1732,20 +1748,6 @@
(set @current-clause-order) (set @current-clause-order)
(set (keys @clause-format)))) (set (keys @clause-format))))
(defn- kw->sym
"Given a keyword, produce a symbol, retaining the namespace
qualifier, if any."
[k]
(if (keyword? k)
#?(:bb (if-let [n (namespace k)]
(symbol n (name k))
(symbol (name k)))
:clj (.sym ^clojure.lang.Keyword k)
:default (if-let [n (namespace k)]
(symbol n (name k))
(symbol (name k))))
k))
(defn format-dsl (defn format-dsl
"Given a hash map representing a SQL statement and a hash map "Given a hash map representing a SQL statement and a hash map
of options, return a vector containing a string -- the formatted of options, return a vector containing a string -- the formatted

View file

@ -1038,11 +1038,15 @@
(sql/format (create-index [:unique :my-column-idx :if-not-exists] [:my-table :my-column])))) (sql/format (create-index [:unique :my-column-idx :if-not-exists] [:my-table :my-column]))))
(is (= ["CREATE INDEX my_column_idx ON my_table (LOWER(my_column))"] (is (= ["CREATE INDEX my_column_idx ON my_table (LOWER(my_column))"]
(sql/format (create-index :my-column-idx [:my-table :%lower.my-column]))))) (sql/format (create-index :my-column-idx [:my-table :%lower.my-column])))))
(testing "PostgreSQL extensions (USING GIN)" (testing "PostgreSQL extensions (USING GIN/HASH)"
(is (= ["CREATE INDEX my_column_idx ON my_table USING GIN (my_column)"] (is (= ["CREATE INDEX my_column_idx ON my_table USING GIN (my_column)"]
(sql/format {:create-index [:my-column-idx [:my-table :using-gin :my-column]]}))) (sql/format {:create-index [:my-column-idx [:my-table :using-gin :my-column]]})))
(is (= ["CREATE INDEX my_column_idx ON my_table USING GIN (my_column)"] (is (= ["CREATE INDEX my_column_idx ON my_table USING GIN (my_column)"]
(sql/format (create-index :my-column-idx [:my-table :using-gin :my-column])))))) (sql/format (create-index :my-column-idx [:my-table :using-gin :my-column]))))
(is (= ["CREATE INDEX my_column_idx ON my_table USING HASH (my_column)"]
(sql/format {:create-index [:my-column-idx [:my-table :using-hash :my-column]]})))
(is (= ["CREATE INDEX my_column_idx ON my_table USING HASH (my_column)"]
(sql/format (create-index :my-column-idx [:my-table :using-hash :my-column]))))))
(deftest join-with-alias (deftest join-with-alias
(is (= ["SELECT * FROM foo LEFT JOIN (populatons AS pm INNER JOIN customers AS pc ON (pm.id = pc.id) AND (pm.other_id = pc.other_id)) ON foo.fk_id = pm.id"] (is (= ["SELECT * FROM foo LEFT JOIN (populatons AS pm INNER JOIN customers AS pc ON (pm.id = pc.id) AND (pm.other_id = pc.other_id)) ON foo.fk_id = pm.id"]