Commits

Anonymous committed 5a47290

overhaul as-clause function to accept keywords and strings (free-form clauses) and values
add as-value-clause function
add sqlfn, as, and as-fn functions

Comments (0)

Files changed (1)

src/main/clj/org/bituf/sqlrat/clause.clj

 
 (defn as-clause
   "Convert given expression into a clause and return it. Throw exception on
-   invalid input. A valid clause is a non-empty vector with first element as
-   the SQL clause followed by optional values for placeholder '?' symbols:
-   [\"id=?\" 45]"
+  invalid input. A strictly valid clause is a non-empty vector with the first
+  element as the string SQL clause followed by optional values for placeholder
+  '?' symbols: [\"id=?\" 45]
+  The following clauses are permitted:
+  Keyword    - :id       >> becomes clause >> [\"id\"]
+  String     - \"id\"    >> becomes clause >> [\"id\"]
+  Clause     - [\"id\"]  >> remains clause >> [\"id\"]
+  Collection - '(\"id\") >> becomes clause >> [\"id\"]
+  Any value  - 479       >> becomes value clause >> [\"?\" 479]
+  You got the drift."
   [clause]
   (debug "as-clause" "Received clause:" clause)
   (if (clause? clause) clause
-    (let [clause-vec (if (string? clause) [clause] (as-vector clause))
+    (let [clause-vec (if (string? clause) [clause]
+                       (if (keyword? clause) [(name clause)]
+                         (if (coll? clause) (as-vector clause)
+                           ["?" clause])))
           _          (if (or (nil? clause) (empty? clause-vec))
                        (bad-arg# "Clause must not be nil or empty: " clause))
           _          (if (not (string? (first clause-vec)))
       (assoc-clause-meta clause-vec))))
 
 
+(def  ^{:doc "Alias for 'as-clause' function"}
+       $ as-clause)
+
+
+(defn as-value-clause
+  "Converts a value, or a set of values into a value clause. Value clauses look
+  like these:
+  [\"?, ?, ?\" 10 20 30]
+  [\"?\" \"Anthony Pereira\"]
+  etc"
+  [value]
+  (assert (not (clause? value)))
+  (let [values (as-vector value)
+        vcount (count values)
+        cl-str (apply str
+                 (interpose ", "
+                   (take vcount
+                     (repeat \? ))))]
+    (as-clause (into [cl-str] values))))
+
+
+(def ^{:doc "Alias for 'as-value-clause' function"}
+      ? as-value-clause)
+
+
 (defn empty-clause
-  [& whatever]
+  []
   (as-clause ""))
 
 
     (as-clause (into [qexpr] qparm))))
 
 
+(def ^{:doc "Alias for 'merge-clauses' function"}
+      >> merge-clauses)
+
+
 (defn merge-topkey-clauses
   "Merge a clause-key with clause.
    Example: (merge-key-clause :where (as-clause \"\"))
                                         (into [clause] more)))
 (defn GROUPBY [^Vector clause & more] (apply merge-key-clauses :group-by
                                         (into [clause] more)))
-(def GROUP-BY GROUPBY)
+(def ^{:doc "Alias for GROUPBY"}
+      GROUP-BY GROUPBY)
 
 
 ;; ========== WHERE clause functions ===========
   [tokens]
   (if (empty? tokens) (empty-clause)
     (let [tokens-vec (as-vector tokens)]
-      (as-clause (apply str
-                   (interpose ", " (map #(str-name %) tokens-vec)))))))
+      (apply merge-clauses
+        (interpose (as-clause ", ")
+          (map as-clause tokens-vec))))))
 
 
 ;; === The LIMIT clause ===
     (as-clause [" LIMIT ?" howmany]))
   ([from howmany]
     (as-clause [" LIMIT ?, ?" from howmany])))
+
+
+;; === Functions and Columns ===
+
+
+(defn sqlfn
+  "Example: (sqlfn :AVG :subjectid)
+            => [\"AVG(subjectid)\"]"
+  [^Keyword fn-name & args]
+  (merge-clauses
+    (apply merge-clauses
+      (as-clause (str (str-name fn-name) "("))
+      (map as-clause args))
+    (as-clause ")")))
+
+(def ^{:doc "Alias for 'sqlfn' function"}
+      FN sqlfn)
+
+(defn as
+  "Example: (as :avgscore \"AVG(score)\")
+            => AVG(score) AS avgscore"
+  [^Keyword new-colname expr]
+  (apply merge-clauses
+    (map as-clause [expr " AS " new-colname])))
+
+(defn asfn
+  "Example: (asfn :avgscore :AVG :score)
+            => AVG(score) AS avgscore"
+  [^Keyword new-colname ^Keyword fn-name & args]
+  (as new-colname (apply sqlfn fn-name args)))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.