Fixes #261 by re-implementing :raw

This commit is contained in:
Sean Corfield 2021-01-30 12:35:51 -08:00
parent 4af4f3f7ed
commit 429761f106
3 changed files with 21 additions and 5 deletions

View file

@ -388,17 +388,25 @@ parameters. If you need a string parameter lifted, you must use `:param`.
(from :foo)
(where [:< :expired_at [:raw ["now() - '" 5 " seconds'"]]])
(sql/format))
=> ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5]
=> ["SELECT * FROM foo WHERE expired_at < now() - '5 seconds'"]
```
```clojure
(-> (select :*)
(from :foo)
(where [:< :expired_at [:raw ["now() - '" [:param :t] " seconds'"]]])
(sql/format {:t 5}))
(sql/format {:params {:t 5}}))
=> ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5]
```
```clojure
(-> (select :*)
(from :foo)
(where [:< :expired_at [:raw ["now() - " [:inline (str 5 " seconds")]]]])
(sql/format))
=> ["SELECT * FROM foo WHERE expired_at < now() - '5 seconds'"]
```
#### Identifiers
To quote identifiers, pass the `:quoted true` option to `format` and they will

View file

@ -96,11 +96,10 @@ The following new syntax has been added:
* `:array` -- used as a function to replace the `sql/array` / `#sql/array` machinery,
* `:inline` -- used as a function to replace the `sql/inline` / `#sql/inline` machinery,
* `:interval` -- used as a function to support `INTERVAL <n> <units>`, e.g., `[:interval 30 :days]`.
* `:raw` -- used as a function to replace the `sql/raw` / `#sql/raw` machinery. Vector subexpressions inside a `[:raw ..]` expression are formatted to SQL and parameters. Other subexpressions are just turned into strings and concatenated. This is different to the v1 behavior but should be more flexible.
> Note 1: in 1.x, inlining a string `"foo"` produced `foo` but in 2.x it produces `'foo'`, i.e., string literals become SQL strings without needing internal quotes (1.x required `"'foo'"`).
> Note 2: expect `:raw` to be added in some form before release.
## Extensibility
The protocols and multimethods in 1.x have all gone away. The primary extension point is `honey.sql/register-clause!` which lets you specify the new clause (keyword), the formatter function for it, and the existing clause that it should be ranked before (`format` processes the DSL in clause order).

View file

@ -556,7 +556,16 @@
:raw
(fn [_ [s]]
(if (sequential? s)
[(str/join " " s)]
(let [[sqls params]
(reduce (fn [[sqls params] s]
(if (vector? s)
(let [[sql & params'] (format-expr s)]
[(conj sqls sql)
(into params params')])
[(conj sqls s) params]))
[[] []]
s)]
(into [(str/join sqls)] params))
[s]))}))
(defn format-expr [x & [{:keys [nested?] :as opts}]]