diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9a5b3..d30bc75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes * 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). * Update dev/build deps. diff --git a/doc/clause-reference.md b/doc/clause-reference.md index 92562fb..399be17 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -149,6 +149,14 @@ user=> (sql/format {:create-index [:my-idx [: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 Used with `:alter-table`, diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 6ed773d..3fc43af 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -370,6 +370,20 @@ (keyword (name 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]] (str (or open "{") (join ", " (map (fn [[k v]] @@ -1418,10 +1432,12 @@ (defn- format-create-index [k clauses] (let [[index-spec [table & exprs]] clauses [pre entity ine & more] (destructure-ddl-item index-spec (str (sql-kw k) " options")) - [using & exprs] (if (contains? #{:using-gin 'using-gin} - (first exprs)) - exprs - (cons nil exprs)) + [using & exprs] + (let [item (first exprs)] + (if (and (ident? item) + (str/starts-with? (str (kw->sym item)) "using-")) + exprs + (cons nil exprs))) [sqls params] (format-expr-list exprs)] (into [(join " " (remove empty?) (-> ["CREATE" pre "INDEX" ine entity @@ -1732,20 +1748,6 @@ (set @current-clause-order) (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 "Given a hash map representing a SQL statement and a hash map of options, return a vector containing a string -- the formatted diff --git a/test/honey/sql/helpers_test.cljc b/test/honey/sql/helpers_test.cljc index 79e72f9..97ccde5 100644 --- a/test/honey/sql/helpers_test.cljc +++ b/test/honey/sql/helpers_test.cljc @@ -1038,11 +1038,15 @@ (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))"] (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)"] (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)"] - (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 (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"]