fix #495 by documenting formatv and adding tests

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2024-03-04 12:36:32 -08:00
parent 9c29cb29ff
commit 225c0db092
No known key found for this signature in database
4 changed files with 30 additions and 18 deletions

View file

@ -7,7 +7,7 @@
* Address [#521](https://github.com/seancorfield/honeysql/issues/521) by adding initial experimental support for an XTDB dialect. * Address [#521](https://github.com/seancorfield/honeysql/issues/521) by adding initial experimental support for an XTDB dialect.
* Address [#520](https://github.com/seancorfield/honeysql/issues/520) by expanding how `:inline` works, to support a sequence of arguments. * Address [#520](https://github.com/seancorfield/honeysql/issues/520) by expanding how `:inline` works, to support a sequence of arguments.
* Fix [#518](https://github.com/seancorfield/honeysql/issues/518) by moving temporal clause before alias. * Fix [#518](https://github.com/seancorfield/honeysql/issues/518) by moving temporal clause before alias.
* Address [#495](https://github.com/seancorfield/honeysql/issues/495) by adding (experimental) `formatv` macro (`.clj` only!) -- purely for discussion: may be removed in a subsequent release! * Address [#495](https://github.com/seancorfield/honeysql/issues/495) by adding `formatv` macro (`.clj` only!) -- and removing the experimental `formatf` function (added for discussion in 2.4.1045).
* Implemented `CREATE INDEX` [#348](https://github.com/seancorfield/honeysql/issues/348) via PR [#517](https://github.com/seancorfield/honeysql/pull/517) [@dancek](https://github.com/dancek). * Implemented `CREATE INDEX` [#348](https://github.com/seancorfield/honeysql/issues/348) via PR [#517](https://github.com/seancorfield/honeysql/pull/517) [@dancek](https://github.com/dancek).
* Mention `:not-in` explicitly in the documentation. * Mention `:not-in` explicitly in the documentation.
* Code cleanup per `clj-kondo`. * Code cleanup per `clj-kondo`.
@ -45,7 +45,7 @@
* Update `tools.build` to 0.9.5 (and remove `:java-opts` setting from `build/run-task`) * Update `tools.build` to 0.9.5 (and remove `:java-opts` setting from `build/run-task`)
* 2.4.1045 -- 2023-06-25 * 2.4.1045 -- 2023-06-25
* Address [#495](https://github.com/seancorfield/honeysql/issues/495) by adding (experimental) `formatf` function -- purely for discussion: may be removed in a subsequent release! * Address [#495](https://github.com/seancorfield/honeysql/issues/495) by adding (experimental) `formatf` function -- _note: this was removed in 2.5.next, in favor of the `formatv` macro._
* Fix [#494](https://github.com/seancorfield/honeysql/issues/494) by supporting expressions in `:on-conflict` instead of just entities. * Fix [#494](https://github.com/seancorfield/honeysql/issues/494) by supporting expressions in `:on-conflict` instead of just entities.
* Address [#493](https://github.com/seancorfield/honeysql/issues/493) by clarifying use of `:values` in CTEs (using `:with`). * Address [#493](https://github.com/seancorfield/honeysql/issues/493) by clarifying use of `:values` in CTEs (using `:with`).
* Address [#489](https://github.com/seancorfield/honeysql/issues/489) by adding more examples around `:update`. * Address [#489](https://github.com/seancorfield/honeysql/issues/489) by adding more examples around `:update`.

View file

@ -143,6 +143,24 @@ Namespace-qualified keywords (and symbols) are generally treated as table-qualif
=> ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"] => ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"]
``` ```
As of 2.5.next, there is a helper macro you can use with quoted symbolic
queries (that are purely literal, not programmatically constructed) to
provide "escape hatches" for certain symbols that you want to be treated
as locally bound symbols (and, hence, their values):
<!-- :test-doc-blocks/skip -->
```clojure
;; quoted symbolic query with local substitution:
(let [search-value "baz"]
(sql/formatv [search-value]
'{select (foo/a, foo/b, foo/c)
from (foo)
where (= foo/a search-value)}))
=> ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"]
```
> Note: this is a Clojure-only feature and is not available in ClojureScript, and it is intended for literal, inline symbolic queries only, not for programmatically constructed queries (where you would be able to substitute the values directly, as you build the query).
Documentation for the entire data DSL can be found in the Documentation for the entire data DSL can be found in the
[Clause Reference](doc/clause-reference.md), the [Clause Reference](doc/clause-reference.md), the
[Operator Reference](doc/operator-reference.md), and the [Operator Reference](doc/operator-reference.md), and the

View file

@ -2101,24 +2101,15 @@
(mapv #(unwrap % opts) (formatter data opts)))))) (mapv #(unwrap % opts) (formatter data opts))))))
([data k v & {:as opts}] (format data (assoc opts k v)))) ([data k v & {:as opts}] (format data (assoc opts k v))))
(defn formatf
"Experimental implementation of https://github.com/seancorfield/honeysql/issues/495
Currently, does not support options."
[dsl & params]
(format dsl {:params (zipmap (map (comp keyword str inc) (range)) params)}))
#?(:clj #?(:clj
(defmacro formatv (defmacro formatv
"Experimental implementation of https://github.com/seancorfield/honeysql/issues/495 "Treats the specified vector of symbols as variables to be substituted
Treats the specified vector of symbols as variables to be substituted
in the symbolic SQL expression. in the symbolic SQL expression.
(let [x 42 y 13] (let [x 42 y 13]
(formatv [x] '{select * from table where (= x y)})) (formatv [y] '{select * from table where (= x y)}))
=> SELECT * FROM table WHERE (42 = y)" => [\"SELECT * FROM table WHERE (x = ?)\" 13]"
[syms sql & opts] [syms sql & opts]
`(honey.sql/format (clojure.template/apply-template '~syms ~sql ~syms) ~@opts))) `(honey.sql/format (clojure.template/apply-template '~syms ~sql ~syms) ~@opts)))
@ -2390,10 +2381,6 @@
(sql/format {:select [:*], :from [:table], :where [:foo [:+ :a 1]]}) (sql/format {:select [:*], :from [:table], :where [:foo [:+ :a 1]]})
(sql/format '{select * from table where (foo (+ a 1))}) (sql/format '{select * from table where (foo (+ a 1))})
(let [v 42]
(sql/formatf '{select * from table where (foo (+ a ?1))} v))
(let [v 42] (println v)
(sql/format& '{select * from table where (foo (+ a v))}))
(let [v 42] (let [v 42]
(sql/formatv [v] '{select * from table where (foo (+ a v))})) (sql/formatv [v] '{select * from table where (foo (+ a v))}))
(sql/format '{select * from table where (foo (+ a ?v))} (sql/format '{select * from table where (foo (+ a ?v))}

View file

@ -1211,6 +1211,13 @@ ORDER BY id = ? DESC
(is (= ["INNER JOIN (tbl1 LEFT JOIN tbl2 USING (id))"] (is (= ["INNER JOIN (tbl1 LEFT JOIN tbl2 USING (id))"]
(sut/format {:join [[[:join :tbl1 {:left-join [:tbl2 [:using :id]]}]]]}))))) (sut/format {:join [[[:join :tbl1 {:left-join [:tbl2 [:using :id]]}]]]})))))
#?(:clj
(deftest issue-495-formatv
(is (= ["SELECT * FROM foo WHERE x = ?" 13]
(let [v 13 x 42]
(assert x) ; just to mark it as used
(sut/formatv [v] '{select * from foo where (= x v)}))))))
(deftest issue-496-overriding (deftest issue-496-overriding
(is (= ["INSERT INTO table (a, b) OVERRIDING SYSTEM VALUE VALUES (?, ?)" 1 2] (is (= ["INSERT INTO table (a, b) OVERRIDING SYSTEM VALUE VALUES (?, ?)" 1 2]
(sut/format {:insert-into [{:overriding-value :system} :table] (sut/format {:insert-into [{:overriding-value :system} :table]