diff --git a/CHANGELOG.md b/CHANGELOG.md index 219482d..52ad68d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Only accretive/fixative changes will be made from now on. * 1.2.next in progress + * To support more tools that perform `datafy`/`nav`, make rows directly `nav`able (even though this is not really the correct behavior). * Address #193 by expanding the argument specs for `get-datasource` and `get-connection`. * Streamline `execute-batch!` for `with-options` and `with-logging` (and this should generalize to any wrapper that satisfies `Connectable` and stores the actual `Connection` under the `:connectable` key). * Update log4j2 test dependency. diff --git a/src/next/jdbc/result_set.clj b/src/next/jdbc/result_set.clj index 23506ab..3ef5193 100644 --- a/src/next/jdbc/result_set.clj +++ b/src/next/jdbc/result_set.clj @@ -408,6 +408,7 @@ i))))) (declare navize-row) +(declare navable-row) (defprotocol DatafiableRow "Protocol for making rows datafiable and therefore navigable. @@ -570,6 +571,8 @@ assoc `core-p/datafy (navize-row connectable opts) + `core-p/nav + (navable-row connectable opts) `row-number (fn [_] (if (instance? Throwable row) (throw row) row)) `column-names @@ -609,7 +612,8 @@ (vary-meta this assoc - `core-p/datafy (navize-row connectable opts)))) + `core-p/datafy (navize-row connectable opts) + `core-p/nav (navable-row connectable opts)))) (defn datafiable-result-set "Given a ResultSet, a connectable, and an options hash map, return a fully @@ -1096,3 +1100,45 @@ ;; assume an exception means we just cannot ;; navigate anywhere, so return just the value v)))))) + +(defn- navable-row + "Given a connectable object, return a function that knows how to `nav` + into a row. + + A `:schema` option can provide a map from qualified column names + (`:/`) to tuples that indicate for which table they are a + foreign key, the name of the key within that table, and (optionality) the + cardinality of that relationship (`:many`, `:one`). + + If no `:schema` item is provided for a column, the convention of `
id` or + `
_id` is used, and the assumption is that such columns are foreign keys + in the `
` portion of their name, the key is called `id`, and the + cardinality is `:one`. + + Rows are looked up using `-execute-all` or `-execute-one`, and the `:table-fn` + option, if provided, is applied to both the assumed table name and the + assumed foreign key column name." + [connectable opts] + (fn [_ k v] + (try + (let [[table fk cardinality] + (expand-schema k (or (get-in opts [:schema k]) + (default-schema k)))] + (if (and fk connectable) + (let [entity-fn (:table-fn opts identity) + exec-fn! (if (= :many cardinality) + p/-execute-all + p/-execute-one)] + (exec-fn! connectable + [(str "SELECT * FROM " + (entity-fn (name table)) + " WHERE " + (entity-fn (name fk)) + " = ?") + v] + opts)) + v)) + (catch Exception _ + ;; assume an exception means we just cannot + ;; navigate anywhere, so return just the value + v))))