Common code shared by various after- methods. Since the after methods operate over instances, we need to upgrade
result-type/pks and result-type/update-count queries to result-type/instances, run them with the 'upgraded'
result type, run our after stuff on each row, and then return the original results.
Common code shared by various `after-` methods. Since the `after` methods operate over instances, we need to upgrade `result-type/pks` and `result-type/update-count` queries to `result-type/instances`, run them with the 'upgraded' result type, run our after stuff on each row, and then return the original results.
Macros that can wrap a form and return the built query, compiled query, etc. without executing it.
Macros that can wrap a form and return the built query, compiled query, etc. without executing it.
No vars found in this namespace.
hydrate adds one or more keys to an instance or instances using various hydration strategies, usually using one of
the existing keys in those instances. A typical use case would be to take a sequence of orders and add :user keys
to them based on their values of the foreign key :user-id.
hydrate is how you use the hydration facilities; everything else in this namespace is only for extending
hydration to support your models.
Toucan 2 ships with several hydration strategies out of the box:
model-for-automagic-hydration)hydrate attempts to do a batched hydration where possible. If the key being hydrated is defined as one of some
table's model-for-automagic-hydration, hydrate will do a batched
toucan2.select/select if a corresponding key (by default, the same key suffixed by -id) is found in the
objects being batch hydrated. The corresponding key can be customized by
implementing fk-keys-for-automagic-hydration.
(hydrate [{:user_id 100}, {:user_id 101}] :user)
Since :user is a hydration key for :models/User, a single toucan2.select/select will used to fetch Users:
(db/select :models/User :id [:in #{100 101}])
The corresponding Users are then added under the key :user.
batched-hydrate methods)If the key can't be hydrated auto-magically with the appropriate model-for-automagic-hydration,
hydrate will attempt to do batched hydration if it can find a matching method
for batched-hydrate. If a matching function is found, it is called with a collection of
objects, e.g.
(m/defmethod hydrate/batched-hydrate [:default :fields]
[_model _k instances]
(let [id->fields (get-some-fields instances)]
(for [instance instances]
(assoc instance :fields (get id->fields (:id instance))))))
simple-hydrate methods)If the key is not eligible for batched hydration, hydrate will look for a matching
simple-hydrate method. simple-hydrate is called with a single instance.
(m/defmethod simple-hydrate [:default :dashboard]
[_model _k {:keys [dashboard-id], :as instance}]
(assoc instance :dashboard (select/select-one :models/Dashboard :toucan/pk dashboard-id)))
You can hydrate several keys at one time:
(hydrate {...} :a :b)
-> {:a 1, :b 2}
You can do recursive hydration by listing keys inside a vector:
(hydrate {...} [:a :b])
-> {:a {:b 1}}
The first key in a vector will be hydrated normally, and any subsequent keys will be hydrated inside the corresponding values for that key.
(hydrate {...}
[:a [:b :c] :e])
-> {:a {:b {:c 1} :e 2}}
Normally, hydration is skipped if an instance already has a non-nil value for the key being hydrated, but you can
override this behavior by implementing needs-hydration?.
If you're digging in to the details, this is a flowchart of how hydration works:
hydrate ◄─────────────┐
│ │
▼ │
hydrate-forms │
│ │
▼ │ (recursively)
hydrate-one-form │
│ │
keyword? ◄─┴─► sequence? │
│ │ │
▼ ▼ │
hydrate-key hydrate-key-seq ─┘
│
▼
(for each strategy) ◄────────┐
::automagic-batched │
::multimethod-batched │
::multimethod-simple │
│ │ (try next strategy)
▼ │
can-hydrate-with-strategy? │
│ │
yes ◄──┴──► no ────────────┘
│
▼
hydrate-with-strategy
[[hydrate]] adds one or more keys to an instance or instances using various hydration strategies, usually using one of
the existing keys in those instances. A typical use case would be to take a sequence of `orders` and add `:user` keys
to them based on their values of the foreign key `:user-id`.
[[hydrate]] is how you *use* the hydration facilities; everything else in this namespace is only for extending
hydration to support your models.
Toucan 2 ships with several hydration strategies out of the box:
#### Automagic Batched Hydration (via [[model-for-automagic-hydration]])
[[hydrate]] attempts to do a *batched hydration* where possible. If the key being hydrated is defined as one of some
table's [[model-for-automagic-hydration]], `hydrate` will do a batched
[[toucan2.select/select]] if a corresponding key (by default, the same key suffixed by `-id`) is found in the
objects being batch hydrated. The corresponding key can be customized by
implementing [[fk-keys-for-automagic-hydration]].
```clj
(hydrate [{:user_id 100}, {:user_id 101}] :user)
```
Since `:user` is a hydration key for `:models/User`, a single [[toucan2.select/select]] will used to fetch Users:
```clj
(db/select :models/User :id [:in #{100 101}])
```
The corresponding Users are then added under the key `:user`.
#### Function-Based Batched Hydration (via [[batched-hydrate]] methods)
If the key can't be hydrated auto-magically with the appropriate [[model-for-automagic-hydration]],
[[hydrate]] will attempt to do batched hydration if it can find a matching method
for [[batched-hydrate]]. If a matching function is found, it is called with a collection of
objects, e.g.
```clj
(m/defmethod hydrate/batched-hydrate [:default :fields]
[_model _k instances]
(let [id->fields (get-some-fields instances)]
(for [instance instances]
(assoc instance :fields (get id->fields (:id instance))))))
```
#### Simple Hydration (via [[simple-hydrate]] methods)
If the key is *not* eligible for batched hydration, [[hydrate]] will look for a matching
[[simple-hydrate]] method. `simple-hydrate` is called with a single instance.
```clj
(m/defmethod simple-hydrate [:default :dashboard]
[_model _k {:keys [dashboard-id], :as instance}]
(assoc instance :dashboard (select/select-one :models/Dashboard :toucan/pk dashboard-id)))
```
#### Hydrating Multiple Keys
You can hydrate several keys at one time:
```clj
(hydrate {...} :a :b)
-> {:a 1, :b 2}
```
#### Nested Hydration
You can do recursive hydration by listing keys inside a vector:
```clj
(hydrate {...} [:a :b])
-> {:a {:b 1}}
```
The first key in a vector will be hydrated normally, and any subsequent keys will be hydrated *inside* the
corresponding values for that key.
```clj
(hydrate {...}
[:a [:b :c] :e])
-> {:a {:b {:c 1} :e 2}}
```
### Forcing Hydration
Normally, hydration is skipped if an instance already has a non-nil value for the key being hydrated, but you can
override this behavior by implementing [[needs-hydration?]].
### Flowchart
If you're digging in to the details, this is a flowchart of how hydration works:
```
hydrate ◄─────────────┐
│ │
▼ │
hydrate-forms │
│ │
▼ │ (recursively)
hydrate-one-form │
│ │
keyword? ◄─┴─► sequence? │
│ │ │
▼ ▼ │
hydrate-key hydrate-key-seq ─┘
│
▼
(for each strategy) ◄────────┐
::automagic-batched │
::multimethod-batched │
::multimethod-simple │
│ │ (try next strategy)
▼ │
can-hydrate-with-strategy? │
│ │
yes ◄──┴──► no ────────────┘
│
▼
hydrate-with-strategy
```cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |