summaryrefslogtreecommitdiff
path: root/src/clojure_sql/compiler.clj
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@clearboxsystems.com.au>2013-06-17 17:27:20 +1000
committerCarlo Zancanaro <carlo@clearboxsystems.com.au>2013-06-17 17:27:20 +1000
commitb8fef59b7b85ae414ad64d2fb6540b3aea66602c (patch)
treed1f3a4a2d0e643a3c12d253a127489ec8e3e01d7 /src/clojure_sql/compiler.clj
parent4ab5ae273750c0d52ec72f103fe9165b52d2abb6 (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.clj74
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)))