diff --git a/CHANGELOG.md b/CHANGELOG.md index 5160fd3..bbeaf9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ * 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. * 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). * Mention `:not-in` explicitly in the documentation. * 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`) * 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. * 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`. diff --git a/README.md b/README.md index 784e16f..1c51ab8 100644 --- a/README.md +++ b/README.md @@ -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"] ``` +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): + + +```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 [Clause Reference](doc/clause-reference.md), the [Operator Reference](doc/operator-reference.md), and the diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index f096f04..fb964d2 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -2101,24 +2101,15 @@ (mapv #(unwrap % opts) (formatter data opts)))))) ([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 (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. (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] `(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))}) - (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] (sql/formatv [v] '{select * from table where (foo (+ a v))})) (sql/format '{select * from table where (foo (+ a ?v))} diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 61b313c..7d58241 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -1211,6 +1211,13 @@ ORDER BY id = ? DESC (is (= ["INNER 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 (is (= ["INSERT INTO table (a, b) OVERRIDING SYSTEM VALUE VALUES (?, ?)" 1 2] (sut/format {:insert-into [{:overriding-value :system} :table]