Documented extension mechanism; updated README
Helpers are the next big piece of work.
This commit is contained in:
parent
97a3782112
commit
a83998d354
3 changed files with 58 additions and 642 deletions
89
README.md
89
README.md
|
|
@ -522,58 +522,81 @@ OFFSET ?
|
|||
|
||||
## Extensibility
|
||||
|
||||
_This needs a rewrite!_
|
||||
Any keyword (or symbol) that appears as the first element of a vector will be treated as a generic function unless it is declared to be an operator or "special syntax". Any keyword (or symbol) that appears as a key in a hash map will be treated as a SQL clause -- and must either be built-in or must be registered as new clauses.
|
||||
|
||||
You can define your own function handlers for use in `where`:
|
||||
If your database supports `<=>` as an operator, you can tell HoneySQL about it using the `register-op!` function (which should be called before the first call to `honey.sql/format`):
|
||||
|
||||
```clojure
|
||||
(defmethod fmt/fn-handler "betwixt" [_ field lower upper]
|
||||
(str (fmt/to-sql field) " BETWIXT "
|
||||
(fmt/to-sql lower) " AND " (fmt/to-sql upper)))
|
||||
(sql/register-op! :<=>)
|
||||
;; default is a binary operator:
|
||||
(-> (select :a) (where [:<=> :a "foo"]) sql/format)
|
||||
=> ["SELECT a WHERE a <=> ?" "foo"]
|
||||
;; you can declare that an operator is variadic:
|
||||
(sql/register-op! :<=> :variadic? true)
|
||||
(-> (select :a) (where [:<=> "food" :a "fool"]) sql/format)
|
||||
=> ["SELECT a WHERE ? <=> a <=> ?" "food" "fool"]
|
||||
```
|
||||
|
||||
Sometimes you want an operator to ignore `nil` clauses (`:and` and `:or` are declared that way):
|
||||
|
||||
```clojure
|
||||
(sql/register-op! :<=> :ignore-nil? true)
|
||||
```
|
||||
|
||||
Or perhaps your database supports syntax like `a BETWIXT b AND c`, in which case you can use `register-fn!` to tell HoneySQL about it (again, called before the first call to `honey.sql/format`):
|
||||
|
||||
```clojure
|
||||
;; the formatter will be passed your new operator (function) and a
|
||||
;; sequence of the arguments provided to it (so you can write any arity ops):
|
||||
(sql/register-fn! :betwixt
|
||||
(fn [op [a b c]]
|
||||
(let [[sql-a & params-a] (sql/format-expr a)
|
||||
[sql-b & params-b] (sql/format-expr b)
|
||||
[sql-c & params-c] (sql/format-expr c)]
|
||||
(-> [(str sql-a " " (sql/sql-kw op) " "
|
||||
sql-b " AND " sql-c)]
|
||||
(into params-a)
|
||||
(into params-b)
|
||||
(into params-c)))))
|
||||
;; example usage:
|
||||
(-> (select :a) (where [:betwixt :a 1 10]) sql/format)
|
||||
=> ["SELECT a WHERE a BETWIXT ? AND ?" 1 10]
|
||||
```
|
||||
|
||||
You can also define your own clauses:
|
||||
You can also register SQL clauses, specifying the keyword, the formatting function, and an existing clause that this new clause should be processed before:
|
||||
|
||||
```clojure
|
||||
;; Takes a MapEntry of the operator & clause data, plus the entire SQL map
|
||||
(defmethod fmt/format-clause :foobar [[op v] sqlmap]
|
||||
(str "FOOBAR " (fmt/to-sql v)))
|
||||
```
|
||||
```clojure
|
||||
;; the formatter will be passed your new clause and the value associated
|
||||
;; with that clause in the DSL (which is often a sequence but does not
|
||||
;; need to be -- it can be whatever syntax you desire in the DSL):
|
||||
(sql/register-clause! :foobar
|
||||
(fn [clause x]
|
||||
(let [[sql & params]
|
||||
(if (keyword? x)
|
||||
(sql/format-expr x)
|
||||
(sql/format-dsl x))]
|
||||
(into [(str (sql/sql-kw clause) " " sql)] params)))
|
||||
:from) ; SELECT ... FOOBAR ... FROM ...
|
||||
;; example usage:
|
||||
(sql/format {:select [:a :b] :foobar :baz})
|
||||
=> ["SELECT a, b FOOBAR baz"]
|
||||
```
|
||||
```clojure
|
||||
(require '[honeysql.helpers :refer [defhelper]])
|
||||
|
||||
;; Defines a helper function, and allows 'build' to recognize your clause
|
||||
(defhelper foobar [m args]
|
||||
(assoc m :foobar (first args)))
|
||||
```
|
||||
```clojure
|
||||
(-> (select :a :b) (foobar :baz) sql/format)
|
||||
=> ["SELECT a, b FOOBAR baz"]
|
||||
|
||||
(sql/format {:select [:a :b] :foobar {:where [:= :id 1]}})
|
||||
=> ["SELECT a, b FOOBAR WHERE id = ?" 1]
|
||||
```
|
||||
|
||||
When adding a new clause, you may also need to register it with a specific priority so that it formats correctly, for example:
|
||||
|
||||
```clojure
|
||||
(fmt/register-clause! :foobar 110)
|
||||
```
|
||||
|
||||
If you do implement a clause or function handler for an ANSI SQL, consider submitting a pull request so others can use it, too. For non-standard clauses and/or functions, look for a library that extends `honeysql` for that specific database or create one, if no such library exists.
|
||||
If you find yourself registering an operator, a function (syntax), or a new clause, consider submitting a [pull request to HoneySQL](https://github.com/seancorfield/honeysql/pulls) so others can use it, too. If it is dialect-specific, let me know in the pull request.
|
||||
|
||||
## Why does my parameter get emitted as `()`?
|
||||
|
||||
_Need to investigate whether this is still true in 2.0!_
|
||||
|
||||
If you want to use your own datatype as a parameter then the idiomatic approach of implementing
|
||||
`next.jdbc`'s [`SettableParameter`](https://cljdoc.org/d/seancorfield/next.jdbc/CURRENT/api/next.jdbc.prepare#SettableParameter)
|
||||
or `clojure.java.jdbc`'s [`ISQLValue`](https://clojure.github.io/java.jdbc/#clojure.java.jdbc/ISQLValue) protocol isn't enough as `honeysql` won't correct pass through your datatype, rather it will interpret it incorrectly.
|
||||
or `clojure.java.jdbc`'s [`ISQLValue`](https://clojure.github.io/java.jdbc/#clojure.java.jdbc/ISQLValue) protocol isn't enough as HoneySQL won't correct pass through your datatype, rather it will interpret it incorrectly.
|
||||
|
||||
To teach `honeysql` how to handle your datatype you need to implement [`honeysql.format/ToSql`](https://github.com/seancorfield/honeysql/blob/a9dffec632be62c961be7d9e695d0b2b85732c53/src/honeysql/format.cljc#L94). For example:
|
||||
_This bit no longer exists:_
|
||||
|
||||
To teach HoneySQL how to handle your datatype you need to implement [`honeysql.format/ToSql`](https://github.com/seancorfield/honeysql/blob/a9dffec632be62c961be7d9e695d0b2b85732c53/src/honeysql/format.cljc#L94). For example:
|
||||
``` clojure
|
||||
;; given:
|
||||
(defrecord MyDateWrapper [...]
|
||||
|
|
@ -599,7 +622,7 @@ To teach `honeysql` how to handle your datatype you need to implement [`honeysql
|
|||
|
||||
## Extensions
|
||||
|
||||
* [For PostgreSQL-specific extensions falling outside of ANSI SQL](https://github.com/nilenso/honeysql-postgres)
|
||||
* [For PostgreSQL-specific extensions falling outside of ANSI SQL](https://github.com/nilenso/honeysql-postgres) -- these will all be core in 2.0!
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
#?(:clj (fn [^String s] (.. s toString (toUpperCase (java.util.Locale/US))))
|
||||
:cljs str/upper-case))
|
||||
|
||||
(defn- sql-kw [k]
|
||||
(defn sql-kw [k]
|
||||
(-> k (name) (upper-case) (str/replace "-" " ")))
|
||||
|
||||
(defn- format-entity [x & [{:keys [aliased? drop-ns?]}]]
|
||||
|
|
@ -444,7 +444,7 @@
|
|||
;; ;do-nothing
|
||||
;:returning
|
||||
|
||||
(defn- format-dsl [x & [{:keys [aliased? nested? pretty?]}]]
|
||||
(defn format-dsl [x & [{:keys [aliased? nested? pretty?]}]]
|
||||
(let [[sqls params leftover]
|
||||
(reduce (fn [[sql params leftover] k]
|
||||
(if-let [xs (or (k x) (let [s (symbol (name k))] (get x s)))]
|
||||
|
|
|
|||
607
src/readme.clj
607
src/readme.clj
|
|
@ -1,607 +0,0 @@
|
|||
(ns readme (:require [seancorfield.readme]))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-25
|
||||
(refer-clojure :exclude '[for group-by set update])
|
||||
(require '[honey.sql :as sql]
|
||||
;; caution: this overwrites for, group-by, set, and update
|
||||
'[honey.sql.helpers :refer :all :as helpers])
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-34
|
||||
(def sqlmap {:select [:a :b :c]
|
||||
:from [:foo]
|
||||
:where [:= :f.a "baz"]})
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-46
|
||||
(sql/format sqlmap)
|
||||
=> ["SELECT a, b, c FROM foo WHERE f.a = ?" "baz"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-67
|
||||
(def q-sqlmap {:select [:foo/a :foo/b :foo/c]
|
||||
:from [:foo]
|
||||
:where [:= :foo/a "baz"]})
|
||||
(sql/format q-sqlmap)
|
||||
=> ["SELECT foo.a, foo.b, foo.c FROM foo WHERE foo.a = ?" "baz"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-81
|
||||
(-> (select :a :b :c)
|
||||
(from :foo)
|
||||
(where [:= :f.a "baz"]))
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-89
|
||||
(= (-> (select :*) (from :foo))
|
||||
(-> (from :foo) (select :*)))
|
||||
=> true
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-97
|
||||
(-> sqlmap (select :d))
|
||||
=> '{:from [:foo], :where [:= :f.a "baz"], :select [:a :b :c :d]}
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-104
|
||||
(-> sqlmap
|
||||
(dissoc :select)
|
||||
(select :*)
|
||||
(where [:> :b 10])
|
||||
sql/format)
|
||||
=> ["SELECT * FROM foo WHERE (f.a = ?) AND (b > ?)" "baz" 10]
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-115
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(where [:= :a 1] [:< :b 100])
|
||||
sql/format)
|
||||
=> ["SELECT * FROM foo WHERE (a = ?) AND (b < ?)" 1 100]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-126
|
||||
(-> (select :a [:b :bar] :c [:d :x])
|
||||
(from [:foo :quux])
|
||||
(where [:= :quux.a 1] [:< :bar 100])
|
||||
sql/format)
|
||||
=> ["SELECT a, b AS bar, c, d AS x FROM foo quux WHERE (quux.a = ?) AND (bar < ?)" 1 100]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-143
|
||||
(-> (insert-into :properties)
|
||||
(columns :name :surname :age)
|
||||
(values
|
||||
[["Jon" "Smith" 34]
|
||||
["Andrew" "Cooper" 12]
|
||||
["Jane" "Daniels" 56]])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
INSERT INTO properties (name, surname, age)
|
||||
VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)
|
||||
"
|
||||
"Jon" "Smith" 34 "Andrew" "Cooper" 12 "Jane" "Daniels" 56]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-162
|
||||
(-> (insert-into :properties)
|
||||
(values [{:name "John" :surname "Smith" :age 34}
|
||||
{:name "Andrew" :surname "Cooper" :age 12}
|
||||
{:name "Jane" :surname "Daniels" :age 56}])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
INSERT INTO properties (name, surname, age)
|
||||
VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)
|
||||
"
|
||||
"John" "Smith" 34
|
||||
"Andrew" "Cooper" 12
|
||||
"Jane" "Daniels" 56]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-181
|
||||
(let [user-id 12345
|
||||
role-name "user"]
|
||||
(-> (insert-into :user_profile_to_role)
|
||||
(values [{:user_profile_id user-id
|
||||
:role_id (-> (select :id)
|
||||
(from :role)
|
||||
(where [:= :name role-name]))}])
|
||||
(sql/format {:pretty? true})))
|
||||
|
||||
=> ["
|
||||
INSERT INTO user_profile_to_role (user_profile_id, role_id)
|
||||
VALUES (?, (SELECT id FROM role WHERE name = ?))
|
||||
"
|
||||
12345
|
||||
"user"]
|
||||
)
|
||||
|
||||
(seancorfield.readme/defreadme readme-199
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(where [:in :foo.a (-> (select :a) (from :bar))])
|
||||
sql/format)
|
||||
=> ["SELECT * FROM foo WHERE (foo.a in (SELECT a FROM bar))"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-211
|
||||
(-> (insert-into :comp_table)
|
||||
(columns :name :comp_column)
|
||||
(values
|
||||
[["small" (composite 1 "inch")]
|
||||
["large" (composite 10 "feet")]])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
INSERT INTO comp_table (name, comp_column)
|
||||
VALUES (?, (?, ?)), (?, (?, ?))
|
||||
"
|
||||
"small" 1 "inch" "large" 10 "feet"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-229
|
||||
(-> (helpers/update :films)
|
||||
(set {:kind "dramatic"
|
||||
:watched [:+ :watched 1]})
|
||||
(where [:= :kind "drama"])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
UPDATE films SET kind = ?, watched = (watched + ?)
|
||||
WHERE kind = ?
|
||||
"
|
||||
"dramatic"
|
||||
1
|
||||
"drama"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-255
|
||||
(-> (delete-from :films)
|
||||
(where [:<> :kind "musical"])
|
||||
(sql/format))
|
||||
=> ["DELETE FROM films WHERE kind <> ?" "musical"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-264
|
||||
(-> (delete [:films :directors])
|
||||
(from :films)
|
||||
(join :directors [:= :films.director_id :directors.id])
|
||||
(where [:<> :kind "musical"])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
DELETE films, directors
|
||||
FROM films
|
||||
INNER JOIN directors ON films.director_id = directors.id
|
||||
WHERE kind <> ?
|
||||
"
|
||||
"musical"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-281
|
||||
(-> (truncate :films)
|
||||
(sql/format))
|
||||
=> ["TRUNCATE films"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-291
|
||||
(sql/format {:union [(-> (select :*) (from :foo))
|
||||
(-> (select :*) (from :bar))]})
|
||||
=> ["SELECT * FROM foo UNION SELECT * FROM bar"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-301
|
||||
(-> (select :%count.*) (from :foo) sql/format)
|
||||
=> ["SELECT count(*) FROM foo"]
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-305
|
||||
(-> (select :%max.id) (from :foo) sql/format)
|
||||
=> ["SELECT max(id) FROM foo"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-316
|
||||
(-> (select :id)
|
||||
(from :foo)
|
||||
(where [:= :a :?baz])
|
||||
(sql/format {:params {:baz "BAZ"}}))
|
||||
=> ["SELECT id FROM foo WHERE (a = ?)" "BAZ"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-329
|
||||
(def call-qualify-map
|
||||
(-> (select [[:foo :bar]] [[:raw "@var := foo.bar"]])
|
||||
(from :foo)
|
||||
(where [:= :a [:param :baz]] [:= :b [:inline 42]])))
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-335
|
||||
call-qualify-map
|
||||
=> '{:where [:and [:= :a [:param :baz]] [:= :b [:inline 42]]]
|
||||
:from (:foo)
|
||||
:select [[[:foo :bar]] [[:raw "@var := foo.bar"]]]}
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-341
|
||||
(sql/format call-qualify-map {:params {:baz "BAZ"}})
|
||||
=> ["SELECT foo(bar), @var := foo.bar FROM foo WHERE (a = ?) AND (b = 42)" "BAZ"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-351
|
||||
(-> (insert-into :sample)
|
||||
(values [{:location [:ST_SetSRID
|
||||
[:ST_MakePoint 0.291 32.621]
|
||||
[:cast 4325 :integer]]}])
|
||||
(sql/format {:pretty? true}))
|
||||
=> ["
|
||||
INSERT INTO sample (location)
|
||||
VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer)))
|
||||
"
|
||||
0.291 32.621 4326]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-377
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(where [:< :expired_at [:raw ["now() - '" 5 " seconds'"]]])
|
||||
(sql/format {:foo 5}))
|
||||
=> ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5]
|
||||
)
|
||||
|
||||
(seancorfield.readme/defreadme readme-385
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(where [:< :expired_at [:raw ["now() - '" [:param :t] " seconds'"]]])
|
||||
(sql/format {:t 5}))
|
||||
=> ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-402
|
||||
(-> (select :foo.a)
|
||||
(from :foo)
|
||||
(where [:= :foo.a "baz"])
|
||||
(sql/format {:dialect :mysql}))
|
||||
=> ["SELECT `foo`.`a` FROM `foo` WHERE `foo`.`a` = ?" "baz"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-426
|
||||
(-> (select :foo.a)
|
||||
(from :foo)
|
||||
(where [:= :foo.a "baz"])
|
||||
(for :update)
|
||||
(format))
|
||||
=> ["SELECT foo.a FROM foo WHERE (foo.a = ?) FOR UPDATE" "baz"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-437
|
||||
(sql/format {:select [:*] :from :foo
|
||||
:where [:= :name [:inline "Jones"]]
|
||||
:lock [:in-share-mode]}
|
||||
{:dialect :mysql :quoted false})
|
||||
=> ["SELECT * FROM foo WHERE name = 'Jones' LOCK IN SHARE MODE"]
|
||||
)
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-446
|
||||
(sql/format
|
||||
{:select [:f.foo-id :f.foo-name]
|
||||
:from [[:foo-bar :f]]
|
||||
:where [:= :f.foo-id 12345]}
|
||||
{:allow-dashed-names? true ; not implemented yet
|
||||
:quoted true})
|
||||
=> ["SELECT \"f\".\"foo-id\", \"f\".\"foo-name\" FROM \"foo-bar\" \"f\" WHERE \"f\".\"foo-id\" = ?" 12345]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-460
|
||||
(def big-complicated-map
|
||||
(-> (select :f.* :b.baz :c.quux [:b.bla "bla-bla"]
|
||||
[[:now]] [[:raw "@x := 10"]])
|
||||
#_(modifiers :distinct) ; this is not implemented yet
|
||||
(from [:foo :f] [:baz :b])
|
||||
(join :draq [:= :f.b :draq.x])
|
||||
(left-join [:clod :c] [:= :f.a :c.d])
|
||||
(right-join :bock [:= :bock.z :c.e])
|
||||
(where [:or
|
||||
[:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]]
|
||||
[:< 1 2 3]
|
||||
[:in :f.e [1 [:param :param2] 3]]
|
||||
[:between :f.e 10 20]])
|
||||
(group-by :f.a :c.e)
|
||||
(having [:< 0 :f.e])
|
||||
(order-by [:b.baz :desc] :c.quux [:f.a :nulls-first])
|
||||
(limit 50)
|
||||
(offset 10)))
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-480
|
||||
big-complicated-map
|
||||
=> {:select [:f.* :b.baz :c.quux [:b.bla "bla-bla"]
|
||||
[[:now]] [[:raw "@x := 10"]]]
|
||||
:modifiers [:distinct]
|
||||
:from [[:foo :f] [:baz :b]]
|
||||
:join [:draq [:= :f.b :draq.x]]
|
||||
:left-join [[:clod :c] [:= :f.a :c.d]]
|
||||
:right-join [:bock [:= :bock.z :c.e]]
|
||||
:where [:or
|
||||
[:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]]
|
||||
[:< 1 2 3]
|
||||
[:in :f.e [1 [:param :param2] 3]]
|
||||
[:between :f.e 10 20]]
|
||||
:group-by [:f.a :c.e]
|
||||
:having [:< 0 :f.e]
|
||||
:order-by [[:b.baz :desc] :c.quux [:f.a :nulls-first]]
|
||||
:limit 50
|
||||
:offset 10}
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-500
|
||||
(sql/format big-complicated-map {:param1 "gabba" :param2 2})
|
||||
=> ["
|
||||
SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS bla_bla, now(), @x := 10
|
||||
FROM foo f, baz b
|
||||
INNER JOIN draq ON f.b = draq.x
|
||||
LEFT JOIN clod c ON f.a = c.d
|
||||
RIGHT JOIN bock ON bock.z = c.e
|
||||
WHERE ((f.a = ? AND b.baz <> ?) OR (? < ? AND ? < ?) OR (f.e in (?, ?, ?)) OR f.e BETWEEN ? AND ?)
|
||||
GROUP BY f.a, c.e
|
||||
HAVING ? < f.e
|
||||
ORDER BY b.baz DESC, c.quux, f.a NULLS FIRST
|
||||
LIMIT ?
|
||||
OFFSET ?
|
||||
"
|
||||
"bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10]
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-517
|
||||
;; Printable and readable
|
||||
(= big-complicated-map (read-string (pr-str big-complicated-map)))
|
||||
=> true
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-529
|
||||
(defmethod fmt/fn-handler "betwixt" [_ field lower upper]
|
||||
(str (fmt/to-sql field) " BETWIXT "
|
||||
(fmt/to-sql lower) " AND " (fmt/to-sql upper)))
|
||||
|
||||
(-> (select :a) (where [:betwixt :a 1 10]) sql/format)
|
||||
=> ["SELECT a WHERE a BETWIXT ? AND ?" 1 10]
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-540
|
||||
;; Takes a MapEntry of the operator & clause data, plus the entire SQL map
|
||||
(defmethod fmt/format-clause :foobar [[op v] sqlmap]
|
||||
(str "FOOBAR " (fmt/to-sql v)))
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-545
|
||||
(sql/format {:select [:a :b] :foobar :baz})
|
||||
=> ["SELECT a, b FOOBAR baz"]
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-549
|
||||
(require '[honeysql.helpers :refer [defhelper]])
|
||||
|
||||
;; Defines a helper function, and allows 'build' to recognize your clause
|
||||
(defhelper foobar [m args]
|
||||
(assoc m :foobar (first args)))
|
||||
)
|
||||
(seancorfield.readme/defreadme readme-556
|
||||
(-> (select :a :b) (foobar :baz) sql/format)
|
||||
=> ["SELECT a, b FOOBAR baz"]
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
(seancorfield.readme/defreadme readme-564
|
||||
(fmt/register-clause! :foobar 110)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in a new issue