fix #570 by adding :at
there is also :.:. Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
parent
44494e61c0
commit
d74046c658
4 changed files with 58 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
* 2.7.next in progress
|
* 2.7.next in progress
|
||||||
* Address #570 by adding `:.:.` as special syntax for Snowflake's JSON path syntax.
|
* Address #570 by adding `:.:.` as special syntax for Snowflake's JSON path syntax, and `:at` as special syntax for general `[`..`]` path syntax.
|
||||||
|
|
||||||
* 2.6.1281 -- 2025-03-06
|
* 2.6.1281 -- 2025-03-06
|
||||||
* Address [#568](https://github.com/seancorfield/honeysql/issues/568) by adding `honey.sql/semicolon` to merge multiple SQL+params vectors into one (with semicolons separating the SQL statements).
|
* Address [#568](https://github.com/seancorfield/honeysql/issues/568) by adding `honey.sql/semicolon` to merge multiple SQL+params vectors into one (with semicolons separating the SQL statements).
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,29 @@ In the subquery case, produces `ARRAY(subquery)`:
|
||||||
;;=> ["SELECT ARRAY(SELECT * FROM table) AS arr"]
|
;;=> ["SELECT ARRAY(SELECT * FROM table) AS arr"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## at
|
||||||
|
|
||||||
|
If addition to dot navigation (for JSON) -- see the `.` and `.:.` syntax below --
|
||||||
|
HoneySQL also supports bracket notation for JSON navigation.
|
||||||
|
|
||||||
|
The first argument to `:at` is treated as an expression that identifies
|
||||||
|
the column, and subsequent arguments are treated as field names or array
|
||||||
|
indices to navigate into that document.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format {:select [[[:at :col :field1 :field2]]]})
|
||||||
|
["SELECT col.field1.field2"]
|
||||||
|
user=> (sql/format {:select [[[:at :table.col 0 :field]]]})
|
||||||
|
["SELECT table.col[0].field"]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want an array index to be a parameter, use `:lift`:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format {:select [[[:at :col [:lift 0] :field]]]})
|
||||||
|
["SELECT col[?].field" 0]
|
||||||
|
```
|
||||||
|
|
||||||
## at time zone
|
## at time zone
|
||||||
|
|
||||||
Accepts two arguments: an expression (assumed to be a date/time of some sort)
|
Accepts two arguments: an expression (assumed to be a date/time of some sort)
|
||||||
|
|
@ -235,6 +258,9 @@ Can be used with `:nest` for field selection from composites:
|
||||||
;;=> ["SELECT (v).*, (MYFUNC(x)).y"]
|
;;=> ["SELECT (v).*, (MYFUNC(x)).y"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See also [`get-in`](xtdb.md#object-navigation-expressions)
|
||||||
|
and [`at`](#at) for additional path navigation functions.
|
||||||
|
|
||||||
## entity
|
## entity
|
||||||
|
|
||||||
Accepts a single keyword or symbol argument and produces a
|
Accepts a single keyword or symbol argument and produces a
|
||||||
|
|
|
||||||
|
|
@ -1936,28 +1936,34 @@
|
||||||
|
|
||||||
(defn- get-in-navigation
|
(defn- get-in-navigation
|
||||||
"[:get-in expr key-or-index1 key-or-index2 ...]"
|
"[:get-in expr key-or-index1 key-or-index2 ...]"
|
||||||
[_ [expr & kix]]
|
[wrap [expr & kix]]
|
||||||
(let [[sql & params] (format-expr expr)
|
(let [[sql & params] (format-expr expr)
|
||||||
[sqls params']
|
[sqls params']
|
||||||
(reduce-sql (map #(cond (number? %)
|
(reduce-sql (map #(cond (number? %)
|
||||||
[(str "[" % "]")]
|
[(str "[" % "]")]
|
||||||
|
(string? %)
|
||||||
|
[(str "[" (sqlize-value %) "]")]
|
||||||
(ident? %)
|
(ident? %)
|
||||||
[(str "." (format-entity %))]
|
[(str "." (format-entity %))]
|
||||||
:else
|
:else
|
||||||
(let [[sql' & params'] (format-expr %)]
|
(let [[sql' & params'] (format-expr %)]
|
||||||
(cons (str "[" sql' "]") params')))
|
(cons (str "[" sql' "]") params')))
|
||||||
kix))]
|
kix))]
|
||||||
(into* [(str "(" sql ")" (join "" sqls))] params params')))
|
(into* [(str (if wrap (str "(" sql ")") sql)
|
||||||
|
(join "" sqls))]
|
||||||
|
params
|
||||||
|
params')))
|
||||||
|
|
||||||
(defn ignore-respect-nulls [k [x]]
|
(defn- ignore-respect-nulls [k [x]]
|
||||||
(let [[sql & params] (format-expr x)]
|
(let [[sql & params] (format-expr x)]
|
||||||
(into [(str sql " " (sql-kw k))] params)))
|
(into [(str sql " " (sql-kw k))] params)))
|
||||||
|
|
||||||
(defn dot-navigation [sep [expr col & subcols]]
|
(defn- dot-navigation [sep [expr col & subcols]]
|
||||||
(let [[sql & params] (format-expr expr)]
|
(let [[sql & params] (format-expr expr)]
|
||||||
(into [(str sql sep (format-entity col)
|
(into [(str sql sep (format-simple-expr col "dot navigation")
|
||||||
(when (seq subcols)
|
(when (seq subcols)
|
||||||
(str "." (join "." (map format-entity subcols)))))]
|
(str "." (join "." (map #(format-simple-expr % "dot navigation")
|
||||||
|
subcols)))))]
|
||||||
params)))
|
params)))
|
||||||
(def ^:private special-syntax
|
(def ^:private special-syntax
|
||||||
(atom
|
(atom
|
||||||
|
|
@ -2006,6 +2012,7 @@
|
||||||
(let [[sqls params] (format-expr-list arr)
|
(let [[sqls params] (format-expr-list arr)
|
||||||
type-str (when type (str "::" (sql-kw type) "[]"))]
|
type-str (when type (str "::" (sql-kw type) "[]"))]
|
||||||
(into [(str "ARRAY[" (join ", " sqls) "]" type-str)] params))))
|
(into [(str "ARRAY[" (join ", " sqls) "]" type-str)] params))))
|
||||||
|
:at (fn [_ data] (get-in-navigation false data))
|
||||||
:at-time-zone
|
:at-time-zone
|
||||||
(fn [_ [expr tz]]
|
(fn [_ [expr tz]]
|
||||||
(let [[sql & params] (format-expr expr {:nested true})
|
(let [[sql & params] (format-expr expr {:nested true})
|
||||||
|
|
@ -2038,7 +2045,7 @@
|
||||||
[sql-e & params-e] (format-expr escape-chars)]
|
[sql-e & params-e] (format-expr escape-chars)]
|
||||||
(into* [(str sql-p " " (sql-kw :escape) " " sql-e)] params-p params-e)))
|
(into* [(str sql-p " " (sql-kw :escape) " " sql-e)] params-p params-e)))
|
||||||
:filter expr-clause-pairs
|
:filter expr-clause-pairs
|
||||||
:get-in #'get-in-navigation
|
:get-in (fn [_ data] (get-in-navigation true data))
|
||||||
:ignore-nulls ignore-respect-nulls
|
:ignore-nulls ignore-respect-nulls
|
||||||
:inline
|
:inline
|
||||||
(fn [_ xs]
|
(fn [_ xs]
|
||||||
|
|
|
||||||
|
|
@ -1225,7 +1225,23 @@ ORDER BY id = ? DESC
|
||||||
(sut/format '{select (((.:. (nest v) *))
|
(sut/format '{select (((.:. (nest v) *))
|
||||||
((.:. (nest w) x))
|
((.:. (nest w) x))
|
||||||
((.:. (nest (y z)) *)))}
|
((.:. (nest (y z)) *)))}
|
||||||
{:dialect :mysql})))))
|
{:dialect :mysql}))))
|
||||||
|
(testing "bracket selection"
|
||||||
|
(is (= ["SELECT a['b'], c['b'], a['d'].x, a:e[0].name"]
|
||||||
|
(sut/format {:select [[[:at :a [:inline "b"]]]
|
||||||
|
[[:at :c "b"]]
|
||||||
|
[[:at :a [:inline "d"] :x]]
|
||||||
|
[[:.:. :a [:at :e [:inline 0]] :name]]]})))
|
||||||
|
(is (= ["SELECT a[?].name" 0]
|
||||||
|
(sut/format '{select (((at a (lift 0) name)))})))
|
||||||
|
;; sanity check, compare with get-in:
|
||||||
|
(is (= ["SELECT (a)[?].name" 0]
|
||||||
|
(sut/format '{select (((get-in a (lift 0) name)))})))
|
||||||
|
(is (= ["SELECT (a)['b'], (c)['b'], (a)['d'].x, a:(e)[0].name"]
|
||||||
|
(sut/format {:select [[[:get-in :a [:inline "b"]]]
|
||||||
|
[[:get-in :c "b"]]
|
||||||
|
[[:get-in :a [:inline "d"] :x]]
|
||||||
|
[[:.:. :a [:get-in :e [:inline 0]] :name]]]})))))
|
||||||
|
|
||||||
(deftest issue-476-raw
|
(deftest issue-476-raw
|
||||||
(testing "single argument :raw"
|
(testing "single argument :raw"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue