Fixes #249 by adding :namespace-as-table? option for 0.9.8

This commit is contained in:
Sean Corfield 2019-09-07 23:42:38 -07:00
parent bf33e4803f
commit a732815b37
5 changed files with 38 additions and 9 deletions

View file

@ -1,3 +1,7 @@
## 0.9.8
* Fix #249 by adding `honeysql.format/*namespace-as-table?*` and `:namespace-as-table?` option to `format`. (@seancorfield)
## 0.9.7 ## 0.9.7
* Fix #248 by treating alias as "not a subquery" when generating SQL for it. (@seancorfield) * Fix #248 by treating alias as "not a subquery" when generating SQL for it. (@seancorfield)

View file

@ -33,8 +33,8 @@ Everything is built on top of maps representing SQL queries:
```clojure ```clojure
(def sqlmap {:select [:a :b :c] (def sqlmap {:select [:a :b :c]
:from [:foo] :from [:foo]
:where [:= :f.a "baz"]}) :where [:= :f.a "baz"]})
``` ```
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).
@ -46,6 +46,18 @@ Column names can be provided as keywords or symbols (but not strings -- HoneySQL
=> ["SELECT a, b, c FROM foo WHERE f.a = ?" "baz"] => ["SELECT a, b, c FROM foo WHERE f.a = ?" "baz"]
``` ```
By default, namespace-qualified keywords as treated as simple keywords: their namespace portion is ignored. This was the behavior in HoneySQL prior to the 0.9.0 release and has been restored since the 0.9.7 release as this is considered the least surprising behavior.
As of version 0.9.7, `format` accepts `:allow-namespaced-names? true` to provide the somewhat unusual behavior of 0.9.0-0.9.6, namely that namespace-qualified keywords were passed through into the SQL "as-is", i.e., with the `/` in them (which generally required a quoting strategy as well).
As of version 0.9.8, `format` accepts `:namespace-as-table? true` to treat namespace-qualified keywords as if the `/` were `.`, allowing `:table/column` as an alternative to `:table.column`. This approach is likely to be more compatible with code that uses libraries like [`next.jdbc`](https://github.com/seancorfield/next-jdbc) and [`seql`](https://github.com/exoscale/seql), as well as being more convenient in a world of namespace-qualified keywords, following the example of `clojure.spec` etc.
```clojure
(def q-sqlmap {:select [:foo/a :foo/b :foo/c]
:from [:foo]
:where [:= :foo/a "baz"]})
(sql/format q-sqlmap :namespace-as-table? true)
=> ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"]
```
Honeysql is a relatively "pure" library, it does not manage your sql connection Honeysql is a relatively "pure" library, it does not manage your sql connection
or run queries for you, it simply generates SQL strings. You can then pass them or run queries for you, it simply generates SQL strings. You can then pass them
to jdbc: to jdbc:

View file

@ -1,6 +1,6 @@
{ {
"name": "@honeysql/honeysql", "name": "@honeysql/honeysql",
"version": "0.9.7", "version": "0.9.8",
"license": "EPL-1.0", "license": "EPL-1.0",
"homepage": "https://github.com/jkk/honeysql", "homepage": "https://github.com/jkk/honeysql",
"repository": { "repository": {

View file

@ -46,6 +46,8 @@
(def ^:dynamic *allow-namespaced-names?* false) (def ^:dynamic *allow-namespaced-names?* false)
(def ^:dynamic *namespace-as-table?* false)
(def ^:dynamic *name-transform-fn* nil) (def ^:dynamic *name-transform-fn* nil)
(def ^:private quote-fns (def ^:private quote-fns
@ -95,11 +97,16 @@
s (cond s (cond
(or (keyword? x) (symbol? x)) (or (keyword? x) (symbol? x))
(name-transform-fn (name-transform-fn
(if *allow-namespaced-names?* (cond *namespace-as-table?*
(str (when-let [n (namespace x)] (str (when-let [n (namespace x)]
(str n "/")) (str n "."))
(name x)) (name x))
(name x))) *allow-namespaced-names?*
(str (when-let [n (namespace x)]
(str n "/"))
(name x))
:else
(name x)))
(string? x) (if qf x (name-transform-fn x)) (string? x) (if qf x (name-transform-fn x))
:else (str x))] :else (str x))]
(if-not qf (if-not qf
@ -286,7 +293,8 @@
*quote-identifier-fn* (quote-fns (:quoting opts)) *quote-identifier-fn* (quote-fns (:quoting opts))
*parameterizer* (or (:parameterizer opts) :jdbc) *parameterizer* (or (:parameterizer opts) :jdbc)
*allow-dashed-names?* (:allow-dashed-names? opts) *allow-dashed-names?* (:allow-dashed-names? opts)
*allow-namespaced-names?* (:allow-namespaced-names? opts)] *allow-namespaced-names?* (:allow-namespaced-names? opts)
*namespace-as-table?* (:namespace-as-table? opts)]
(let [sql-str (to-sql sql-map)] (let [sql-str (to-sql sql-map)]
(if (and (seq @*params*) (not= :none (:parameterizer opts))) (if (and (seq @*params*) (not= :none (:parameterizer opts)))
(if (:return-param-names opts) (if (:return-param-names opts)

View file

@ -6,6 +6,7 @@
[honeysql.types :as sql] [honeysql.types :as sql]
[honeysql.format :refer [honeysql.format :refer
[*allow-dashed-names?* *allow-namespaced-names?* [*allow-dashed-names?* *allow-namespaced-names?*
*namespace-as-table?*
quote-identifier format-clause format quote-identifier format-clause format
parameterize]])) parameterize]]))
@ -38,6 +39,10 @@
(deftest test-namespaced-identifier (deftest test-namespaced-identifier
(is (= (quote-identifier :foo/bar) "bar")) (is (= (quote-identifier :foo/bar) "bar"))
(is (= (quote-identifier :foo/bar :style :ansi) "\"bar\"")) (is (= (quote-identifier :foo/bar :style :ansi) "\"bar\""))
(binding [*namespace-as-table?* true]
(is (= (quote-identifier :foo/bar) "foo.bar"))
(is (= (quote-identifier :foo/bar :style :ansi) "\"foo\".\"bar\""))
(is (= (quote-identifier :foo/bar :style :ansi :split false) "\"foo.bar\"")))
(binding [*allow-namespaced-names?* true] (binding [*allow-namespaced-names?* true]
(is (= (quote-identifier :foo/bar) "foo/bar")) (is (= (quote-identifier :foo/bar) "foo/bar"))
(is (= (quote-identifier :foo/bar :style :ansi) "\"foo/bar\"")))) (is (= (quote-identifier :foo/bar :style :ansi) "\"foo/bar\""))))