diff --git a/README.md b/README.md index 5c7c44a..6f9d441 100644 --- a/README.md +++ b/README.md @@ -222,13 +222,12 @@ VALUES (?, (?, ?)), (?, (?, ?)) ### Updates -Updates are possible too (note the double S in `sset` to avoid clashing -with `clojure.core/set`): +Updates are possible too: ```clojure (-> (helpers/update :films) - (sset {:kind "dramatic" - :watched (sql/call :+ :watched 1)}) + (set {:kind "dramatic" + :watched [:+ :watched 1]}) (where [:= :kind "drama"]) (sql/format {:pretty? true})) => [" @@ -329,16 +328,16 @@ to identify inline parameter values, and how to add in raw SQL fragments! (def call-qualify-map (-> (select [[:foo :bar]] [[:raw "@var := foo.bar"]]) (from :foo) - (where [:= :a (???/param :baz)] [:= :b [:inline 42]]))) + (where [:= :a [:param :baz]] [:= :b [:inline 42]]))) ``` ```clojure call-qualify-map -=> '{:where [:and [:= :a ???/param :baz] [:= :b [:inline 42]]] +=> '{:where [:and [:= :a [:param :baz]] [:= :b [:inline 42]]] :from (:foo) :select [[[:foo :bar]] [[:raw "@var := foo.bar"]]]} ``` ```clojure -(sql/format call-qualify-map :??? {:baz "BAZ"}) +(sql/format call-qualify-map {:params {:baz "BAZ"}}) => ["SELECT foo(bar), @var := foo.bar FROM foo WHERE (a = ?) AND (b = 42)" "BAZ"] ``` @@ -370,13 +369,13 @@ will not be lifted out as parameters, so they end up in the SQL string as-is. Raw SQL can also be supplied as a vector of strings and values. Strings are rendered as-is into the formatted SQL string. Non-strings are lifted as -parameters. If you need a string parameter lifted, you must use `#sql/param` +parameters. If you need a string parameter lifted, you must use `:param` or the `param` helper. ```clojure (-> (select :*) (from :foo) - (where [:< :expired_at (sql/raw ["now() - '" 5 " seconds'"])]) + (where [:< :expired_at [:raw ["now() - '" 5 " seconds'"]]]) (sql/format {:foo 5})) => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] ``` @@ -384,7 +383,7 @@ or the `param` helper. ```clojure (-> (select :*) (from :foo) - (where [:< :expired_at (sql/raw ["now() - '" #sql/param :t " seconds'"])]) + (where [:< :expired_at [:raw ["now() - '" [:param :t] " seconds'"]]]) (sql/format {:t 5})) => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] ``` @@ -450,9 +449,9 @@ Here's a big, complicated query. Note that Honey SQL makes no attempt to verify (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)]] + [:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]] [:< 1 2 3] - [:in :f.e [1 (???/param :param2) 3]] + [:in :f.e [1 [:param :param2] 3]] [:between :f.e 10 20]]) (group :f.a :c.e) (having [:< 0 :f.e]) @@ -470,9 +469,9 @@ big-complicated-map :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)]] + [:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]] [:< 1 2 3] - [:in :f.e [1 (????/param :param2) 3]] + [:in :f.e [1 [:param :param2] 3]] [:between :f.e 10 20]] :group-by [:f.a :c.e] :having [:< 0 :f.e] diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index f53c700..138899c 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -17,7 +17,7 @@ "The (default) order for known clauses. Can have items added and removed." [:with :with-recursive :intersect :union :union-all :except :except-all :select :insert-into :update :delete :delete-from :truncate - :columns :set :from + :columns :composite :set :from :join :left-join :right-join :inner-join :outer-join :full-join :cross-join :where :group-by :having :order-by :limit :offset :values @@ -169,8 +169,8 @@ [[] []] (map #(format-expr % opts) xs))) -(defn- format-columns [_ xs] - (let [[sqls params] (format-expr-list xs {:drop-ns? true})] +(defn- format-columns [k xs] + (let [[sqls params] (format-expr-list xs {:drop-ns? (= :columns k)})] (into [(str "(" (str/join ", " sqls) ")")] params))) (defn- format-selects [k xs] @@ -340,6 +340,7 @@ :delete-from #'format-selector :truncate #'format-selector :columns #'format-columns + :composite #'format-columns :set #'format-set-exprs :from #'format-selects :join #'format-join diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc index e147cc2..dd2ed59 100644 --- a/src/honey/sql/helpers.cljc +++ b/src/honey/sql/helpers.cljc @@ -40,6 +40,7 @@ (defn delete-from [& args] (generic :delete-from args)) (defn truncate [& args] (generic :truncate args)) (defn columns [& args] (generic :columns args)) +(defn composite [& args] (generic :composite args)) (defn set [& args] (generic :set args)) (defn from [& args] (generic :from args)) (defn join [& args] (generic :join args)) diff --git a/src/readme.clj b/src/readme.clj index b996a51..f9f7e46 100644 --- a/src/readme.clj +++ b/src/readme.clj @@ -224,11 +224,10 @@ VALUES (?, (?, ?)), (?, (?, ?)) - -(seancorfield.readme/defreadme readme-228 +(seancorfield.readme/defreadme readme-227 (-> (helpers/update :films) - (sset {:kind "dramatic" - :watched (sql/call :+ :watched 1)}) + (set {:kind "dramatic" + :watched [:+ :watched 1]}) (where [:= :kind "drama"]) (sql/format {:pretty? true})) => [" @@ -251,7 +250,7 @@ WHERE kind = ? -(seancorfield.readme/defreadme readme-254 +(seancorfield.readme/defreadme readme-253 (-> (delete-from :films) (where [:<> :kind "musical"]) (sql/format)) @@ -260,7 +259,7 @@ WHERE kind = ? -(seancorfield.readme/defreadme readme-263 +(seancorfield.readme/defreadme readme-262 (-> (delete [:films :directors]) (from :films) (join :directors [:= :films.director_id :directors.id]) @@ -277,7 +276,7 @@ WHERE kind <> ? -(seancorfield.readme/defreadme readme-280 +(seancorfield.readme/defreadme readme-279 (-> (truncate :films) (sql/format)) => ["TRUNCATE films"] @@ -287,7 +286,7 @@ WHERE kind <> ? -(seancorfield.readme/defreadme readme-290 +(seancorfield.readme/defreadme readme-289 (sql/format {:union [(-> (select :*) (from :foo)) (-> (select :*) (from :bar))]}) => ["SELECT * FROM foo UNION SELECT * FROM bar"] @@ -297,11 +296,11 @@ WHERE kind <> ? -(seancorfield.readme/defreadme readme-300 +(seancorfield.readme/defreadme readme-299 (-> (select :%count.*) (from :foo) sql/format) => ["SELECT count(*) FROM foo"] ) -(seancorfield.readme/defreadme readme-304 +(seancorfield.readme/defreadme readme-303 (-> (select :%max.id) (from :foo) sql/format) => ["SELECT max(id) FROM foo"] ) @@ -312,7 +311,7 @@ WHERE kind <> ? -(seancorfield.readme/defreadme readme-315 +(seancorfield.readme/defreadme readme-314 (-> (select :id) (from :foo) (where [:= :a :?baz]) @@ -325,20 +324,20 @@ WHERE kind <> ? -(seancorfield.readme/defreadme readme-328 +(seancorfield.readme/defreadme readme-327 (def call-qualify-map (-> (select [[:foo :bar]] [[:raw "@var := foo.bar"]]) (from :foo) - (where [:= :a (???/param :baz)] [:= :b [:inline 42]]))) + (where [:= :a [:param :baz]] [:= :b [:inline 42]]))) ) -(seancorfield.readme/defreadme readme-334 +(seancorfield.readme/defreadme readme-333 call-qualify-map -=> '{:where [:and [:= :a ???/param :baz] [:= :b [:inline 42]]] +=> '{:where [:and [:= :a [:param :baz]] [:= :b [:inline 42]]] :from (:foo) :select [[[:foo :bar]] [[:raw "@var := foo.bar"]]]} ) -(seancorfield.readme/defreadme readme-340 -(sql/format call-qualify-map :??? {:baz "BAZ"}) +(seancorfield.readme/defreadme readme-339 +(sql/format call-qualify-map {:params {:baz "BAZ"}}) => ["SELECT foo(bar), @var := foo.bar FROM foo WHERE (a = ?) AND (b = 42)" "BAZ"] ) @@ -347,7 +346,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-350 +(seancorfield.readme/defreadme readme-349 (-> (insert-into :sample) (values [{:location [:ST_SetSRID [:ST_MakePoint 0.291 32.621] @@ -373,18 +372,18 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) -(seancorfield.readme/defreadme readme-376 +(seancorfield.readme/defreadme readme-375 (-> (select :*) (from :foo) - (where [:< :expired_at (sql/raw ["now() - '" 5 " seconds'"])]) + (where [:< :expired_at [:raw ["now() - '" 5 " seconds'"]]]) (sql/format {:foo 5})) => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] ) -(seancorfield.readme/defreadme readme-384 +(seancorfield.readme/defreadme readme-383 (-> (select :*) (from :foo) - (where [:< :expired_at (sql/raw ["now() - '" #sql/param :t " seconds'"])]) + (where [:< :expired_at [:raw ["now() - '" [:param :t] " seconds'"]]]) (sql/format {:t 5})) => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] ) @@ -398,7 +397,7 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) -(seancorfield.readme/defreadme readme-401 +(seancorfield.readme/defreadme readme-400 (-> (select :foo.a) (from :foo) (where [:= :foo.a "baz"]) @@ -414,7 +413,7 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) -(seancorfield.readme/defreadme readme-417 +(seancorfield.readme/defreadme readme-416 (-> (select :foo.a) (from :foo) (where [:= :foo.a "baz"]) @@ -426,7 +425,7 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) -(seancorfield.readme/defreadme readme-429 +(seancorfield.readme/defreadme readme-428 (sql/format {:select [:f.foo-id :f.foo-name] :from [[:foo-bar :f]] @@ -440,7 +439,7 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) -(seancorfield.readme/defreadme readme-443 +(seancorfield.readme/defreadme readme-442 (def big-complicated-map (-> (select :f.* :b.baz :c.quux [:b.bla "bla-bla"] [[:now]] [[:raw "@x := 10"]]) @@ -450,9 +449,9 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) (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)]] + [:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]] [:< 1 2 3] - [:in :f.e [1 (???/param :param2) 3]] + [:in :f.e [1 [:param :param2] 3]] [:between :f.e 10 20]]) (group :f.a :c.e) (having [:< 0 :f.e]) @@ -460,7 +459,7 @@ VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) (limit 50) (offset 10))) ) -(seancorfield.readme/defreadme readme-463 +(seancorfield.readme/defreadme readme-462 big-complicated-map => {:select [:f.* :b.baz :c.quux [:b.bla "bla-bla"] [[:now]] [[:raw "@x := 10"]]] @@ -470,9 +469,9 @@ big-complicated-map :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)]] + [:and [:= :f.a "bort"] [:not= :b.baz [:param :param1]]] [:< 1 2 3] - [:in :f.e [1 (????/param :param2) 3]] + [:in :f.e [1 [:param :param2] 3]] [:between :f.e 10 20]] :group-by [:f.a :c.e] :having [:< 0 :f.e] @@ -480,7 +479,7 @@ big-complicated-map :limit 50 :offset 10} ) -(seancorfield.readme/defreadme readme-483 +(seancorfield.readme/defreadme readme-482 (sql/format big-complicated-map {:param1 "gabba" :param2 2}) => [" SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS bla_bla, now(), @x := 10 @@ -497,7 +496,7 @@ OFFSET ? " "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10] ) -(seancorfield.readme/defreadme readme-500 +(seancorfield.readme/defreadme readme-499 ;; Printable and readable (= big-complicated-map (read-string (pr-str big-complicated-map))) => true @@ -509,7 +508,7 @@ OFFSET ? -(seancorfield.readme/defreadme readme-512 +(seancorfield.readme/defreadme readme-511 (defmethod fmt/fn-handler "betwixt" [_ field lower upper] (str (fmt/to-sql field) " BETWIXT " (fmt/to-sql lower) " AND " (fmt/to-sql upper))) @@ -520,23 +519,23 @@ OFFSET ? -(seancorfield.readme/defreadme readme-523 +(seancorfield.readme/defreadme readme-522 ;; 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-528 +(seancorfield.readme/defreadme readme-527 (sql/format {:select [:a :b] :foobar :baz}) => ["SELECT a, b FOOBAR baz"] ) -(seancorfield.readme/defreadme readme-532 +(seancorfield.readme/defreadme readme-531 (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-539 +(seancorfield.readme/defreadme readme-538 (-> (select :a :b) (foobar :baz) sql/format) => ["SELECT a, b FOOBAR baz"] @@ -544,7 +543,7 @@ OFFSET ? -(seancorfield.readme/defreadme readme-547 +(seancorfield.readme/defreadme readme-546 (fmt/register-clause! :foobar 110) )