Start some tests; implement more clauses

This commit is contained in:
Sean Corfield 2020-09-20 19:17:37 -07:00
parent 29b6e47a8e
commit 2c98d35f63
2 changed files with 94 additions and 22 deletions

View file

@ -41,7 +41,7 @@
(str (q t) ".")))) (str (q t) "."))))
(defn- format-selectable [x] (defn- format-selectable [x]
(if (vector? x) (if (sequential? x)
(str (let [s (first x)] (str (let [s (first x)]
(if (map? s) (if (map? s)
(format-dsl s) (format-dsl s)
@ -53,7 +53,9 @@
;; primary clauses ;; primary clauses
(defn- format-selector [k xs] (defn- format-selector [k xs]
[(str (sql-kw k) " " (str/join ", " (map #'format-selectable xs)))]) (if (sequential? xs)
[(str (sql-kw k) " " (str/join ", " (map #'format-selectable xs)))]
[(str (sql-kw k) " " (format-selectable xs))]))
(defn- format-join [k [j e]] (defn- format-join [k [j e]]
(let [[sql & params] (format-expr e)] (let [[sql & params] (format-expr e)]
@ -74,8 +76,9 @@
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))) (into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
(defn- format-order-by [k xs] (defn- format-order-by [k xs]
(let [dirs (map #(if (vector? %) (second %) :asc) xs) (let [dirs (map #(if (sequential? %) (second %) :asc) xs)
[sqls params] (format-expr-list (map #(if (vector? %) (first %) %) xs))] [sqls params]
(format-expr-list (map #(if (sequential? %) (first %) %) xs))]
(into [(str (sql-kw k) " " (into [(str (sql-kw k) " "
(str/join ", " (map (fn [sql dir] (str sql " " (sql-kw dir))) (str/join ", " (map (fn [sql dir] (str sql " " (sql-kw dir)))
sqls sqls
@ -83,17 +86,64 @@
(def ^:private clause-order (def ^:private clause-order
"The (default) order for known clauses. Can have items added and removed." "The (default) order for known clauses. Can have items added and removed."
(atom [:select :from :join :where :group-by :order-by])) (atom [:select :from
:join :left-join :right-join :inner-join :outer-join :full-join
:where :group-by :having :order-by]))
(def ^:private clause-format (def ^:private clause-format
"The (default) behavior for each known clause. Can also have items added "The (default) behavior for each known clause. Can also have items added
and removed." and removed."
(atom {:select #'format-selector (atom {:select #'format-selector
:from #'format-selector :insert-into #'format-selector
:join #'format-join ; any join works :update #'format-selector
:where #'format-where :delete #'format-selector
:group-by #'format-group-by :delete-from #'format-selector
:order-by #'format-order-by})) :truncate #'format-selector
:from #'format-selector
:join #'format-join
:left-join #'format-join
:right-join #'format-join
:inner-join #'format-join
:outer-join #'format-join
:full-join #'format-join
:where #'format-where
:group-by #'format-group-by
:having #'format-where
:order-by #'format-order-by}))
(comment :target
{:with 20
:with-recursive 30
:intersect 35
:union 40
:union-all 45
:except 47
;:select 50
;:insert-into 60
;:update 70
;:delete 75
;:delete-from 80
;:truncate 85
:columns 90
:composite 95
:set0 100 ; low-priority set clause
;:from 110
;:join 120
;:left-join 130
;:right-join 140
;:full-join 150
:cross-join 152 ; doesn't have on clauses
:set 155
:set1 156 ; high-priority set clause (synonym for :set)
;:where 160
;:group-by 170
;:having 180
;:order-by 190
:limit 200
:offset 210
:lock 215
:values 220
:query-values 230})
(defn- format-dsl [x] (defn- format-dsl [x]
(let [[sqls params] (let [[sqls params]
@ -125,7 +175,16 @@
(->> (into #{} (map keyword))))) (->> (into #{} (map keyword)))))
(def ^:private special-syntax (def ^:private special-syntax
{:cast {:between
(fn [[x a b]]
(let [[sql-x & params-x] (format-expr x true)
[sql-a & params-a] (format-expr a true)
[sql-b & params-b] (format-expr b true)]
(-> [(str sql-x " BETWEEN " sql-a " AND " sql-b)]
(into params-x)
(into params-a)
(into params-b))))
:cast
(fn [[x type]] (fn [[x type]]
(let [[sql & params] (format-expr x)] (let [[sql & params] (format-expr x)]
(into [(str "CAST(" sql " AS " (sql-kw type) ")")] params))) (into [(str "CAST(" sql " AS " (sql-kw type) ")")] params)))
@ -138,7 +197,7 @@
(cond (keyword? x) (cond (keyword? x)
[(format-entity x)] [(format-entity x)]
(vector? x) (sequential? x)
(let [op (first x)] (let [op (first x)]
(if (keyword? op) (if (keyword? op)
(cond (infix-ops op) (cond (infix-ops op)
@ -168,10 +227,10 @@
:else :else
["?" x])) ["?" x]))
(defn Hformat (defn format
"Turn the data DSL into a vector containing a SQL string followed by "Turn the data DSL into a vector containing a SQL string followed by
any parameter values that were encountered in the DSL structure." any parameter values that were encountered in the DSL structure."
([data] (Hformat data {})) ([data] (format data {}))
([data opts] ([data opts]
(let [dialect (get dialects (get opts :dialect :ansi))] (let [dialect (get dialects (get opts :dialect :ansi))]
(binding [*dialect* dialect (binding [*dialect* dialect
@ -186,6 +245,7 @@
(reset! default-dialect (get dialects dialect :ansi))) (reset! default-dialect (get dialects dialect :ansi)))
(comment (comment
format
(format-expr [:= :id 1]) (format-expr [:= :id 1])
(format-expr [:+ :id 1]) (format-expr [:+ :id 1])
(format-expr [:+ 1 [:+ 1 :quux]]) (format-expr [:+ 1 [:+ 1 :quux]])
@ -194,12 +254,13 @@
(format-expr 1) (format-expr 1)
(format-where :where [:= :id 1]) (format-where :where [:= :id 1])
(format-dsl {:select [:*] :from [:table] :where [:= :id 1]}) (format-dsl {:select [:*] :from [:table] :where [:= :id 1]})
(Hformat {:select [:t.*] :from [[:table :t]] :where [:= :id 1]}) (format {:select [:t.*] :from [[:table :t]] :where [:= :id 1]})
(Hformat {:select [:*] :from [:table] :group-by [:foo :bar]}) (format {:select [:*] :from [:table] :group-by [:foo :bar]})
(Hformat {:select [:*] :from [:table] :group-by [[:date :bar]]}) (format {:select [:*] :from [:table] :group-by [[:date :bar]]})
(Hformat {:select [:*] :from [:table] :order-by [[:foo :desc] :bar]}) (format {:select [:*] :from [:table] :order-by [[:foo :desc] :bar]})
(Hformat {:select [:*] :from [:table] :order-by [[[:date :expiry] :desc] :bar]}) (format {:select [:*] :from [:table] :order-by [[[:date :expiry] :desc] :bar]})
(Hformat {:select [:*] :from [:table] :where [:< [:date_add :expiry [:interval 30 :days]] [:now]]}) (format {:select [:*] :from [:table] :where [:< [:date_add :expiry [:interval 30 :days]] [:now]]})
(format-expr [:interval 30 :days]) (format-expr [:interval 30 :days])
(Hformat {:select [:*] :from [:table] :where [:= :id 1]} {:dialect :mysql}) (format {:select [:*] :from [:table] :where [:= :id 1]} {:dialect :mysql})
(format {:select [:*] :from [:table] :where [:in :id [1 2 3 4]]})
,) ,)

11
test/honey/sql_test.cljc Normal file
View file

@ -0,0 +1,11 @@
;; copyright (c) sean corfield, all rights reserved
(ns honey.sql-test
(:require #?(:clj [clojure.test :refer [deftest is testing]]
:cljs [cljs.test :refer-macros [deftest is testing]])
[honey.sql :as sut]))
(deftest mysql-tests
(is (= ["SELECT * FROM `table` WHERE `id` = ?" 1]
(sut/format {:select [:*] :from [:table] :where [:= :id 1]}
{:dialect :mysql}))))