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() | term(), 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()}
An association between a path and a condition. As long as the condition evaluates to true, the tree node is kept. Once the condition evaluates to false, the tree node is deleted.
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 on the inserted node itself.
Paths in the map can be native paths or Unix-like paths. However, having two entries that resolve to the same node (one native path entry and one Unix-like path entry for instance) is undefined behavior: one of them will overwrite the other.
Example:khepri:put(
StoreId,
[foo],
Payload,
#{keep_while => #{
%% The node `[foo]' will be removed as soon as `[bar]' is removed
%% because the condition associated with `[bar]' will not be true
%% anymore.
[bar] => #if_node_exists{exists = true}
}}
).
native_keep_while() = #{khepri_path:native_path() => condition()}
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, term(), term(), term(), term()}} | {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