Store elements on the context.

This commit is contained in:
Richard Newman 2016-07-13 12:42:01 -07:00
parent 64460f7eef
commit 437a80a978

View file

@ -29,7 +29,7 @@
;; `:bindings` is a map from var to qualified columns. ;; `:bindings` is a map from var to qualified columns.
;; `:wheres` is a list of fragments that can be joined by `:and`. ;; `:wheres` is a list of fragments that can be joined by `:and`.
;; ;;
(defrecord Context [from bindings wheres attribute-transform constant-transform]) (defrecord Context [from bindings wheres elements attribute-transform constant-transform])
(defn attribute-in-context [context attribute] (defn attribute-in-context [context attribute]
((:attribute-transform context) attribute)) ((:attribute-transform context) attribute))
@ -53,7 +53,7 @@
(raise (str "Couldn't find variable " variable)))) (raise (str "Couldn't find variable " variable))))
(defn make-context [] (defn make-context []
(->Context [] {} [] (->Context [] {} [] []
transforms/attribute-transform-string transforms/attribute-transform-string
transforms/constant-transform-default)) transforms/constant-transform-default))
@ -124,12 +124,15 @@
(assoc context :wheres (concat (bindings->where (:bindings context)) (assoc context :wheres (concat (bindings->where (:bindings context))
(:wheres context)))) (:wheres context))))
(defn apply-elements-to-context [context elements]
(assoc context :elements elements))
(defn patterns->context (defn patterns->context
"Turn a sequence of patterns into a Context." "Turn a sequence of patterns into a Context."
[patterns] [patterns]
(reduce apply-pattern-to-context (make-context) patterns)) (reduce apply-pattern-to-context (make-context) patterns))
(defn elements->sql-projection (defn sql-projection
"Take a `find` clause's `:elements` list and turn it into a SQL "Take a `find` clause's `:elements` list and turn it into a SQL
projection clause, suitable for passing as a `:select` clause to projection clause, suitable for passing as a `:select` clause to
honeysql. honeysql.
@ -146,19 +149,30 @@
[[:datoms12.e :foo] [:datoms13.e :bar]] [[:datoms12.e :foo] [:datoms13.e :bar]]
@param context A Context. @param context A Context, containing elements.
@param elements The input clause.
@return a sequence of pairs." @return a sequence of pairs."
[context elements] [context]
(let [elements (:elements context)]
(when-not (every? #(instance? Variable %1) elements) (when-not (every? #(instance? Variable %1) elements)
(raise "Unable to :find non-variables.")) (raise "Unable to :find non-variables."))
(map (fn [elem] (map (fn [elem]
(let [var (:symbol elem)] (let [var (:symbol elem)]
[(lookup-variable context var) (var->sql-var var)])) [(lookup-variable context var) (var->sql-var var)]))
elements)) elements)))
(defn context->sql-clause [context elements] (defn row-transducer [context projection rf]
{:select (elements->sql-projection context elements) ;; For now, we only support straight var lists, so
;; our transducer is trivial.
(let [columns-in-order (map second projection)
row-mapper (fn [row] (map columns-in-order row))]
(fn
([] (rf))
([result] (rf result))
([result input]
(rf result (row-mapper input))))))
(defn context->sql-clause [context]
{:select (sql-projection context)
:from (:from context) :from (:from context)
:where (if (empty? (:wheres context)) :where (if (empty? (:wheres context))
nil nil
@ -173,6 +187,18 @@
(= "$" (name (-> in first :variable :symbol)))) (= "$" (name (-> in first :variable :symbol))))
(raise (str "Complex `in` not supported: " (print-str in))))) (raise (str "Complex `in` not supported: " (print-str in)))))
(defn find->prepared-context [find]
;; There's some confusing use of 'where' and friends here. That's because
;; the parsed Datalog includes :where, and it's also input to honeysql's
;; SQL formatter.
(let [{:keys [find in with where]} find] ; Destructure the Datalog query.
(validate-with with)
(validate-in in)
(apply-elements-to-context
(expand-where-from-bindings
(patterns->context where)) ; 'where' here is the Datalog :where clause.
(:elements find))))
(defn find->sql-clause (defn find->sql-clause
"Take a parsed `find` expression and turn it into a structured SQL "Take a parsed `find` expression and turn it into a structured SQL
expression that can be formatted by honeysql." expression that can be formatted by honeysql."
@ -180,13 +206,8 @@
;; There's some confusing use of 'where' and friends here. That's because ;; There's some confusing use of 'where' and friends here. That's because
;; the parsed Datalog includes :where, and it's also input to honeysql's ;; the parsed Datalog includes :where, and it's also input to honeysql's
;; SQL formatter. ;; SQL formatter.
(let [{:keys [find in with where]} find] ; Destructure the Datalog query.
(validate-with with)
(validate-in in)
(context->sql-clause (context->sql-clause
(expand-where-from-bindings (find->prepared-context find)))
(patterns->context where)) ; 'where' here is the Datalog :where clause.
(:elements find))))
(defn find->sql-string (defn find->sql-string
"Take a parsed `find` expression and turn it into SQL." "Take a parsed `find` expression and turn it into SQL."