diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/clojure_sql/compiler.clj | 45 | ||||
| -rw-r--r-- | src/clojure_sql/core.clj | 4 | ||||
| -rw-r--r-- | src/clojure_sql/writer.clj | 2 | 
3 files changed, 39 insertions, 12 deletions
| diff --git a/src/clojure_sql/compiler.clj b/src/clojure_sql/compiler.clj index 9ba0c3a..c7f907f 100644 --- a/src/clojure_sql/compiler.clj +++ b/src/clojure_sql/compiler.clj @@ -5,6 +5,12 @@              [clojure-sql.util :as u :refer [named?]]              [clojure-sql.writer :as w :refer [return lift p-lift sequence do-m tell >>]])) +(defn no-args-operator-error [op] +  (throw (ex-info (str "Argument called with no args doesn't have identity value: " op) +                  {:operator op}))) + + +  (defn add-parentheses [s]    (str \( s \))) @@ -39,10 +45,18 @@  ;; Utility functions for the compile-* functions  ;; ============================================================== +(def ^:private boolean? (some-fn true? false?)) +(def ^:private regex? (partial instance? (class #""))) +(def ^:private operator-name (some-fn (comp {"$" "~"} name) name)) +  (def quote? (comp boolean '#{"quote"} name)) -(def unary? (comp boolean '#{"not" "exists"} name)) -(def binary? (comp boolean '#{"=" "<" ">" "<=" ">=" "is" "in"} name)) -(def operator? (comp boolean '#{"and" "or" "+" "-" "/" "*"} name)) +(def unary? (comp boolean '#{"not" "exists" "-"} name)) +(def binary? (comp boolean '#{"=" "<" ">" "<=" ">=" "is" "in" "like" "~"} name)) +(def n-ary? (comp boolean '#{"and" "or" "+" "-" "/" "*"} name)) +(def operator-identity (comp {"and" true +                              "or" false +                              "+" 0 +                              "*" 1} name))  ;; ============================================================== @@ -64,24 +78,31 @@  (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)) +        op-name (operator-name (first ex))          num-args (dec (count ex))] -    (-> (condp u/funcall (first ex) +    (-> (condp u/funcall op-name            quote?    (do (assert (= num-args 1) "`quote` must only take one argument")                          (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")) +          n-ary?    (do-m :let [[op & exprs] (compile-exprs ex)] +                          vals <- (apply sequence (interpose op exprs)) +                          (condp = (count vals) +                            0 (if-let [id (operator-identity op-name)] +                                (compile-expression db id) +                                (no-args-operator-error (name (first ex)))) +                            1 (if (unary? op-name) +                                (do-m compiled-op <- op +                                      (return (str compiled-op (first vals)))))  +                            (return (string/join " " vals)))) +          unary?    (do (assert (= num-args 1) (str "Unary operator `" (first ex) "` must take one argument"))                          (do-m :let [exprs (compile-exprs ex)]                                vals <- (apply sequence exprs)                                (return (string/join "" vals)))) -          binary?   (do (assert (= num-args 2) (str "Binary operator `" op "` must take two arguments")) +          binary?   (do (assert (= num-args 2) (str "Binary operator `" (first ex) "` must take two arguments"))                          (do-m :let [[op left right] (compile-exprs ex)]                                vals <- (sequence left op right)                                (return (string/join " " vals)))) -          operator? (do-m :let [[op & exprs] (compile-exprs ex)] -                          vals <- (apply sequence (interpose op exprs)) -                          (return (string/join " " vals)))            (do-m :let [fn-name (function-name db (first ex))                        exprs (compile-exprs (rest ex))]                  vals <- (apply sequence exprs) @@ -92,12 +113,14 @@  (defmulti compile-expression (fn [db _] db))  (defmethod compile-expression :default [db ex]    (condp u/funcall ex +    boolean?     (return (string/upper-case (str ex)))      query?       ($add-parentheses (compile-query db ex))      nil?         (return "NULL")      vector?      (return (str (table-name db (first ex)) \. (field-name db (second ex))))      keyword?     (return (field-name db ex)) +    regex?       (>> (tell (str ex)) (return "?"))      string?      (>> (tell ex) (return "?")) ;;(sql-string db ex) -    symbol?      (return (string/upper-case (name ex))) +    symbol?      (return (string/upper-case (operator-name ex)))      sequential?  (compile-expression-sequential db ex)      (return ex))) diff --git a/src/clojure_sql/core.clj b/src/clojure_sql/core.clj index 72438a6..bd4b431 100644 --- a/src/clojure_sql/core.clj +++ b/src/clojure_sql/core.clj @@ -26,3 +26,7 @@  (def group #'d/group)  (def having #'d/having)  (def sort #'d/sort) + + +(-> (table :x) +    (select `($ (- :a) #"bloo"))) diff --git a/src/clojure_sql/writer.clj b/src/clojure_sql/writer.clj index 5f4250b..176cc67 100644 --- a/src/clojure_sql/writer.clj +++ b/src/clojure_sql/writer.clj @@ -53,7 +53,7 @@           (if (= (first args) :let)             `(let ~(second args)                ~(apply do-m* (nnext args)))) -         (if (= (name (second args)) "<-") +         (if (every? #(% (second args)) [symbol? #(= (name %) "<-")])             (let [[var <- val & others] args]               `(bind ~val                      (fn [~var] | 
