Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CREATE INDEX #517

Merged
merged 2 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion doc/clause-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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`,
Expand Down
13 changes: 13 additions & 0 deletions src/honey/sql.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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?
Expand Down Expand Up @@ -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})]
Expand Down
14 changes: 14 additions & 0 deletions src/honey/sql/helpers.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
19 changes: 19 additions & 0 deletions test/honey/sql/helpers_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]))))))
3 changes: 1 addition & 2 deletions test/honey/sql_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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]}))