diff --git a/src/honey/sql/helpers.clj b/src/honey/sql/helpers.clj deleted file mode 100644 index 0363db8..0000000 --- a/src/honey/sql/helpers.clj +++ /dev/null @@ -1,6 +0,0 @@ -;; copyright (c) 2020 sean corfield, all rights reserved - -(ns honey.sql.helpers - "Macros to create consistent helpers from DSL clauses. - - I don't know how this will work in ClojureScript yet...") diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc new file mode 100644 index 0000000..e147cc2 --- /dev/null +++ b/src/honey/sql/helpers.cljc @@ -0,0 +1,67 @@ +;; copyright (c) 2020 sean corfield, all rights reserved + +(ns honey.sql.helpers + "Helper functions for the built-in clauses in honey.sql." + (:refer-clojure :exclude [update set group-by]) + (:require [honey.sql :as h])) + +(defn- default-merge [current args] + (into (vec current) args)) + +(def ^:private special-merges + {:where (fn [current args] + (if (= :and (first (first args))) + (default-merge current args) + (-> [:and] + (into current) + (into args))))}) + +(defn- helper-merge [data k args] + (let [merge-fn (special-merges k default-merge)] + (clojure.core/update data k merge-fn args))) + +(defn- generic [k args] + (if (map? (first args)) + (let [[data & args] args] + (helper-merge data k args)) + (helper-merge {} k args))) + +(defn with [& args] (generic :with args)) +(defn with-recursive [& args] (generic :with-recursive args)) +(defn intersect [& args] (generic :intersect args)) +(defn union [& args] (generic :union args)) +(defn union-all [& args] (generic :union-all args)) +(defn except [& args] (generic :except args)) +(defn except-all [& args] (generic :except-all args)) +(defn select [& args] (generic :select args)) +(defn insert-into [& args] (generic :insert-into args)) +(defn update [& args] (generic :update args)) +(defn delete [& args] (generic :delete args)) +(defn delete-from [& args] (generic :delete-from args)) +(defn truncate [& args] (generic :truncate args)) +(defn columns [& args] (generic :columns args)) +(defn set [& args] (generic :set args)) +(defn from [& args] (generic :from args)) +(defn join [& args] (generic :join args)) +(defn left-join [& args] (generic :left-join args)) +(defn right-join [& args] (generic :right-join args)) +(defn inner-join [& args] (generic :inner-join args)) +(defn outer-join [& args] (generic :outer-join args)) +(defn full-join [& args] (generic :full-join args)) +(defn cross-join [& args] (generic :cross-join args)) +(defn where [& args] (generic :where args)) +(defn group-by [& args] (generic :group-by args)) +(defn having [& args] (generic :having args)) +(defn order-by [& args] (generic :order-by args)) +(defn limit [& args] (generic :limit args)) +(defn offset [& args] (generic :offset args)) +(defn values [& args] (generic :values args)) +(defn on-conflict [& args] (generic :on-conflict args)) +(defn on-constraint [& args] (generic :on-constraint args)) +(defn do-nothing [& args] (generic :do-nothing args)) +(defn do-update-set [& args] (generic :do-update-set args)) +(defn returning [& args] (generic :returning args)) + +#?(:clj + (assert (= (clojure.core/set @@#'h/base-clause-order) + (clojure.core/set (map keyword (keys (ns-publics *ns*))))))) diff --git a/src/readme.clj b/src/readme.clj index d6f4b75..b996a51 100644 --- a/src/readme.clj +++ b/src/readme.clj @@ -22,16 +22,14 @@ - - -(seancorfield.readme/defreadme readme-27 +(seancorfield.readme/defreadme readme-25 (require '[honey.sql :as sql] '[honey.sql.helpers :refer :all :as helpers]) ) -(seancorfield.readme/defreadme readme-34 +(seancorfield.readme/defreadme readme-32 (def sqlmap {:select [:a :b :c] :from [:foo] :where [:= :f.a "baz"]}) @@ -43,7 +41,7 @@ -(seancorfield.readme/defreadme readme-46 +(seancorfield.readme/defreadme readme-44 (sql/format sqlmap) => ["SELECT a, b, c FROM foo WHERE f.a = ?" "baz"] ) @@ -64,7 +62,7 @@ -(seancorfield.readme/defreadme readme-67 +(seancorfield.readme/defreadme readme-65 (def q-sqlmap {:select [:foo/a :foo/b :foo/c] :from [:foo] :where [:= :foo/a "baz"]}) @@ -78,7 +76,7 @@ -(seancorfield.readme/defreadme readme-81 +(seancorfield.readme/defreadme readme-79 (-> (select :a :b :c) (from :foo) (where [:= :f.a "baz"])) @@ -86,7 +84,7 @@ -(seancorfield.readme/defreadme readme-89 +(seancorfield.readme/defreadme readme-87 (= (-> (select :*) (from :foo)) (-> (from :foo) (select :*))) => true @@ -94,14 +92,14 @@ -(seancorfield.readme/defreadme readme-97 +(seancorfield.readme/defreadme readme-95 (-> sqlmap (select :d)) => '{:from [:foo], :where [:= :f.a "baz"], :select [:a :b :c :d]} ) -(seancorfield.readme/defreadme readme-104 +(seancorfield.readme/defreadme readme-102 (-> sqlmap (dissoc :select) (select :*) @@ -112,7 +110,7 @@ -(seancorfield.readme/defreadme readme-115 +(seancorfield.readme/defreadme readme-113 (-> (select :*) (from :foo) (where [:= :a 1] [:< :b 100]) @@ -123,7 +121,7 @@ -(seancorfield.readme/defreadme readme-126 +(seancorfield.readme/defreadme readme-124 (-> (select :a [:b :bar] :c [:d :x]) (from [:foo :quux]) (where [:= :quux.a 1] [:< :bar 100]) @@ -140,36 +138,38 @@ -(seancorfield.readme/defreadme readme-143 +(seancorfield.readme/defreadme readme-141 (-> (insert-into :properties) (columns :name :surname :age) (values [["Jon" "Smith" 34] ["Andrew" "Cooper" 12] ["Jane" "Daniels" 56]]) - sql/format) -=> [#sql/regularize - "INSERT INTO properties (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-161 +(seancorfield.readme/defreadme readme-160 (-> (insert-into :properties) (values [{:name "John" :surname "Smith" :age 34} {:name "Andrew" :surname "Cooper" :age 12} {:name "Jane" :surname "Daniels" :age 56}]) - sql/format) -=> [#sql/regularize - "INSERT INTO properties (name, surname, age) - VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)" - "John" "Smith" 34 - "Andrew" "Cooper" 12 - "Jane" "Daniels" 56] + (sql/format {:pretty? true})) +=> [" +INSERT INTO properties (name, surname, age) +VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) +" +"John" "Smith" 34 +"Andrew" "Cooper" 12 +"Jane" "Daniels" 56] ) @@ -184,16 +184,17 @@ :role_id (-> (select :id) (from :role) (where [:= :name role-name]))}]) - sql/format)) + (sql/format {:pretty? true}))) -=> [#sql/regularize - "INSERT INTO user_profile_to_role (user_profile_id, role_id) - VALUES (?, (SELECT id FROM role WHERE name = ?))" - 12345 - "user"] +=> [" +INSERT INTO user_profile_to_role (user_profile_id, role_id) +VALUES (?, (SELECT id FROM role WHERE name = ?)) +" +12345 +"user"] ) -(seancorfield.readme/defreadme readme-196 +(seancorfield.readme/defreadme readme-197 (-> (select :*) (from :foo) (where [:in :foo.a (-> (select :a) (from :bar))]) @@ -205,17 +206,18 @@ -(seancorfield.readme/defreadme readme-208 +(seancorfield.readme/defreadme readme-209 (-> (insert-into :comp_table) (columns :name :comp_column) (values [["small" (composite 1 "inch")] ["large" (composite 10 "feet")]]) - sql/format) -=> [#sql/regularize - "INSERT INTO comp_table (name, comp_column) - VALUES (?, (?, ?)), (?, (?, ?))" - "small" 1 "inch" "large" 10 "feet"] + (sql/format {:pretty? true})) +=> [" +INSERT INTO comp_table (name, comp_column) +VALUES (?, (?, ?)), (?, (?, ?)) +" +"small" 1 "inch" "large" 10 "feet"] ) @@ -223,18 +225,19 @@ -(seancorfield.readme/defreadme readme-226 +(seancorfield.readme/defreadme readme-228 (-> (helpers/update :films) (sset {:kind "dramatic" :watched (sql/call :+ :watched 1)}) (where [:= :kind "drama"]) - sql/format) -=> [#sql/regularize - "UPDATE films SET kind = ?, watched = (watched + ?) - WHERE kind = ?" - "dramatic" - 1 - "drama"] + (sql/format {:pretty? true})) +=> [" +UPDATE films SET kind = ?, watched = (watched + ?) +WHERE kind = ? +" +"dramatic" +1 +"drama"] ) @@ -248,34 +251,35 @@ -(seancorfield.readme/defreadme readme-251 +(seancorfield.readme/defreadme readme-254 (-> (delete-from :films) (where [:<> :kind "musical"]) - sql/format) + (sql/format)) => ["DELETE FROM films WHERE kind <> ?" "musical"] ) -(seancorfield.readme/defreadme readme-260 +(seancorfield.readme/defreadme readme-263 (-> (delete [:films :directors]) (from :films) (join :directors [:= :films.director_id :directors.id]) (where [:<> :kind "musical"]) - sql/format) -=> [#sql/regularize - "DELETE films, directors - FROM films - INNER JOIN directors ON 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-276 +(seancorfield.readme/defreadme readme-280 (-> (truncate :films) - sql/format) + (sql/format)) => ["TRUNCATE films"] ) @@ -283,7 +287,7 @@ -(seancorfield.readme/defreadme readme-286 +(seancorfield.readme/defreadme readme-290 (sql/format {:union [(-> (select :*) (from :foo)) (-> (select :*) (from :bar))]}) => ["SELECT * FROM foo UNION SELECT * FROM bar"] @@ -293,11 +297,11 @@ -(seancorfield.readme/defreadme readme-296 +(seancorfield.readme/defreadme readme-300 (-> (select :%count.*) (from :foo) sql/format) => ["SELECT count(*) FROM foo"] ) -(seancorfield.readme/defreadme readme-300 +(seancorfield.readme/defreadme readme-304 (-> (select :%max.id) (from :foo) sql/format) => ["SELECT max(id) FROM foo"] ) @@ -308,7 +312,7 @@ -(seancorfield.readme/defreadme readme-311 +(seancorfield.readme/defreadme readme-315 (-> (select :id) (from :foo) (where [:= :a :?baz]) @@ -321,19 +325,19 @@ -(seancorfield.readme/defreadme readme-324 +(seancorfield.readme/defreadme readme-328 (def call-qualify-map (-> (select [[:foo :bar]] [[:raw "@var := foo.bar"]]) (from :foo) (where [:= :a (???/param :baz)] [:= :b [:inline 42]]))) ) -(seancorfield.readme/defreadme readme-330 +(seancorfield.readme/defreadme readme-334 call-qualify-map => '{:where [:and [:= :a ???/param :baz] [:= :b [:inline 42]]] :from (:foo) :select [[[:foo :bar]] [[:raw "@var := foo.bar"]]]} ) -(seancorfield.readme/defreadme readme-336 +(seancorfield.readme/defreadme readme-340 (sql/format call-qualify-map :??? {:baz "BAZ"}) => ["SELECT foo(bar), @var := foo.bar FROM foo WHERE (a = ?) AND (b = 42)" "BAZ"] ) @@ -343,16 +347,17 @@ call-qualify-map -(seancorfield.readme/defreadme readme-346 +(seancorfield.readme/defreadme readme-350 (-> (insert-into :sample) (values [{:location [:ST_SetSRID [:ST_MakePoint 0.291 32.621] [:cast 4325 :integer]]}]) - (sql/format)) -=> [#sql/regularize - "INSERT INTO sample (location) - VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer)))" - 0.291 32.621 4326] + (sql/format {:pretty? true})) +=> [" +INSERT INTO sample (location) +VALUES (ST_SetSRID(ST_MakePoint(?, ?), CAST(? AS integer))) +" +0.291 32.621 4326] ) @@ -368,7 +373,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-371 +(seancorfield.readme/defreadme readme-376 (-> (select :*) (from :foo) (where [:< :expired_at (sql/raw ["now() - '" 5 " seconds'"])]) @@ -376,7 +381,7 @@ call-qualify-map => ["SELECT * FROM foo WHERE expired_at < now() - '? seconds'" 5] ) -(seancorfield.readme/defreadme readme-379 +(seancorfield.readme/defreadme readme-384 (-> (select :*) (from :foo) (where [:< :expired_at (sql/raw ["now() - '" #sql/param :t " seconds'"])]) @@ -393,7 +398,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-396 +(seancorfield.readme/defreadme readme-401 (-> (select :foo.a) (from :foo) (where [:= :foo.a "baz"]) @@ -409,7 +414,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-412 +(seancorfield.readme/defreadme readme-417 (-> (select :foo.a) (from :foo) (where [:= :foo.a "baz"]) @@ -421,7 +426,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-424 +(seancorfield.readme/defreadme readme-429 (sql/format {:select [:f.foo-id :f.foo-name] :from [[:foo-bar :f]] @@ -435,7 +440,7 @@ call-qualify-map -(seancorfield.readme/defreadme readme-438 +(seancorfield.readme/defreadme readme-443 (def big-complicated-map (-> (select :f.* :b.baz :c.quux [:b.bla "bla-bla"] [[:now]] [[:raw "@x := 10"]]) @@ -455,7 +460,7 @@ call-qualify-map (limit 50) (offset 10))) ) -(seancorfield.readme/defreadme readme-458 +(seancorfield.readme/defreadme readme-463 big-complicated-map => {:select [:f.* :b.baz :c.quux [:b.bla "bla-bla"] [[:now]] [[:raw "@x := 10"]]] @@ -475,26 +480,24 @@ big-complicated-map :limit 50 :offset 10} ) -(seancorfield.readme/defreadme readme-478 +(seancorfield.readme/defreadme readme-483 (sql/format big-complicated-map {:param1 "gabba" :param2 2}) -=> [#sql/regularize - "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] +=> [" +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-497 +(seancorfield.readme/defreadme readme-500 ;; Printable and readable (= big-complicated-map (read-string (pr-str big-complicated-map))) => true @@ -506,7 +509,7 @@ big-complicated-map -(seancorfield.readme/defreadme readme-509 +(seancorfield.readme/defreadme readme-512 (defmethod fmt/fn-handler "betwixt" [_ field lower upper] (str (fmt/to-sql field) " BETWIXT " (fmt/to-sql lower) " AND " (fmt/to-sql upper))) @@ -517,23 +520,23 @@ big-complicated-map -(seancorfield.readme/defreadme readme-520 +(seancorfield.readme/defreadme readme-523 ;; 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-525 +(seancorfield.readme/defreadme readme-528 (sql/format {:select [:a :b] :foobar :baz}) => ["SELECT a, b FOOBAR baz"] ) -(seancorfield.readme/defreadme readme-529 +(seancorfield.readme/defreadme readme-532 (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-536 +(seancorfield.readme/defreadme readme-539 (-> (select :a :b) (foobar :baz) sql/format) => ["SELECT a, b FOOBAR baz"] @@ -541,7 +544,7 @@ big-complicated-map -(seancorfield.readme/defreadme readme-544 +(seancorfield.readme/defreadme readme-547 (fmt/register-clause! :foobar 110) )