diff options
author | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-06-13 18:24:05 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-06-13 18:24:05 +1000 |
commit | 148f752b5f48707dc3d7fe448d1faf33d5cd0228 (patch) | |
tree | a61345f51f248c5061cf47630ea5eafcdf638408 /test | |
parent | e2bd4b4939d34fc9400c9843b691428d3888ecc4 (diff) |
Starting a re-write of the DSL, to be followed by the compiler.
Flip around field/table aliases, do joins a bit differently. They're my main
aims at the moment! I'll also add a preprocessor for the compiler to massage it
into a nicer form there.
I discovered that joins can be done with a pretty sweet syntax in SQL:
(tableA LEFT JOIN tableB) RIGHT JOIN tableC
This is pretty much perfect for my purposes.
Flipping alias maps just makes more sense and removes a whole bunch of
`flip-map` calls that would be unnecessary if the aliases were the other way
around. The user-facing side of the DSL will be left unchanged, though. The
user provides an `{old-name new-name}` map and internally we convert that into
`{new-name old-name}`. Like magic.
I'm also adding a bunch more tests. Hopefully that will make things more likely
to work for long periods of time.
Peace out!
Diffstat (limited to 'test')
-rw-r--r-- | test/clojure_sql/core_test.clj | 63 | ||||
-rw-r--r-- | test/clojure_sql/dsl_test.clj | 168 |
2 files changed, 206 insertions, 25 deletions
diff --git a/test/clojure_sql/core_test.clj b/test/clojure_sql/core_test.clj index 236e421..6a12698 100644 --- a/test/clojure_sql/core_test.clj +++ b/test/clojure_sql/core_test.clj @@ -3,28 +3,41 @@ (:require [clojure-sql.core :refer :all] [midje.sweet :refer :all])) -(fact - @(table :user) - => ["SELECT * FROM \"user\""] - - @(-> (table :user) (select '(= :username "george"))) - => ["SELECT * FROM \"user\" WHERE (\"user\".\"username\" = ?)" "george"] - - @(-> (table :user) (project {:username :u})) - => ["SELECT \"user\".\"username\" AS \"u\" FROM \"user\""] - - @(-> (table :user) (project {'(+ :username :password) :u})) - => ["SELECT (\"user\".\"username\" + \"user\".\"password\") AS \"u\" FROM \"user\""]) - -(into {} (-> (table :user) (project '{(+ :username :password) :u}))) - -(-> (table :users) - (project '[:username (+ 1 2 3)]) - (rename '{(+ 1 2 3) :x}) - (select `(exists ~(-> (table :users) - (select '(= 10 :username))))) - println) - -(-> (table :users) - (project {:username :un}) - (select '(= :username 10))) +(comment + + (fact + @(table :user) + => ["SELECT * FROM \"user\""] + + @(-> (table :user) (project [:username])) + => ["SELECT \"user\".\"username\" AS \"username\" FROM \"user\""] + + @(-> (table :user) (select '(= :username "george"))) + => ["SELECT * FROM \"user\" WHERE (\"user\".\"username\" = ?)" "george"] + + @(-> (table :user) (project {:username :u})) + => ["SELECT \"user\".\"username\" AS \"u\" FROM \"user\""] + + @(-> (table :user) (project {'(+ :age :modifier) :u})) + => ["SELECT (\"user\".\"age\" + \"user\".\"modifier\") AS \"u\" FROM \"user\""] + + @(-> (table :user) + (project [:id]) + (join (-> (table :x) + (project [:id]) + (join (-> (table :y) + (project [:id])) + :type :left)))) + => ["SELECT \"user\".\"id\" AS \"id\" FROM \"user\" INNER JOIN \"x\" ON ((\"user\".\"id\" = \"x\".\"id\"))"]) + + (into {} (-> (table :user) (project '{(+ :username :password) :u}))) + + (-> (table :users) + (project '[:username (+ 1 2 3)]) + (rename '{(+ 1 2 3) :x}) + (select `(exists ~(-> (table :users) + (select '(= 10 :username)))))) + + (-> (table :users) + (project {:username :un}) + (select '(= :username 10)))) diff --git a/test/clojure_sql/dsl_test.clj b/test/clojure_sql/dsl_test.clj new file mode 100644 index 0000000..182749e --- /dev/null +++ b/test/clojure_sql/dsl_test.clj @@ -0,0 +1,168 @@ +(ns clojure-sql.dsl-test + (:refer-clojure :exclude [sort-by]) + (:require [clojure-sql.dsl :refer :all] + [midje.sweet :refer :all])) + +(unfinished join) + +(fact "Table creates basic queries on tables" + + (table ..name..) + => {:tables {..name.. ..name..}} + ;(provided (keyword? ..name..) => true) + + (table {..name.. ..alias..}) + => {:tables {..alias.. ..name..}} + + (table {..name.. ..alias.., ..name2.. ..alias2..}) + => {:tables {..alias.. ..name.., + ..alias2.. ..name2..}}) + + +(fact "Project restricts (and/or adds) fields of a query" + + (prerequisites (keyword? ..table-alias..) => true + (keyword? ..table..) => true + (keyword? ..field..) => true + (keyword? ..field-alias..) => true + (keyword? ..field2..) => true + (keyword? ..field2-alias..) => true) + + (fact "projecting onto a single field from one table" + (-> (table {..table.. ..table-alias..}) + (project [..field..])) + => {:tables {..table-alias.. ..table..} + :fields {..field.. [..table-alias.. ..field..]}} + + (-> (table {..table.. ..table-alias..}) + (project {..field.. ..field-alias..})) + => {:tables {..table-alias.. ..table..} + :fields {..field-alias.. [..table-alias.. ..field..]}}) + + + (fact "projecting onto multiple fields from one table" + (-> (table {..table.. ..table-alias..}) + (project [..field.. ..field2..])) + => {:tables {..table-alias.. ..table..} + :fields {..field.. [..table-alias.. ..field..] + ..field2.. [..table-alias.. ..field2..]}} + + (-> (table {..table.. ..table-alias..}) + (project {..field.. ..field-alias.., ..field2.. ..field2-alias..})) + => {:tables {..table-alias.. ..table..} + :fields {..field-alias.. [..table-alias.. ..field..] + ..field2-alias.. [..table-alias.. ..field2..]}}) + + (fact "projecting one a field from multiple tables" + (prerequisites ..tables.. =contains=> {:tables {..table.. ..table.., ..table2.. ..table2..}}) + + (project ..tables.. [..field..]) + => (throws clojure.lang.ExceptionInfo) + + (project ..tables.. {..field.. ..field-alias..}) + => (throws clojure.lang.ExceptionInfo)) + + (fact "projecting a subset of the current projection from one table" + ;; Note that these two facts are retaining the ..table.. in the + ;; fields rather than using the ..table-alias.. they would have + ;; used otherwise. This shows they are filtering the existing + ;; fields rather than removing and re-adding the fields. + (project {:tables {..table-alias.. ..table..} + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + [..field..]) + => {:tables {..table-alias.. ..table..} + :fields {..field.. [..table.. ..field..]}} + + (project {:tables {..table-alias.. ..table..} + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + {..field.. ..field-alias..}) + => {:tables {..table-alias.. ..table..} + :fields {..field-alias.. [..table.. ..field..]}}) + + (fact "projecting a disjoint set from the current projection from one table" + (project {:tables {..table-alias.. ..table..} + :fields {[..table.. ..field..] ..field..}} + [..field2..]) + => {:tables {..table-alias.. ..table..} + :fields {..field2.. [..table-alias.. ..field2..]}}) + + (fact "projecting a superset from the current projection from one table" + (project {:tables {..table.. ..table..} + :fields {..field.. [..table.. ..field..]}} + [..field.. ..field2..]) + => {:tables {..table.. ..table..} + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + + ;; once again - note the table aliases + (project {:tables {..table-alias.. ..table..} + :fields {..field.. [..table.. ..field..]}} + [..field.. ..field2..]) + => {:tables {..table-alias.. ..table..} + :fields {..field.. [..table.. ..field..] + ..field2.. [..table-alias.. ..field2..]}}) + + + + (fact "projecting a subset of the current projection from two table" + (prerequisites ..tables.. =contains=> {:tables {..table.. ..table.., ..table2.. ..table2..}}) + + (project {:tables ..tables.. + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + [..field..]) + => {:tables ..tables.. + :fields {..field.. [..table.. ..field..]}} + + (project {:tables ..tables.. + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + {..field.. ..field-alias..}) + => {:tables ..tables.. + :fields {..field-alias.. [..table.. ..field..]}}) + + (fact "projecting a disjoint set from the current projection from two tables" + (project {:tables {..table-alias.. ..table.., ..table2-alias.. ..table2..} + :fields {[..table.. ..field..] ..field..}} + [..field2..]) + => (throws clojure.lang.ExceptionInfo)) + + (fact "projecting a superset from the current projection from two tables" + (project {:tables {..table-alias.. ..table.., ..table2-alias.. ..table2..} + :fields {[..table.. ..field..] ..field..}} + [..field.. ..field2..]) + => (throws clojure.lang.ExceptionInfo))) + + + +(fact "renaming fields does what you'd expect (renames them, removes the old alias)" + (prerequisites (keyword? ..table..) => true + (keyword? ..field..) => true + (keyword? ..field2..) => true + (keyword? ..field-alias..) => true) + + (-> (table ..table..) + (project [..field..]) + (rename {..field.. ..field-alias..})) + => {:tables {..table.. ..table..} + :fields {..field-alias.. [..table.. ..field..]}} + + (-> (table ..table..) + (project [..field.. ..field2..]) + (rename {..field.. ..field-alias..})) + => {:tables {..table.. ..table..} + :fields {..field-alias.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + + (-> {:tables {..table.. ..table.., + ..table2.. ..table2..} + :fields {..field.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}} + (rename {..field.. ..field-alias..})) + => {:tables {..table.. ..table.., ..table2.. ..table2..} + :fields {..field-alias.. [..table.. ..field..] + ..field2.. [..table.. ..field2..]}}) + + |