address #532 by adding exclude, rename

and tests for nest_one, nest_many

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2024-11-12 15:58:32 -08:00
parent c1c7cba96a
commit 6fa606ffd5
No known key found for this signature in database
4 changed files with 71 additions and 18 deletions

View file

@ -2,6 +2,7 @@
* 2.6.next in progress * 2.6.next in progress
* Fix [#549](https://github.com/seancorfield/honeysql/issues/549) by using `:bb` conditionals to support Babashka (and still support Clojure 1.9.0), and add testing against Babashka so it is fully-supported as a target via PR [#550](https://github.com/seancorfield/honeysql/pull/550) [@borkdude](https://github.com/borkdude) * Fix [#549](https://github.com/seancorfield/honeysql/issues/549) by using `:bb` conditionals to support Babashka (and still support Clojure 1.9.0), and add testing against Babashka so it is fully-supported as a target via PR [#550](https://github.com/seancorfield/honeysql/pull/550) [@borkdude](https://github.com/borkdude)
* Address [#532](https://github.com/seancorfield/honeysql/issues/532) by adding support for `EXCLUDE` and `RENAME` and starting to write tests for XTDB compatibility.
* 2.6.1203 -- 2024-10-22 * 2.6.1203 -- 2024-10-22
* Fix [#548](https://github.com/seancorfield/honeysql/issues/548) which was a regression introduced in [#526](https://github.com/seancorfield/honeysql/issues/526) (in 2.6.1161). * Fix [#548](https://github.com/seancorfield/honeysql/issues/548) which was a regression introduced in [#526](https://github.com/seancorfield/honeysql/issues/526) (in 2.6.1161).

View file

@ -58,7 +58,7 @@
:raw :nest :with :with-recursive :intersect :union :union-all :except :except-all :raw :nest :with :with-recursive :intersect :union :union-all :except :except-all
:table :table
:select :select-distinct :select-distinct-on :select-top :select-distinct-top :select :select-distinct :select-distinct-on :select-top :select-distinct-top
:distinct :expr :distinct :expr :exclude :rename
:into :bulk-collect-into :into :bulk-collect-into
:insert-into :replace-into :update :delete :delete-from :truncate :insert-into :replace-into :update :delete :delete-from :truncate
:columns :set :from :using :columns :set :from :using
@ -775,28 +775,34 @@
(let [[sqls params] (format-expr-list xs {:drop-ns true})] (let [[sqls params] (format-expr-list xs {:drop-ns true})]
(into [(str "(" (join ", " sqls) ")")] params)))) (into [(str "(" (join ", " sqls) ")")] params))))
(defn- format-selects-common [prefix as xs] (defn- format-selects-common
([prefix as xs] (format-selects-common prefix as xs nil))
([prefix as xs wrap]
(let [qualifier (format-meta xs) (let [qualifier (format-meta xs)
prefix (if prefix prefix (if prefix
(cond-> prefix qualifier (str " " qualifier)) (cond-> prefix qualifier (str " " qualifier))
qualifier)] qualifier)
[pre post] (when (and wrap (sequential? xs) (< 1 (count xs)))
["(" ")"])]
(if (sequential? xs) (if (sequential? xs)
(let [[sqls params] (reduce-sql (map #(format-selectable-dsl % {:as as})) xs)] (let [[sqls params] (reduce-sql (map #(format-selectable-dsl % {:as as})) xs)]
(when-not (= :none *checking*) (when-not (= :none *checking*)
(when (empty? xs) (when (empty? xs)
(throw (ex-info (str prefix " empty column list is illegal") (throw (ex-info (str prefix " empty column list is illegal")
{:clause (into [prefix] xs)})))) {:clause (into [prefix] xs)}))))
(into [(str (when prefix (str prefix " ")) (join ", " sqls))] params)) (into [(str (when prefix (str prefix " ")) pre (join ", " sqls) post)] params))
(let [[sql & params] (format-selectable-dsl xs {:as as})] (let [[sql & params] (format-selectable-dsl xs {:as as})]
(into [(str (when prefix (str prefix " ")) sql)] params))))) (into [(str (when prefix (str prefix " ")) sql)] params))))))
(defn- format-selects [k xs] (defn- format-selects [k xs]
(format-selects-common (format-selects-common
(sql-kw k) (sql-kw k)
(#{:select :select-distinct :from :window :delete-from :facet (#{:select :select-distinct :rename :from :window :delete-from :facet
'select 'select-distinct 'from 'window 'delete-from 'facet} 'select 'select-distinct 'rename 'from 'window 'delete-from 'facet
}
k) k)
xs)) xs
(#{:exclude :rename 'exclude 'rename} k)))
(defn- format-selects-on [_ xs] (defn- format-selects-on [_ xs]
(let [[on & cols] xs (let [[on & cols] xs
@ -1610,6 +1616,8 @@
:select-distinct-on #'format-selects-on :select-distinct-on #'format-selects-on
:select-top #'format-select-top :select-top #'format-select-top
:select-distinct-top #'format-select-top :select-distinct-top #'format-select-top
:exclude #'format-selects
:rename #'format-selects
:distinct (fn [k xs] (format-selects k [[xs]])) :distinct (fn [k xs] (format-selects k [[xs]]))
:expr (fn [_ xs] (format-selects nil [[xs]])) :expr (fn [_ xs] (format-selects nil [[xs]]))
:into #'format-select-into :into #'format-select-into

View file

@ -508,6 +508,16 @@
[& args] [& args]
(generic-1 :expr args)) (generic-1 :expr args))
(defn exclude
"Accepts one or more column names to exclude from a select list."
[& args]
(generic :exclude args))
(defn rename
"Accepts one or more column names with aliases to rename in a select list."
[& args]
(generic :rename args))
(defn into (defn into
"Accepts table name, optionally followed a database name." "Accepts table name, optionally followed a database name."
{:arglists '([table] [table dbname])} {:arglists '([table] [table dbname])}

View file

@ -0,0 +1,34 @@
;; copyright (c) 2020-2024 sean corfield, all rights reserved
(ns honey.sql.xtdb-test
(:require [clojure.test :refer [deftest is testing]]
[honey.sql :as sql]
[honey.sql.helpers :as h
:refer [select exclude rename from where]]))
(deftest select-tests
(testing "select, exclude, rename"
(is (= ["SELECT * EXCLUDE _id RENAME value AS foo_value FROM foo"]
(sql/format (-> (select :*) (exclude :_id) (rename [:value :foo_value])
(from :foo)))))
(is (= ["SELECT * EXCLUDE (_id, a) RENAME value AS foo_value FROM foo"]
(sql/format (-> (select :*) (exclude :_id :a) (rename [:value :foo_value])
(from :foo)))))
(is (= ["SELECT * EXCLUDE _id RENAME (value AS foo_value, a AS b) FROM foo"]
(sql/format (-> (select :*) (exclude :_id)
(rename [:value :foo_value]
[:a :b])
(from :foo))))))
(testing "select, nest_one, nest_many"
(is (= ["SELECT a._id, NEST_ONE (SELECT * FROM foo AS b WHERE b_id = a._id) FROM bar AS a"]
(sql/format '{select (a._id,
((nest_one {select * from ((foo b)) where (= b_id a._id)})))
from ((bar a))})))
(is (= ["SELECT a._id, NEST_MANY (SELECT * FROM foo AS b) FROM bar AS a"]
(sql/format '{select (a._id,
((nest_many {select * from ((foo b))})))
from ((bar a))})))))
(deftest dotted-array-access-tests
(is (= ["SELECT (a.b).c"]
(sql/format '{select (((. (nest :a.b) :c)))}))))