# `AshCache.Calculations.CalculateThrough`
[🔗](https://github.com/Undeadlol1/ash_cache/blob/v0.1.0/lib/ash_cache/calculations/calculate_through.ex#L1)

Caching for a module calculation, one entry per record.

`AshCache.Resource.Transformers.AttachCacheHooks` puts this module in the
calculation's place and hands it the original as the `:calculation`
option. `init/1`, `describe/1` and `load/3` are passed to the original,
so Ash still loads everything the original needs.

For a batch of records, each record is looked up on its own; the
original runs once, only for the records that were not found, and the
results go back in the records' order. `nil` and `[]` are real results
and are cached. An `{:error, _}` or `:unknown` from the original is
returned unchanged and nothing is cached.

The key (`AshCache.Key`) holds the calculation's arguments, the actor,
the tenant, every attribute of the record and the value of every field
the original loads: the fields its `load/3` names (asked again with a
fresh query of the resource) and the calculation's own `load` option.
So a change to anything the calculation can read gives a new key, and a
stale result is never served; old entries simply expire after the `ttl`.
Writes and `AshCache.invalidate/1` do not touch these entries.

`strict_loads?/0` is `false`, so related records are loaded with all
their attributes. A callback without options cannot tell what the
original says, and loading more is always safe.

A load with `context: %{ash_cache: :bypass}` skips the cache.

Known limit: identical misses running at the same time each run the
original; there is no `AshCache.Coalesce` for calculations.

# `has_calculate?`

# `has_expression?`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
