Skip to content

Instantly share code, notes, and snippets.

@bwalex
Created November 27, 2018 20:44
Show Gist options
  • Save bwalex/bb3d3a757ab6071a2623f10512710907 to your computer and use it in GitHub Desktop.
Save bwalex/bb3d3a757ab6071a2623f10512710907 to your computer and use it in GitHub Desktop.
(comment
(jdbc/query db sqlvec {:identifiers ...
:keywordize? ...
:qualifier ...})
(def sql-schema
{:tables {:location "locations"
:part "parts"
:stock "stock"
:stock-log "stock_log"}
:columns {:location
#{:id :name :description}
:part
#{:id :mpn :manufacturer}
:stock
#{:id :part-id :location-id :qty}
:stock-log
#{:id :part-id :location-id :qty :qty-change}}
:idents {:locations/all :location
:parts/all :part
:stock-log/by-location :stock-log/location-id
:stock-log/by-part :stock-log/part-id}
:joins {:part/stock [:part/id :stock/part-id]
:location/stock [:location/id :stock/location-id]
:part/stock-log [:part/id :stock-log/part-id]
:location/stock-log [:location/id :stock-log/location-id]}
:reversed-joins {:stock/part :part/stock
:stock/location :location/stock
:stock-log/part :part/stock-log
:stock-log/location :location/stock-log}
:cardinality {:part/updated-by :one
:stock/updated-by :one
:stock-log/updated-by :one
:location/updated-by :one
:stock/part :one
:stock/location :one
:stock-log/part :one
:stock-log/location :one}
:alias-cols {:stock/part-id :part/id
:stock/location-id :location/id
:stock-log/part-id :part/id
:stock-log/location-id :location/id}})
;; 1. for each ident, generate a resolver
;; a. if RHS doesn't have a namespace, it's a query without inputs
;; b. if RHS does have a namespace, it's a query WHERE rhs_field = input_value
;; 2. for each join, generate a resolver with output of LHS FROM ns-of-rhs_field.2 WHERE rhs_field.2 = input_value (where input is rhs_field.1)
;; depending on cardinality, do a (first) on the result...
;; 3. turn reversed join into forward joins by renaming LHS, swapping RHS entries and do step 2 again.
;; 4. for each alias-col, do a pc/alias-resolver2 thing
(defn expand-joins [{:keys [joins reversed-joins]}]
(reduce
(fn [a [k v]]
(let [fwd-join (get joins v)]
(assoc a k [(second fwd-join) (first fwd-join)])))
joins
reversed-joins))
(expand-joins sql-schema)
(defn compile-schema [schema]
(merge schema
{::expanded-joins (expand-joins schema)}))
(def compiled-schema (compile-schema sql-schema))
(defn query-fields [{::keys [expanded-joins]} pq]
(->> pq
(mapcat #(if (map? %) (keys %) [%]))
(map (fn [x]
(if-let [join (get expanded-joins x)]
(first join)
x)))))
(query-fields compiled-schema
[:stock/id :stock/qty :stock/part-id])
(query-fields compiled-schema
[:stock/id :stock/qty :stock/part-id {:stock/location [:location/id]}])
(defn build-query [qmap]
qmap)
(defn build-joins [schema]
(for [join (::expanded-joins schema)]
(let [[output [input ns-col]] join
table (namespace ns-col)
col (name ns-col)
target-cols (get-in schema [:columns (keyword table)])
;; e.g: env {::p/parent-query [:stock/id :stock/qty :stock/part-id {:stock/location [:location/id]}]}
resolve-fn
(fn [env entity]
(let [fields (->> (::p/parent-query env)
(query-fields schema)
(filter #(= (namespace %) table))
(map (comp keyword name))
(filter target-cols)) ]
(build-query {:select fields
:from [table]
:where [:= col]})))]
{::pc/sym (gensym)
::pc/input #{input}
::pc/output [{output (mapv (comp (partial keyword table) name) target-cols)}]
::pc/resolve resolve-fn})))
(build-joins compiled-schema)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment