Skip to content

Commit

Permalink
Merge pull request #151 from walkable-server/exists
Browse files Browse the repository at this point in the history
Exists
  • Loading branch information
myguidingstar authored Mar 22, 2019
2 parents 42b52a2 + 0b28fa5 commit 6216dc7
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 17 deletions.
6 changes: 4 additions & 2 deletions src/walkable/sql_query_builder.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@

(defn process-supplied-condition
[{::keys [floor-plan] :as env}]
(let [{::floor-plan/keys [compiled-formulas join-filter-subqueries]}
(let [{::floor-plan/keys [compiled-formulas compiled-exists-forms
join-filter-subqueries]}
floor-plan

supplied-condition
(get-in env [:ast :params :filters])]
(when supplied-condition
(->> supplied-condition
(expressions/compile-to-string
{:join-filter-subqueries join-filter-subqueries})
{:compiled-exists-forms compiled-exists-forms
:join-filter-subqueries join-filter-subqueries})
(expressions/substitute-atomic-variables
{:variable-values compiled-formulas})))))

Expand Down
8 changes: 8 additions & 0 deletions src/walkable/sql_query_builder/expressions.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@
{:raw-string (str "CAST (? AS " type-str ")")
:params [(process-expression env expression)]})))

(defmethod unsafe-expression? :exists [_operator] true)

(defmethod process-unsafe-expression :exists
[{:keys [compiled-exists-forms] :as env} [_operator [column-keyword]]]
(if-let [compiled (get compiled-exists-forms column-keyword)]
compiled
(throw (ex-info "Invalid column supplied to :exists" {}))))

(defmethod operator? :and [_operator] true)

(defmethod process-operator :and
Expand Down
58 changes: 45 additions & 13 deletions src/walkable/sql_query_builder/floor_plan.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@
(zipmap ks
(map #(emitter/clojuric-name emitter %) ks)))

(defn compile-exists [emitter column-keyword]
{:raw-string (str "EXISTS (SELECT "
(emitter/column-name emitter column-keyword)
" FROM "
(emitter/table-name emitter column-keyword)
")")
:params []})

(defn compile-exists-forms [emitter column-keywords]
(apply hash-map
(interleave column-keywords
(map #(compile-exists emitter %) column-keywords))))

(s/def ::without-join-table
(s/coll-of ::expressions/namespaced-keyword
:count 2))
Expand Down Expand Up @@ -233,9 +246,11 @@
(defn rotate [coll]
(take (count coll) (drop 1 (cycle coll))))

(defn compile-formulas-once [compiled-true-columns formulas]
(defn compile-formulas-once [compiled-true-columns compiled-exists-forms formulas]
(reduce-kv (fn [result k expression]
(let [compiled (expressions/compile-to-string {} expression)]
(let [compiled (expressions/compile-to-string
{:compiled-exists-forms compiled-exists-forms}
expression)]
(if (unbound-expression? compiled)
(update result :unbound assoc k compiled)
(update result :bound assoc k compiled))))
Expand Down Expand Up @@ -368,9 +383,10 @@
(map #(expressions/verbatim-raw-string (emitter/column-name emitter %)) ks)))

(defn compile-formulas
[{:keys [true-columns pseudo-columns aggregators emitter] :as floor-plan}]
[{:keys [true-columns pseudo-columns aggregators emitter compiled-exists-forms]
:as floor-plan}]
(let [compiled-formulas (-> (compile-true-columns emitter true-columns)
(compile-formulas-once (merge pseudo-columns aggregators))
(compile-formulas-once compiled-exists-forms (merge pseudo-columns aggregators))
compile-formulas-recursively)
_ok? (column-dependencies compiled-formulas)
{:keys [bound unbound]} compiled-formulas
Expand All @@ -388,13 +404,15 @@
(assoc floor-plan :compiled-selection compiled-selection)))

(defn compile-ident-conditions
[{:keys [conditional-idents compiled-formulas] :as floor-plan}]
[{:keys [conditional-idents compiled-formulas compiled-exists-forms]
:as floor-plan}]
(let [compiled-ident-conditions
(reduce-kv (fn [acc k ident-key]
(assoc acc k
(expressions/substitute-atomic-variables
{:variable-values compiled-formulas}
(expressions/compile-to-string {}
(expressions/compile-to-string
{:compiled-exists-forms compiled-exists-forms}
[:= ident-key (expressions/av `ident-value)]))))
{}
conditional-idents)]
Expand Down Expand Up @@ -441,15 +459,17 @@
(assoc :compiled-aggregator-selection compiled-aggregator-selection))))

(defn compile-join-conditions
[{:keys [joins compiled-formulas target-columns] :as floor-plan}]
[{:keys [joins compiled-formulas target-columns compiled-exists-forms]
:as floor-plan}]
(let [compiled-join-conditions
(reduce-kv (fn [acc k join-seq]
(let [target-column (get target-columns k)
clojuric-name (get clojuric-names target-column)]
(assoc acc k
(expressions/substitute-atomic-variables
{:variable-values compiled-formulas}
(expressions/compile-to-string {}
(expressions/compile-to-string
{:compiled-exists-forms compiled-exists-forms}
[:= target-column (expressions/av `source-column-value)])))))
{}
joins)]
Expand Down Expand Up @@ -488,13 +508,16 @@
(dissoc :joins))))

(defn compile-extra-conditions
[{:keys [extra-conditions compiled-formulas join-filter-subqueries] :as floor-plan}]
[{:keys [extra-conditions compiled-formulas compiled-exists-forms
join-filter-subqueries]
:as floor-plan}]
(let [compiled-extra-conditions
(reduce-kv (fn [acc k extra-condition]
(assoc acc k
(->> extra-condition
(expressions/compile-to-string
{:join-filter-subqueries join-filter-subqueries})
{:compiled-exists-forms compiled-exists-forms
:join-filter-subqueries join-filter-subqueries})
(expressions/substitute-atomic-variables
{:variable-values compiled-formulas}))))
{}
Expand All @@ -509,10 +532,12 @@
:params [compiled-having]}))

(defn compile-having
[{:keys [compiled-formulas join-filter-subqueries]} having-condition]
[{:keys [compiled-formulas join-filter-subqueries compiled-exists-forms]}
having-condition]
(->> having-condition
(expressions/compile-to-string
{:join-filter-subqueries join-filter-subqueries})
{:compiled-exists-forms compiled-exists-forms
:join-filter-subqueries join-filter-subqueries})
(expressions/substitute-atomic-variables
{:variable-values compiled-formulas})
prefix-having))
Expand Down Expand Up @@ -592,6 +617,7 @@
:batch-query
:cardinality
:clojuric-names
:compiled-exists-forms
:column-keywords
:compiled-extra-conditions
:compiled-formulas
Expand Down Expand Up @@ -704,6 +730,11 @@
(-> floor-plan
(assoc :clojuric-names (clojuric-names emitter column-keywords))))

(defn prepare-exists-forms
[{:keys [emitter column-keywords] :as floor-plan}]
(-> floor-plan
(assoc :compiled-exists-forms (compile-exists-forms emitter column-keywords))))

(defn separate-floor-plan-keys
[{:keys [joins emitter idents
extra-conditions]
Expand All @@ -712,7 +743,8 @@
separate-idents
polulate-columns-with-condititional-idents
prepare-keywords
prepare-clojuric-names))
prepare-clojuric-names
prepare-exists-forms))

(defn precompile-floor-plan
[{:keys [joins emitter idents unconditional-idents conditional-idents] :as floor-plan}]
Expand Down
27 changes: 25 additions & 2 deletions test/walkable/sql_query_builder/floor_plan_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
(is (= (sut/clojuric-names emitter/mysql-emitter [:foo/bar :loo/lar])
{:foo/bar "`foo/bar`", :loo/lar "`loo/lar`"})))

(deftest compile-exists-test
(is (= (sut/compile-exists emitter/default-emitter :foo/bar)
{:raw-string "EXISTS (SELECT \"foo\".\"bar\" FROM \"foo\")", :params []})))

(deftest target-column-tests
(is (= (sut/target-column [:pet/owner :person/number])
:person/number))
Expand Down Expand Up @@ -142,6 +146,7 @@
(is (= (sut/compile-formulas-once
(sut/compile-true-columns emitter/postgres-emitter
#{:x/a :x/b})
{}
{:x/c 99
:x/d [:- 100 :x/c]})
{:unbound #:x {:d {:params [(expressions/av :x/c)],
Expand All @@ -151,24 +156,42 @@
:c {:raw-string "99", :params []}}})))

(deftest compile-formulas-recursively-test
(is (= (sut/compile-formulas-recursively
(sut/compile-formulas-once
(sut/compile-true-columns
emitter/postgres-emitter #{:x/a :x/b})
{}
{:x/c 99
:x/d [:- 100 :x/c]}))
{:unbound {},
:bound #:x {:a {:raw-string "\"x\".\"a\"", :params []},
:b {:raw-string "\"x\".\"b\"", :params []},
:c {:raw-string "99", :params []},
:d {:raw-string "(100)-(99)", :params []}}}))

(is (= (sut/compile-formulas-recursively
(sut/compile-formulas-once
(sut/compile-true-columns
emitter/postgres-emitter #{:x/a :x/b})
(sut/compile-exists-forms
emitter/postgres-emitter #{:x/a :x/b})
{:x/c 99
:x/d [:- 100 :x/c]}))
:x/d [:- 100 :x/c]
:x/e [:exists :x/a]}))
{:unbound {},
:bound #:x {:a {:raw-string "\"x\".\"a\"", :params []},
:b {:raw-string "\"x\".\"b\"", :params []},
:c {:raw-string "99", :params []},
:d {:raw-string "(100)-(99)", :params []}}})))
:d {:raw-string "(100)-(99)", :params []}
:e {:raw-string "EXISTS (SELECT \"x\".\"a\" FROM \"x\")", :params []}}})))

(deftest column-dependencies-test
(is (= (sut/column-dependencies
(sut/compile-formulas-recursively
(sut/compile-formulas-once
(sut/compile-true-columns
emitter/postgres-emitter #{:x/a :x/b})
{}
{:x/c [:+ :x/d (expressions/av 'o)]
:x/d [:- 100 :x/e]
:x/e [:- 100 :x/c]})))
Expand Down

0 comments on commit 6216dc7

Please sign in to comment.