Condition support.
Conditions can be used in path patterns and keep_while conditions. They
allow to point to a specific node only if conditions are met, or to match
several tree nodes with a single path pattern.
A condition is an Erlang record defining a specific property. Some of them have arguments to further define the condition.
Path components (atoms and binaries) also act as conditions which check
equality with the path of the tested node. This can be useful for
conditions which compose other conditions: if_not(),
if_all() and if_any().
Example:
%% Matches `[stock, wood, <<"birch">>]' but not `[stock, wood, <<"oak">>]'
[stock, wood, #if_not{condition = <<"oak">>}]
All supported conditions are described in the Data Types
section.
comparison_op(Type) = {eq, Type} | {ne, Type} | {lt, Type} | {le, Type} | {gt, Type} | {ge, Type}
Comparison operator in some condition().
condition() = if_name_matches() | if_path_matches() | if_has_payload() | if_has_data() | if_has_sproc() | if_data_matches() | if_node_exists() | if_payload_version() | if_child_list_version() | if_child_list_length() | if_not() | if_all() | if_any()
All supported conditions.
if_all() = #if_all{conditions = [khepri_path:pattern_component()]}
Condition. Evaluates to true if all inner conditions evaluate to true.
Record fields:conditions: a list of inner conditions to evaluate.#if_all{conditions = [#if_name_matches{regex = "^a"},
#if_has_data{has_data = true}]}.
if_any() = #if_any{conditions = [khepri_path:pattern_component()]}
Condition. Evaluates to true if any of the inner conditions evaluate to true.
Record fields:conditions: a list of inner conditions to evaluate.#if_any{conditions = [#if_name_matches{regex = "^a"},
#if_has_data{has_data = true}]}.
if_child_list_length() = #if_child_list_length{count = non_neg_integer() | khepri_condition:comparison_op(non_neg_integer())}
Condition. Evaluates to true if the tested node's child list size corresponds to the expected value.
Record fields:version: integer or comparison_op() to compare to the actual
child list child.#if_child_list_length{count = 1}.
#if_child_list_length{count = {gt, 10}}.
if_child_list_version() = #if_child_list_version{version = khepri:child_list_version() | khepri_condition:comparison_op(khepri:child_list_version())}
Condition. Evaluates to true if the tested node's child list version corresponds to the expected value.
Record fields:version: integer or comparison_op() to compare to the actual
child list version.#if_child_list_version{version = 1}.
#if_child_list_version{version = {gt, 10}}.
if_data_matches() = #if_data_matches{pattern = ets:match_pattern() | any(), conditions = [any()], compiled = ets:comp_match_spec() | undefined}
Condition. Evaluates to true if the tested node has a data payload and the
data payload term matches the given pattern and all conditions evaluates
to true.
pattern: an ETS-like match pattern. The match pattern can define
variables to be used in the conditions below.conditions: a list of guard expressions. All guard expressions must
evaluate to true to consider a match. The default is an empty list of
conditions which means that only the pattern matching is
considered.%% The data must be of the form `{user, _}', so a tuple of arity 2 with the
%% first element being the `user' atom. The second element can be anything.
#if_data_matches{pattern = {user, '_'}}.
%% The data must be of the form `{age, Age}' and `Age' must be an
%% integer greater than or equal to 18.
#if_data_matches{pattern = {age, '$1'},
conditions = [{is_integer, '$1'},
{'>=', '$1', 18}]}.
See Match
Specifications in Erlang for a detailed documentation of how it works.
if_has_data() = #if_has_data{has_data = boolean()}
Condition. Evaluates to true if the tested node's data payload presence corresponds to the expected state.
Record fields:has_data: boolean set to the expected presence of a data
payload.Data absence is either no payload or a non-data type of payload.
Example:#if_has_data{has_data = false}.
if_has_payload() = #if_has_payload{has_payload = boolean()}
Condition. Evaluates to true if the tested node has any kind of payload.
Record fields:has_payload: boolean set to the expected presence of any kind of
payload.#if_has_payload{has_payload = true}.
if_has_sproc() = #if_has_sproc{has_sproc = boolean()}
Condition. Evaluates to true if the tested node's stored procedure payload presence corresponds to the expected state.
Record fields:has_sproc: boolean set to the expected presence of a stored procedure
payload.Stored procedure absence is either no payload or a non-sproc type of payload.
Example:#if_has_sproc{has_sproc = false}.
if_name_matches() = #if_name_matches{regex = any | iodata() | unicode:charlist(), compiled = khepri_condition:re_compile_ret() | undefined}
Condition. Evaluates to true if the name of the tested node matches the condition pattern.
Record fields:regex: defines the condition pattern. It can be either:
any to match any node names; the equivalent of the ".*"
regular expression but more efficient#if_name_matches{regex = "^user_"}.
#if_name_matches{regex = any}.
if_node_exists() = #if_node_exists{exists = boolean()}
Condition. Evaluates to true if the tested node existence corresponds to the expected state.
Record fields:exists: boolean set to the expected presence of the node.#if_node_exists{exists = false}.
if_not() = #if_not{condition = khepri_path:pattern_component()}
Condition. Evaluates to true if the inner condition evaluates to false.
Record fields:condition: the inner condition to evaluate.#if_not{condition = #if_name_matches{regex = "^a"}}.
if_path_matches() = #if_path_matches{regex = any | iodata() | unicode:charlist(), compiled = khepri_condition:re_compile_ret() | undefined}
Condition. Evaluates to true if the name of the tested node matches the condition pattern. If it does not match, child node names are tested recursively.
Record fields:regex: defines the condition pattern. It can be either:
any to match any node names; the equivalent of the ".*"
regular expression but more efficient#if_path_matches{regex = "^user_"}.
#if_path_matches{regex = any}.
if_payload_version() = #if_payload_version{version = khepri:payload_version() | khepri_condition:comparison_op(khepri:payload_version())}
Condition. Evaluates to true if the tested node's payload version corresponds to the expected value.
Record fields:version: integer or comparison_op() to compare to the actual
payload version.#if_payload_version{version = 1}.
#if_payload_version{version = {gt, 10}}.
keep_while() = #{khepri_path:path() => condition()} | pid()
A condition that impacts the lifetime of a tree node.
As long as the condition evaluates to true, the tree node is kept. Once the condition evaluates to false, the tree node is deleted.
There are several types of conditions:An association between a target path and a Khepri condition (condition()) that must be true on that target.
A process PID that must be alive.
This can be a process running on a member of the cluster or outside of the cluster. If the node hosting the process is a member and the connection to this node is lost, Khepri will wait for the node to come back and monitor the process again, to ensure they are actually gone. If that node is removed from the cluster while it is still down, the process is considered gone. If the node is not a member of the cluster, the process is considered gone right away.If the keep_while conditions are false at the time of the insert, the
insert fails. The only exception to that is if the keep_while condition
is path-based and that path points to the inserted node itself.
khepri:put(
StoreId, [foo], Payload,
%% The node `[foo]' will be removed as soon as `[bar]' is removed
%% because the condition associated with `[bar]' will not be true
%% anymore.
#{keep_while => #{
[bar] => #if_node_exists{exists = true}
}}
).
Example with a PID:
khepri:put(
StoreId, [foo], Payload,
%% The node `[foo]' will be removed as soon as the process inserting it
%% exits.
#{keep_while => self()}}
).
native_keep_while() = #{khepri_path:native_path() => condition()} | pid()
An association between a native path and a condition.
This is the same askeep_while() but the paths in the map keys were
converted to native paths if necessary.
re_compile_ret() = {ok, {re_pattern, any(), any(), any(), any()}} | {error, {string(), non_neg_integer()}}
Return value of re:compile/1.
re:mp(), is unfortunately not
exported by re, neither is the error tuple (at least up to
Erlang/OTP 25.1).
| ensure_native_keep_while/1 |
ensure_native_keep_while(KeepWhile) -> NativeKeepWhile
KeepWhile = keep_while()NativeKeepWhile = native_keep_while()Generated by EDoc