Khepri projections

Projections build a replicated ETS table using tree nodes from the store
which match a `khepri_path:pattern()`

. When a tree node matching a
projection's pattern is changed in the store, the tree node is passed
through the projection's `projection_fun()`

to create record(s).
These records are then stored in the projection's ETS table for all members
in a Khepri cluster.

Projections provide a way to query the store as fast as possible and are appropriate for lookups which require low latency and/or high throughput. Projection tables contain all records matching the pattern, though, so the memory footprint of a projection table grows with the number of tree nodes in the store matching the pattern.

Projection ETS tables are owned by the Khepri cluster and are deleted when the cluster stops.

Updates to projection tables are immediately consistent for the member of the cluster on which the change to the store is made and the leader member but are eventually consistent for all other followers.`extended_projection_fun() = fun((Table::ets:tid(), Path::khepri_path:native_path(), OldPayload::khepri:node_props(), NewPayload::khepri:node_props()) -> any())`

An extended projection function.

In some cases, a tree node in the store might correspond to many objects in a projection table. Extended projection functions are allowed to call ETS functions directly in order to build the projection table.

`OldPayload`

or `NewPayload`

are empty maps if there is no tree node. For
example, a newly created tree node will have an empty map for `OldPayload`

and a `khepri:node_props()`

map with values for `NewPayload`

.

This function is compiled like a transaction function except that calls
to the `ets`

module are allowed.

`options() = #{type => ets:table_type(), keypos => pos_integer(), read_concurrency => boolean(), write_concurrency => boolean() | auto, compressed => boolean(), standalone_fun_options => horus:options()}`

Options which control the created ETS table.

If provided, `standalone_fun_options`

are merged with defaults and passed to
`horus:to_standalone_fun/2`

. The remaining options are a subset of the
options available to `ets:new/2`

. Refer to the `ets:new/2`

documentation for a reference on each type and available values.

`simple_projection_fun()`

, the
`type`

option may only be `set`

or `ordered_set`

: `bag`

types are not
allowed. `extended_projection_fun()`

s may use any valid `ets:table_type()`

.
`projection() = #khepri_projection{name = atom(), projection_fun = copy | horus:horus_fun(), ets_options = [atom() | tuple()]}`

A projection resource.

`projection_fun() = copy | simple_projection_fun() | extended_projection_fun()`

A function that formats an entry in the tree into a record to be stored in a projection.

Projection functions may either be:- "simple" - a function that takes the path within the tree for a tree
node and the payload and returns a record. See
`simple_projection_fun()`

. - "copy" - a projection that ignores the path and use the tree node's payload as the record directly. This is a special case that avoids the overhead of executing standalone functions for the sake of performance.
- "extended" - a function that takes the ETS table identifier, path, and
old and new tree node properties and executes ETS functions directly.
See
`extended_projection_fun()`

.

`simple_projection_fun() = fun((Path::khepri_path:native_path(), Payload::khepri:data()) -> Record::tuple())`

A simple projection function.

Simple projection functions only take the path and payload for a tree node in the store. The record produced by the function is used to create and delete objects in the ETS table.

This function is compiled the same way as a transaction function: all side-effects are not allowed. Additionally, for any`Path`

and `Payload`

inputs, this function must consistently return the same `Record`

.
new/2 | |

new/3 | Creates a new projection data structure. |

name/1 | Returns the name of the given `Projection` . |

delete/1 |

`new(Name, ProjectionFun) -> Projection`

`Name = atom()`

`ProjectionFun = khepri_projection:projection_fun()`

`Projection = khepri_projection:projection()`

**See also:** khepri:register_projection/4, khepri_projection:new/3.

`new(Name, ProjectionFun, Options) -> Projection`

`Name = atom()`

`ProjectionFun = khepri_projection:projection_fun()`

`Options = khepri_projection:options()`

`Projection = khepri_projection:projection()`

`Name`

: the name of the projection. This corresponds to the name of
the ETS table which is created when the projection is registered.

`ProjectionFun`

: the function which turns paths and data into records
to be stored in the projection table.

`Options`

: options which control properties of the projection table.

returns: a `projection()`

resource.

Creates a new projection data structure.

This function throws an error in the shape of```
{unexpected_option, Key,
Value}
```

when an unknown or invalid `option()`

is passed. For example,
if the passed `ProjectionFun`

is a `simple_projection_fun()`

and the
`Options`

map sets the `type`

to `bag`

, this function throws
`{unexpected_option, type, bag}`

since `bag`

is not valid for simple
projection funs.
`name(Projection) -> Name`

`Projection = projection()`

`Name = atom()`

Returns the name of the given `Projection`

.

`delete(Khepri_projection) -> any()`

*Generated by EDoc*