Skip to content

Commit b25aed7

Browse files
author
Drew Patel
authored
Add constraints format-clause with support for UNIQUE and PRIMARY KEY (#60)
Adds support for formatting constraint clauses.
1 parent 024a93a commit b25aed7

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ The following are the SQL functions added in `honeysql-postgres`
255255

256256
(sql/format (sql/call :primary-key :arg1 :arg2))
257257
=> ["PRIMARY KEY(arg1, arg2)"]
258+
259+
(-> (psqlh/create-table :table)
260+
(psqlh/with-columns [[:column_1 :integer]
261+
[:column_2 :text]])
262+
(psqlh/constraints [[:primary-key [:column_1]]])
263+
sql/format)
264+
=> ["CREATE TABLE table (column_1 integer, column_2 text, PRIMARY KEY(column_1))"]
258265
```
259266
- `unique`
260267
```clojure
@@ -263,6 +270,13 @@ The following are the SQL functions added in `honeysql-postgres`
263270

264271
(sql/format (sql/call :unique :arg1 :arg2))
265272
=> ["UNIQUE(arg1, arg2)"]
273+
274+
(-> (psqlh/create-table :table)
275+
(psqlh/with-columns [[:column_1 :integer]
276+
[:column_2 :text]])
277+
(psqlh/constraints [[:unique [:column_2]]])
278+
sql/format)
279+
=> ["CREATE TABLE table (column_1 integer, column_2 text, UNIQUE(column_2))"]
266280
```
267281
- `foreign-key`
268282
```clojure

src/honeysql_postgres/format.cljc

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
:within-group 55
1818
:over 55
1919
:insert-into-as 60
20+
:with-columns 70
21+
:constraints 75
2022
:partition-by 165
2123
:window 195
2224
:upsert 225
@@ -161,11 +163,39 @@
161163
util/get-first
162164
sqlf/to-sql)))
163165

164-
(defmethod format-clause :with-columns [[_ columns] _]
165-
(sqlf/paren-wrap (->> columns
166-
util/get-first
167-
(map #(sqlf/space-join (map sqlf/to-sql %)))
168-
sqlf/comma-join)))
166+
(def ^:private constraints-format-map
167+
{:primary-key "PRIMARY KEY"
168+
:unique "UNIQUE"})
169+
170+
(defn- format-constraint-clause
171+
[[constraint-type constraint-args]]
172+
(when (contains? constraints-format-map constraint-type)
173+
(str (get constraints-format-map constraint-type)
174+
(sqlf/paren-wrap (->> constraint-args
175+
(map sqlf/to-sql)
176+
sqlf/comma-join)))))
177+
178+
(defn- format-columns-clause
179+
[columns]
180+
(->> columns
181+
util/get-first
182+
(map #(sqlf/space-join (map sqlf/to-sql %)))
183+
sqlf/comma-join))
184+
185+
(defmethod format-clause :with-columns [[_ columns] complete-sql-map]
186+
(when-not (seq (:constraints complete-sql-map))
187+
(sqlf/paren-wrap (format-columns-clause columns))))
188+
189+
(defmethod format-clause :constraints [[_ [constraints]] complete-sql-map]
190+
(let [columns (:with-columns complete-sql-map)
191+
constraints (filter (fn [[constraint-type _]]
192+
(contains? constraints-format-map constraint-type)) constraints)]
193+
(sqlf/paren-wrap
194+
(str (when (seq columns)
195+
(format-columns-clause columns))
196+
(when (seq constraints)
197+
(str ", "
198+
(sqlf/comma-join (map format-constraint-clause constraints))))))))
169199

170200
(defmethod format-clause :drop-table [[_ params] _]
171201
(let [[if-exists & others] params

src/honeysql_postgres/helpers.cljc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
(defhelper with-columns [m args]
4343
(assoc m :with-columns args))
4444

45+
(defhelper constraints [m args]
46+
(assoc m :constraints args))
47+
4548
(defhelper drop-table [m tablenames]
4649
(assoc m :drop-table (sqlh/collify tablenames)))
4750

test/honeysql_postgres/postgres_test.cljc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:refer
99
[add-column
1010
alter-table
11+
constraints
1112
create-extension
1213
create-table
1314
create-view
@@ -193,6 +194,43 @@
193194
[(sql/call :check [:> :discounted_price 0] [:> :price :discounted_price])]])
194195
sql/format)))))
195196

197+
(deftest constraints-test
198+
(testing "creating table with unique constraint on multiple columns"
199+
(is (= ["CREATE TABLE products (product_no integer, name text, product_sku integer, UNIQUE(product_no, product_sku))"]
200+
(-> (create-table :products)
201+
(with-columns [[:product_no :integer]
202+
[:name :text]
203+
[:product_sku :integer]])
204+
(constraints [[:unique [:product_no :product_sku]]])
205+
sql/format))))
206+
(testing "creating table with primary key constraint on single column"
207+
(is (= ["CREATE TABLE products (product_no integer, name text, product_sku integer, PRIMARY KEY(product_no))"]
208+
(-> (create-table :products)
209+
(with-columns [[:product_no :integer]
210+
[:name :text]
211+
[:product_sku :integer]])
212+
(constraints [[:primary-key [:product_no]]])
213+
sql/format))))
214+
(testing "creating table with primary key and unique constraints"
215+
(is (= ["CREATE TABLE products (product_no integer, name text, product_sku integer, UNIQUE(product_no, product_sku), PRIMARY KEY(product_no))"]
216+
(-> (create-table :products)
217+
(with-columns [[:product_no :integer]
218+
[:name :text]
219+
[:product_sku :integer]])
220+
(constraints [[:unique [:product_no :product_sku]]
221+
[:primary-key [:product_no]]])
222+
sql/format))))
223+
(testing "creating table with invalid/unsupported constraints does not produce incorrect SQL statement"
224+
(is (= ["CREATE TABLE products (product_no integer, name text, product_sku integer, PRIMARY KEY(product_no))"]
225+
(-> (create-table :products)
226+
(with-columns [[:product_no :integer]
227+
[:name :text]
228+
[:product_sku :integer]])
229+
(constraints [[:unique-constraint [:product_no]] ;; incorrect constraint-type
230+
[:primary-key [:product_no]]
231+
[:not-null [:name]]]) ;; unsupported constraint-type
232+
sql/format)))))
233+
196234
(deftest over-test
197235
(testing "window function over on select statemt"
198236
(is (= ["SELECT id , avg(salary) OVER (PARTITION BY department ORDER BY designation) AS Average, max(salary) OVER w AS MaxSalary FROM employee WINDOW w AS (PARTITION BY department)"]

0 commit comments

Comments
 (0)