diff options
author | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-06-17 17:27:20 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-06-17 17:27:20 +1000 |
commit | b8fef59b7b85ae414ad64d2fb6540b3aea66602c (patch) | |
tree | d1f3a4a2d0e643a3c12d253a127489ec8e3e01d7 /src/clojure_sql/compiler.clj | |
parent | 4ab5ae273750c0d52ec72f103fe9165b52d2abb6 (diff) |
Rename sort-by, add grouping, refactor+fix some join stuff
`sort-by` is now called `sort`. This is just because I think it makes more
sense and nothing more.
Grouping has been added with `group` and `having`. They behave as you'd expect
from SQL, except that joining with a table which has a `group` or `having`
clause will move that query in as a subquery. I wasn't sure how else to ensure
their composition, so this way maintains the semantics (which is the most
important part) at the potential cost of some efficiency in performing the
query. I'm not sure that there exists a more general solution. I would assume
not.
The join stuff has been fixed a bit (some valid renames were rejected as
invalid) and standardised a bit (exceptions are now more similar). A bunch of
things have been added to the join stuff as a result of the above grouping
things, too. A bunch of changes all around, basically.
The compiler has also had a few small changes made to it, and has been enhanced
to support the grouping stuff.
Diffstat (limited to 'src/clojure_sql/compiler.clj')
-rw-r--r-- | src/clojure_sql/compiler.clj | 74 |
1 files changed, 53 insertions, 21 deletions
diff --git a/src/clojure_sql/compiler.clj b/src/clojure_sql/compiler.clj index 6f940c0..60a5530 100644 --- a/src/clojure_sql/compiler.clj +++ b/src/clojure_sql/compiler.clj @@ -50,18 +50,27 @@ ;; ============================================================== ;; compile-* multimethods are of the signature: -;; (db, expr) -> (fn [s] [sql]) +;; (db, expr) -> [args] -> [sql & args] (declare compile-query compile-expression) -(defmulti compile-expression-sequential (fn [db ex])) +(defmulti compile-expression-list (fn [db _] db)) +(defmethod compile-expression-list :default [db ex] + (->> (map (partial compile-expression db) ex) + (apply sequence) + ((p-lift string/join ",")) + $add-parentheses)) + +(defmulti compile-expression-sequential (fn [db _] db)) (defmethod compile-expression-sequential :default [db ex] (let [compile-exprs #(map (partial compile-expression db) %) op (name (first ex)) num-args (dec (count ex))] (-> (condp u/funcall (first ex) quote? (do (assert (= num-args 1) "`quote` must only take one argument") - (>> (tell (second ex)) (return "?"))) + (if (sequential? (second ex)) + (compile-expression-list db (second ex)) + (>> (tell (second ex)) (return "?")))) unary? (do (assert (= num-args 1) (str "Unary operator `" op "` must take one argument")) (do-m :let [exprs (compile-exprs ex)] vals <- (apply sequence exprs) @@ -120,28 +129,33 @@ (def ^:private join-type-names {:inner "INNER" - :left "LEFT OUTER" - :right "RIGHT OUTER" - :outer "FULL OUTER" + :outer "LEFT OUTER" + :full-outer "FULL OUTER" :cross "CROSS"}) (defmulti compile-tables (fn [db _ _] db)) -(defmethod compile-tables :default [db join tables-map] - (if (vector? join) +(defmethod compile-tables :default [db join tables-map] + (if (vector? join) (->> (for [table-alias join] (make-table-name db (get tables-map table-alias) table-alias)) (apply sequence) ((p-lift string/join ", "))) (let [{:keys [left right type on]} join] - ($str (return "(") - (compile-tables db left tables-map) - (return (str " " (get join-type-names type (name type)) " JOIN ")) - (compile-tables db right tables-map) - (if on - ($str (return " ON ") - (compile-expression db on)) - (return "")) - (return ")"))))) + (if (= type :cross) + ($str (return "(") + (compile-tables db left tables-map) + (return " CROSS JOIN ") + (compile-tables db right tables-map) + (return ")")) + ($str (return "(") + (compile-tables db left tables-map) + (return (str " " (get join-type-names type (name type)) " JOIN ")) + (compile-tables db right tables-map) + (return " ON ") + (if on + (compile-expression db on) + (return "TRUE")) + (return ")")))))) (defmulti compile-where (fn [db _] db)) (defmethod compile-where :default [db expr] @@ -149,8 +163,8 @@ ($str (return " WHERE ") (compile-expression db expr)) (return nil))) -(defmulti compile-sort-by (fn [db _] db)) -(defmethod compile-sort-by :default [db fields] +(defmulti compile-sort (fn [db _] db)) +(defmethod compile-sort :default [db fields] (if fields (->> (for [[[table field] dir] fields] ($str (make-field-name db [table field]) @@ -160,8 +174,24 @@ ($str (return " ORDER BY "))) (return nil))) +(defmulti compile-group (fn [db _] db)) +(defmethod compile-group :default [db fields] + (if fields + (->> (for [[table field] fields] + (make-field-name db [table field])) + (apply sequence) + ((p-lift string/join ",")) + ($str (return " GROUP BY "))) + (return nil))) + +(defmulti compile-having (fn [db _] db)) +(defmethod compile-having :default [db expr] + (if expr + ($str (return " HAVING ") (compile-expression db expr)) + (return nil))) + (defmulti compile-query (fn [db _] db)) -(defmethod compile-query :default [db {:keys [tables fields joins where sort-by]}] +(defmethod compile-query :default [db {:keys [tables fields joins where sort group having]}] ($str (return "SELECT ") (compile-fields db fields) (if tables @@ -169,7 +199,9 @@ (compile-tables db joins tables)) ($str "")) (compile-where db where) - (compile-sort-by db sort-by))) + (compile-group db group) + (compile-having db having) + (compile-sort db sort))) |