Make datafy/nav implementation more robust
Also some documentation cleanup
This commit is contained in:
parent
8c508b8416
commit
e85cbf7c95
1 changed files with 40 additions and 34 deletions
|
|
@ -61,8 +61,11 @@
|
||||||
"Protocol for building rows in various representations:
|
"Protocol for building rows in various representations:
|
||||||
->row -- called once per row to create the basis of each row
|
->row -- called once per row to create the basis of each row
|
||||||
column-count -- return the number of columns in each row
|
column-count -- return the number of columns in each row
|
||||||
with-column -- called with the index of the column to be added
|
with-column -- called with the row and the index of the column to be added;
|
||||||
row! -- called once per row to finalize each row once it is complete"
|
this is expected to read the column value from the ResultSet!
|
||||||
|
row! -- called once per row to finalize each row once it is complete
|
||||||
|
|
||||||
|
The default implementation for building hash maps: MapResultSetBuilder"
|
||||||
(->row [_])
|
(->row [_])
|
||||||
(column-count [_])
|
(column-count [_])
|
||||||
(with-column [_ row i])
|
(with-column [_ row i])
|
||||||
|
|
@ -71,8 +74,11 @@
|
||||||
(defprotocol ResultSetBuilder
|
(defprotocol ResultSetBuilder
|
||||||
"Protocol for building result sets in various representations:
|
"Protocol for building result sets in various representations:
|
||||||
->rs -- called to create the basis of the result set
|
->rs -- called to create the basis of the result set
|
||||||
with-row -- called with the row to be added
|
with-row -- called with the result set and the row to be added
|
||||||
rs! -- called to finalize the result set once it is complete"
|
rs! -- called to finalize the result set once it is complete
|
||||||
|
|
||||||
|
Default implementations for building vectors of hash maps and vectors
|
||||||
|
of column names and row values: MapResultSetBuilder & ArrayResultSetBuilder"
|
||||||
(->rs [_])
|
(->rs [_])
|
||||||
(with-row [_ rs row])
|
(with-row [_ rs row])
|
||||||
(rs! [_ rs]))
|
(rs! [_ rs]))
|
||||||
|
|
@ -93,7 +99,7 @@
|
||||||
(rs! [this mrs] (persistent! mrs)))
|
(rs! [this mrs] (persistent! mrs)))
|
||||||
|
|
||||||
(defn as-maps
|
(defn as-maps
|
||||||
"Given a ResultSet and options, return a RowBuilder and ResultSetBuilder
|
"Given a ResultSet and options, return a RowBuilder / ResultSetBuilder
|
||||||
that produces bare vectors of hash map rows."
|
that produces bare vectors of hash map rows."
|
||||||
[^ResultSet rs opts]
|
[^ResultSet rs opts]
|
||||||
(let [rsmeta (.getMetaData rs)
|
(let [rsmeta (.getMetaData rs)
|
||||||
|
|
@ -101,7 +107,7 @@
|
||||||
(->MapResultSetBuilder rs rsmeta cols)))
|
(->MapResultSetBuilder rs rsmeta cols)))
|
||||||
|
|
||||||
(defn as-unqualified-maps
|
(defn as-unqualified-maps
|
||||||
"Given a ResultSet and options, return a RowBuilder and ResultSetBuilder
|
"Given a ResultSet and options, return a RowBuilder / ResultSetBuilder
|
||||||
that produces bare vectors of hash map rows, with simple keys."
|
that produces bare vectors of hash map rows, with simple keys."
|
||||||
[^ResultSet rs opts]
|
[^ResultSet rs opts]
|
||||||
(let [rsmeta (.getMetaData rs)
|
(let [rsmeta (.getMetaData rs)
|
||||||
|
|
@ -122,7 +128,7 @@
|
||||||
(rs! [this ars] (persistent! ars)))
|
(rs! [this ars] (persistent! ars)))
|
||||||
|
|
||||||
(defn as-arrays
|
(defn as-arrays
|
||||||
"Given a ResulSet and options, return a RowBuilder and ResultSetBuilder
|
"Given a ResulSet and options, return a RowBuilder / ResultSetBuilder
|
||||||
that produces a vector of column names followed by vectors of row values."
|
that produces a vector of column names followed by vectors of row values."
|
||||||
[^ResultSet rs opts]
|
[^ResultSet rs opts]
|
||||||
(let [rsmeta (.getMetaData rs)
|
(let [rsmeta (.getMetaData rs)
|
||||||
|
|
@ -130,7 +136,7 @@
|
||||||
(->ArrayResultSetBuilder rs rsmeta cols)))
|
(->ArrayResultSetBuilder rs rsmeta cols)))
|
||||||
|
|
||||||
(defn as-unqualified-arrays
|
(defn as-unqualified-arrays
|
||||||
"Given a ResulSet and options, return a RowBuilder and ResultSetBuilder
|
"Given a ResulSet and options, return a RowBuilder / ResultSetBuilder
|
||||||
that produces a vector of simple column names followed by vectors of row
|
that produces a vector of simple column names followed by vectors of row
|
||||||
values."
|
values."
|
||||||
[^ResultSet rs opts]
|
[^ResultSet rs opts]
|
||||||
|
|
@ -140,6 +146,11 @@
|
||||||
|
|
||||||
(declare navize-row)
|
(declare navize-row)
|
||||||
|
|
||||||
|
(defprotocol DatafiableRow
|
||||||
|
"Given a connectable object, return a function that knows how to turn a row
|
||||||
|
into a datafiable object that can be 'nav'igated."
|
||||||
|
(datafiable-row [this connectable opts]))
|
||||||
|
|
||||||
(defn- row-builder
|
(defn- row-builder
|
||||||
"Given a RowBuilder -- a row materialization strategy -- produce a fully
|
"Given a RowBuilder -- a row materialization strategy -- produce a fully
|
||||||
materialized row from it."
|
materialized row from it."
|
||||||
|
|
@ -149,11 +160,6 @@
|
||||||
(range 1 (inc (column-count gen))))
|
(range 1 (inc (column-count gen))))
|
||||||
(row! gen)))
|
(row! gen)))
|
||||||
|
|
||||||
(defprotocol DatafiableRow
|
|
||||||
"Given a connectable object, return a function that knows how to turn a row
|
|
||||||
into a datafiable object that can be 'nav'igated."
|
|
||||||
(datafiable-row [this connectable opts]))
|
|
||||||
|
|
||||||
(defn- mapify-result-set
|
(defn- mapify-result-set
|
||||||
"Given a result set, return an object that wraps the current row as a hash
|
"Given a result set, return an object that wraps the current row as a hash
|
||||||
map. Note that a result set is mutable and the current row will change behind
|
map. Note that a result set is mutable and the current row will change behind
|
||||||
|
|
@ -162,7 +168,7 @@
|
||||||
Supports ILookup (keywords are treated as strings).
|
Supports ILookup (keywords are treated as strings).
|
||||||
|
|
||||||
Supports Associative (again, keywords are treated as strings). If you assoc,
|
Supports Associative (again, keywords are treated as strings). If you assoc,
|
||||||
a full row will be realized (via seq/into).
|
a full row will be realized (via `row-builder` above).
|
||||||
|
|
||||||
Supports Seqable which realizes a full row of the data."
|
Supports Seqable which realizes a full row of the data."
|
||||||
[^ResultSet rs opts]
|
[^ResultSet rs opts]
|
||||||
|
|
@ -208,12 +214,12 @@
|
||||||
|
|
||||||
(extend-protocol
|
(extend-protocol
|
||||||
DatafiableRow
|
DatafiableRow
|
||||||
java.util.Map ; assume we can "navigate" any kind of hash map for now
|
clojure.lang.IObj ; assume we can "navigate" anything that accepts metadata
|
||||||
|
;; in reality, this is going to be over-optimistic and will like cause `nav`
|
||||||
|
;; to fail on attempts to navigate into result sets that are not hash maps
|
||||||
(datafiable-row [this connectable opts]
|
(datafiable-row [this connectable opts]
|
||||||
(with-meta this
|
(with-meta this
|
||||||
{`core-p/datafy (navize-row connectable opts)}))
|
{`core-p/datafy (navize-row connectable opts)})))
|
||||||
clojure.lang.IObj ; but we cannot "navigate" other things
|
|
||||||
(datafiable-row [this connectable opts] this))
|
|
||||||
|
|
||||||
(defn- stmt->result-set
|
(defn- stmt->result-set
|
||||||
"Given a PreparedStatement and options, execute it and return a ResultSet
|
"Given a PreparedStatement and options, execute it and return a ResultSet
|
||||||
|
|
@ -370,27 +376,27 @@
|
||||||
"Given a connectable object, return a function that knows how to turn a row
|
"Given a connectable object, return a function that knows how to turn a row
|
||||||
into a navigable object.
|
into a navigable object.
|
||||||
|
|
||||||
A :schema option can provide a map of qualified column names (:table/column)
|
A `:schema` option can provide a map from qualified column names
|
||||||
to tuples that indicate which table they are a foreign key for, the name of
|
(`:<table>/<column>`) to tuples that indicate for which table they are a
|
||||||
the key within that table, and (optionality) the cardinality of that
|
foreign key, the name of the key within that table, and (optionality) the
|
||||||
relationship (:many, :one).
|
cardinality of that relationship (`:many`, `:one`).
|
||||||
|
|
||||||
If no :schema item is provided for a column, the convention of <table>id or
|
If no `:schema` item is provided for a column, the convention of <table>id or
|
||||||
<table>_id is used, and the assumption is that such columns are foreign keys
|
<table>_id is used, and the assumption is that such columns are foreign keys
|
||||||
in the <table> portion of their name, the key is called 'id', and the
|
in the <table> portion of their name, the key is called `id`, and the
|
||||||
cardinality is :one.
|
cardinality is :one.
|
||||||
|
|
||||||
Rows are looked up using 'execute!' or 'execute-one!' and the :table-fn
|
Rows are looked up using `-execute-all` or `-execute-one` and the `:table-fn`
|
||||||
function, if provided, is applied to both the assumed table name and the
|
option, if provided, is applied to both the assumed table name and the
|
||||||
assumed foreign key column name."
|
assumed foreign key column name."
|
||||||
[connectable opts]
|
[connectable opts]
|
||||||
(fn [row]
|
(fn [row]
|
||||||
(with-meta row
|
(with-meta row
|
||||||
{`core-p/nav (fn [coll k v]
|
{`core-p/nav (fn [coll k v]
|
||||||
(let [[table fk cardinality] (or (get-in opts [:schema k])
|
(try
|
||||||
(default-schema k))]
|
(let [[table fk cardinality] (or (get-in opts [:schema k])
|
||||||
(if fk
|
(default-schema k))]
|
||||||
(try
|
(if fk
|
||||||
(let [entity-fn (:table-fn opts identity)
|
(let [entity-fn (:table-fn opts identity)
|
||||||
exec-fn! (if (= :many cardinality)
|
exec-fn! (if (= :many cardinality)
|
||||||
p/-execute-all
|
p/-execute-all
|
||||||
|
|
@ -403,8 +409,8 @@
|
||||||
" = ?")
|
" = ?")
|
||||||
v]
|
v]
|
||||||
opts))
|
opts))
|
||||||
(catch Exception _
|
v))
|
||||||
;; assume an exception means we just cannot
|
(catch Exception _
|
||||||
;; navigate anywhere, so return just the value
|
;; assume an exception means we just cannot
|
||||||
v))
|
;; navigate anywhere, so return just the value
|
||||||
v)))})))
|
v)))})))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue