From e70e3713fc0187a47799c9dc39ccf122d2fa2ee8 Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Fri, 8 Dec 2023 11:21:25 +0200 Subject: [PATCH] Implement CREATE INDEX Fixes #348. --- src/honey/sql.cljc | 13 +++++++++++++ src/honey/sql/helpers.cljc | 14 ++++++++++++++ test/honey/sql/helpers_test.cljc | 19 +++++++++++++++++++ test/honey/sql_test.cljc | 3 +-- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index fdf7f2f..67abc90 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -51,6 +51,7 @@ :create-extension :drop-table :drop-view :drop-materialized-view :drop-extension :refresh-materialized-view + :create-index ;; then SQL clauses in priority order: :raw :nest :with :with-recursive :intersect :union :union-all :except :except-all :table @@ -1255,6 +1256,17 @@ (into more) (conj (when as (sql-kw as))))))])) +(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")) + [sqls params] (format-expr-list exprs)] + (into [(str/join " " (remove empty? + (-> ["CREATE" pre "INDEX" ine entity + "ON" (format-entity table) + (str "(" (str/join ", " sqls) ")")] + (into more))))] + params))) + (defn- format-with-data [_ data] (let [data (if (sequential? data) (first data) data)] [(str/join " " (remove nil? @@ -1433,6 +1445,7 @@ :drop-view #'format-drop-items :drop-materialized-view #'format-drop-items :refresh-materialized-view (fn [_ x] (format-create :refresh :materialized-view x nil)) + :create-index #'format-create-index :raw (fn [_ x] (raw-render x)) :nest (fn [_ x] (let [[sql & params] (format-dsl x {:nested true})] diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc index c96960c..7429ec8 100644 --- a/src/honey/sql/helpers.cljc +++ b/src/honey/sql/helpers.cljc @@ -375,6 +375,20 @@ [& views] (generic :refresh-materialized-view views)) +(defn create-index + "Accepts an index spexification and a column specification. The column + specification consists of table name and one or more columns. + + (create-index :name-of-idx [:table :col]) + (create-index :name-of-idx [:table :col1 :col2]) + (create-index [:unique :name-of-idx] [:table :col]) + + PostgreSQL also supports :if-not-exists and expressions instead of columns. + + (create-index [:name-of-idx :if-not-exists] [:table :%lower.col])" + [& args] + (generic :create-index args)) + (defn with "Accepts one or more CTE definitions. diff --git a/test/honey/sql/helpers_test.cljc b/test/honey/sql/helpers_test.cljc index 245f486..b551a6e 100644 --- a/test/honey/sql/helpers_test.cljc +++ b/test/honey/sql/helpers_test.cljc @@ -7,6 +7,7 @@ [honey.sql.helpers :as h :refer [add-column add-index alter-table columns create-table create-table-as create-view create-materialized-view drop-view drop-materialized-view + create-index bulk-collect-into cross-join do-update-set drop-column drop-index drop-table filter from full-join @@ -962,3 +963,21 @@ (is (= '{} (-> '{} (where)))))) + +(deftest test-create-index + (testing "create index, commonly supported features" + (is (= ["CREATE INDEX my_column_idx ON my_table (my_column)"] + (sql/format {:create-index [:my-column-idx [:my-table :my-column]]}))) + (is (= ["CREATE INDEX my_column_idx ON my_table (my_column)"] + (sql/format (create-index :my-column-idx [:my-table :my-column])))) + (is (= ["CREATE UNIQUE INDEX my_column_idx ON my_table (my_column)"] + (sql/format (create-index [:unique :my-column-idx] [:my-table :my-column])))) + (is (= ["CREATE INDEX my_column_idx ON my_table (my_column, my_other_column)"] + (sql/format (create-index :my-column-idx [:my-table :my-column :my-other-column]))))) + (testing "PostgreSQL extensions (IF NOT EXISTS and expressions)" + (is (= ["CREATE INDEX IF NOT EXISTS my_column_idx ON my_table (my_column)"] + (sql/format (create-index [:my-column-idx :if-not-exists] [:my-table :my-column])))) + (is (= ["CREATE UNIQUE INDEX IF NOT EXISTS my_column_idx ON 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))"] + (sql/format (create-index :my-column-idx [:my-table :%lower.my-column])))))) diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index df52f92..7386fa0 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -1311,5 +1311,4 @@ ORDER BY id = ? DESC (comment ;; partial workaround for #407: - (sut/format {:select :f.* :from [[:foo [:f :for :system-time]]] :where [:= :f.id 1]}) - ) + (sut/format {:select :f.* :from [[:foo [:f :for :system-time]]] :where [:= :f.id 1]}))