Merge branch 'master' of github.com:jkk/honeysql

This commit is contained in:
Sean Corfield 2020-02-12 12:10:42 -08:00
commit ed20b39056

View file

@ -39,6 +39,8 @@ Everything is built on top of maps representing SQL queries:
Column names can be provided as keywords or symbols (but not strings -- HoneySQL treats strings as values that should be lifted out of the SQL as parameters). Column names can be provided as keywords or symbols (but not strings -- HoneySQL treats strings as values that should be lifted out of the SQL as parameters).
### `format`
`format` turns maps into `clojure.java.jdbc`-compatible, parameterized SQL: `format` turns maps into `clojure.java.jdbc`-compatible, parameterized SQL:
```clojure ```clojure
@ -66,6 +68,8 @@ to jdbc:
(jdbc/query conn (sql/format sqlmap)) (jdbc/query conn (sql/format sqlmap))
``` ```
### `build`
You can build up SQL maps yourself or use helper functions. `build` is the Swiss Army Knife helper. It lets you leave out brackets here and there: You can build up SQL maps yourself or use helper functions. `build` is the Swiss Army Knife helper. It lets you leave out brackets here and there:
```clojure ```clojure
@ -86,6 +90,8 @@ You can provide a "base" map as the first argument to build:
:from [:foo]} :from [:foo]}
``` ```
### Vanilla SQL clause helpers
There are also functions for each clause type in the `honeysql.helpers` namespace: There are also functions for each clause type in the `honeysql.helpers` namespace:
```clojure ```clojure
@ -119,7 +125,7 @@ To add to clauses instead of replacing them, use `merge-select`, `merge-where`,
=> ["SELECT a, b, c, d, e FROM foo WHERE (f.a = ? AND b > ?)" "baz" 10] => ["SELECT a, b, c, d, e FROM foo WHERE (f.a = ? AND b > ?)" "baz" 10]
``` ```
`where` will combine multiple clauses together using and: `where` will combine multiple clauses together using SQL's `AND`:
```clojure ```clojure
(-> (select :*) (-> (select :*)
@ -143,6 +149,8 @@ name and the desired alias:
In particular, note that `(select [:a :b])` means `SELECT a AS b` rather than In particular, note that `(select [:a :b])` means `SELECT a AS b` rather than
`SELECT a, b` -- `select` is variadic and does not take a collection of column names. `SELECT a, b` -- `select` is variadic and does not take a collection of column names.
### Inserts
Inserts are supported in two patterns. Inserts are supported in two patterns.
In the first pattern, you must explicitly specify the columns to insert, In the first pattern, you must explicitly specify the columns to insert,
then provide a collection of rows, each a collection of column values: then provide a collection of rows, each a collection of column values:
@ -179,6 +187,8 @@ and the remaining maps *must* have the same set of keys and values:
"Jane" "Daniels" 56] "Jane" "Daniels" 56]
``` ```
### Nested subqueries
The column values do not have to be literals, they can be nested queries: The column values do not have to be literals, they can be nested queries:
```clojure ```clojure
@ -198,6 +208,16 @@ The column values do not have to be literals, they can be nested queries:
"user"] "user"]
``` ```
```clojure
(-> (select :*)
(from :foo)
(where [:in :foo.a (-> (select :a) (from :bar))])
sql/format)
=> ["SELECT * FROM foo WHERE (foo.a in (SELECT a FROM bar))"]
```
### Composite types
Composite types are supported: Composite types are supported:
```clojure ```clojure
@ -213,6 +233,8 @@ Composite types are supported:
"small" 1 "inch" "large" 10 "feet"] "small" 1 "inch" "large" 10 "feet"]
``` ```
### Updates
Updates are possible too (note the double S in `sset` to avoid clashing Updates are possible too (note the double S in `sset` to avoid clashing
with `clojure.core/set`): with `clojure.core/set`):
@ -238,6 +260,8 @@ There are two variants of `sset` (and the underlying `:set` in the SQL map):
* `set0` (and `:set0`) -- this puts the `SET` before `FROM`, * `set0` (and `:set0`) -- this puts the `SET` before `FROM`,
* `set1` (and `:set1`) -- a synonym for `sset` (and `:set`) that puts the `SET` after `JOIN`. * `set1` (and `:set1`) -- a synonym for `sset` (and `:set`) that puts the `SET` after `JOIN`.
### Deletes
Deletes look as you would expect: Deletes look as you would expect:
```clojure ```clojure
@ -271,15 +295,7 @@ If you want to delete everything from a table, you can use `truncate`:
=> ["TRUNCATE films"] => ["TRUNCATE films"]
``` ```
Queries can be nested: ### Unions
```clojure
(-> (select :*)
(from :foo)
(where [:in :foo.a (-> (select :a) (from :bar))])
sql/format)
=> ["SELECT * FROM foo WHERE (foo.a in (SELECT a FROM bar))"]
```
Queries may be united within a :union or :union-all keyword: Queries may be united within a :union or :union-all keyword:
@ -289,6 +305,8 @@ Queries may be united within a :union or :union-all keyword:
=> ["SELECT * FROM foo UNION SELECT * FROM bar"] => ["SELECT * FROM foo UNION SELECT * FROM bar"]
``` ```
### Functions
Keywords that begin with `%` are interpreted as SQL function calls: Keywords that begin with `%` are interpreted as SQL function calls:
```clojure ```clojure
@ -298,6 +316,8 @@ Keywords that begin with `%` are interpreted as SQL function calls:
=> ["SELECT max(id) FROM foo"] => ["SELECT max(id) FROM foo"]
``` ```
### Bindable parameters
Keywords that begin with `?` are interpreted as bindable parameters: Keywords that begin with `?` are interpreted as bindable parameters:
```clojure ```clojure
@ -308,6 +328,8 @@ Keywords that begin with `?` are interpreted as bindable parameters:
=> ["SELECT id FROM foo WHERE a = ?" "BAZ"] => ["SELECT id FROM foo WHERE a = ?" "BAZ"]
``` ```
### Miscellaneous
There are helper functions and data literals for SQL function calls, field There are helper functions and data literals for SQL function calls, field
qualifiers, raw SQL fragments, inline values, and named input parameters: qualifiers, raw SQL fragments, inline values, and named input parameters:
@ -326,6 +348,8 @@ call-qualify-map
=> ["SELECT foo(bar), foo.a, @var := foo.bar FROM foo WHERE (a = ? AND b = 42)" "BAZ"] => ["SELECT foo(bar), foo.a, @var := foo.bar FROM foo WHERE (a = ? AND b = 42)" "BAZ"]
``` ```
#### PostGIS
A common example in the wild is the PostGIS extension to PostgreSQL where you A common example in the wild is the PostGIS extension to PostgreSQL where you
have a lot of function calls needed in code: have a lot of function calls needed in code:
@ -341,6 +365,8 @@ have a lot of function calls needed in code:
0.291 32.621 4326] 0.291 32.621 4326]
``` ```
#### Raw SQL fragments
Raw SQL fragments that are strings are treated exactly as-is when rendered into Raw SQL fragments that are strings are treated exactly as-is when rendered into
the formatted SQL string (with no parsing or parameterization). Inline values the formatted SQL string (with no parsing or parameterization). Inline values
will not be lifted out as parameters, so they end up in the SQL string as-is. will not be lifted out as parameters, so they end up in the SQL string as-is.
@ -366,6 +392,8 @@ or the `param` helper.
=> ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5]
``` ```
#### Identifiers
To quote identifiers, pass the `:quoting` keyword option to `format`. Valid options are `:ansi` (PostgreSQL), `:mysql`, or `:sqlserver`: To quote identifiers, pass the `:quoting` keyword option to `format`. Valid options are `:ansi` (PostgreSQL), `:mysql`, or `:sqlserver`:
```clojure ```clojure
@ -376,9 +404,11 @@ To quote identifiers, pass the `:quoting` keyword option to `format`. Valid opti
=> ["SELECT `foo`.`a` FROM `foo` WHERE `foo`.`a` = ?" "baz"] => ["SELECT `foo`.`a` FROM `foo` WHERE `foo`.`a` = ?" "baz"]
``` ```
#### Locking
To issue a locking select, add a `:lock` to the query or use the lock helper. The lock value must be a map with a `:mode` value. The built-in To issue a locking select, add a `:lock` to the query or use the lock helper. The lock value must be a map with a `:mode` value. The built-in
modes are the standard :update (FOR UPDATE) or the vendor-specific `:mysql-share` (LOCK IN SHARE MODE) or `:postresql-share` (FOR SHARE). The modes are the standard `:update` (FOR UPDATE) or the vendor-specific `:mysql-share` (LOCK IN SHARE MODE) or `:postresql-share` (FOR SHARE). The
lock map may also provide a :wait value, which if false will append the NOWAIT parameter, supported by PostgreSQL. lock map may also provide a `:wait` value, which if false will append the NOWAIT parameter, supported by PostgreSQL.
```clojure ```clojure
(-> (select :foo.a) (-> (select :foo.a)
@ -402,6 +432,8 @@ To be able to use dashes in quoted names, you can pass ```:allow-dashed-names tr
=> ["SELECT \"f\".\"foo-id\", \"f\".\"foo-name\" FROM \"foo-bar\" \"f\" WHERE \"f\".\"foo-id\" = ?" 12345] => ["SELECT \"f\".\"foo-id\", \"f\".\"foo-name\" FROM \"foo-bar\" \"f\" WHERE \"f\".\"foo-id\" = ?" 12345]
``` ```
### Big, complicated example
Here's a big, complicated query. Note that Honey SQL makes no attempt to verify that your queries make any sense. It merely renders surface syntax. Here's a big, complicated query. Note that Honey SQL makes no attempt to verify that your queries make any sense. It merely renders surface syntax.
```clojure ```clojure
@ -538,7 +570,7 @@ To teach `honeysql` how to handle your datatype you need to implement [`honeysql
``` ```
## TODO ## TODO
* Create table, etc. - [ ] Create table, etc.
## Extensions ## Extensions