Merge pull request #517 from dancek/create-index

Implement CREATE INDEX
This commit is contained in:
Sean Corfield 2023-12-08 13:15:58 -08:00 committed by GitHub
commit 1c499ac8a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 3 deletions

View file

@ -98,7 +98,7 @@ names: the "from" and the "to" names.
> Note: `:modify-column` is MySQL-specific and should be considered legacy and deprecated. `:alter-column` will produce `MODIFY COLUMN` when the MySQL dialect is selected.
### add-index, drop-index
### add-index, drop-index, create-index
Used with `:alter-table`,
`:add-index` accepts a single (function) expression
@ -125,6 +125,22 @@ user=> (-> (h/alter-table :fruit)
["ALTER TABLE fruit ADD PRIMARY KEY(id)"]
```
Some databases treat the standalone `:create-index` differently (e.g. PostgreSQL) while some treat it as an alias to `:alter-table` `:add-index` (e.g. MySQL). It accepts a pair of index specification and column specification:
```clojure
user=> (sql/format {:create-index [:my-idx [:fruit :appearance]]})
["CREATE INDEX my_idx ON fruit (appearance)"]
user=> (sql/format {:create-index [[:unique :another-idx] [:fruit :color :appearance]]})
["CREATE UNIQUE INDEX another_idx ON fruit (color, appearance)"]
```
PostgreSQL supports IF NOT EXISTS and expressions instead of columns. This may make `:create-index` more useful than `:add-index`:
```clojure
user=> (sql/format (h/create-index [:unique :another-idx :if-not-exists] [:fruit :color :%lower.appearance]))
["CREATE UNIQUE INDEX IF NOT EXISTS another_idx ON fruit (color, LOWER(appearance))"]
```
### rename-table
Used with `:alter-table`,

View file

@ -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})]

View file

@ -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.

View file

@ -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]))))))

View file

@ -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]}))