Module khepri_condition

Condition support.

Description

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.

Data Types

comparison_op()

comparison_op(Type) = {eq, Type} | {ne, Type} | {lt, Type} | {le, Type} | {gt, Type} | {ge, Type}

Comparison operator in some condition().

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() = #if_all{conditions = [khepri_path:pattern_component()]}

Condition. Evaluates to true if all inner conditions evaluate to true.

Record fields: Example:
#if_all{conditions = [#if_name_matches{regex = "^a"},
                      #if_has_data{has_data = true}]}.

if_any()

if_any() = #if_any{conditions = [khepri_path:pattern_component()]}

Condition. Evaluates to true if any of the inner conditions evaluate to true.

Record fields: Example:
#if_any{conditions = [#if_name_matches{regex = "^a"},
                      #if_has_data{has_data = true}]}.

if_child_list_length()

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: Example:
#if_child_list_length{count = 1}.
#if_child_list_length{count = {gt, 10}}.

if_child_list_version()

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: Example:
#if_child_list_version{version = 1}.
#if_child_list_version{version = {gt, 10}}.

if_data_matches()

if_data_matches() = #if_data_matches{pattern = ets:match_pattern(), 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.

Record fields: Examples:
%% 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() = #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:

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() = #if_has_payload{has_payload = boolean()}

Condition. Evaluates to true if the tested node has any kind of payload.

Record fields: Example:
#if_has_payload{has_payload = true}.

if_has_sproc()

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:

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() = #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: Example:
#if_name_matches{regex = "^user_"}.
#if_name_matches{regex = any}.

if_node_exists()

if_node_exists() = #if_node_exists{exists = boolean()}

Condition. Evaluates to true if the tested node existence corresponds to the expected state.

Record fields: Example:
#if_node_exists{exists = false}.

if_not()

if_not() = #if_not{condition = khepri_path:pattern_component()}

Condition. Evaluates to true if the inner condition evaluates to false.

Record fields: Example:
#if_not{condition = #if_name_matches{regex = "^a"}}.

if_path_matches()

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: Example:
#if_path_matches{regex = "^user_"}.
#if_path_matches{regex = any}.

if_payload_version()

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: Example:
#if_payload_version{version = 1}.
#if_payload_version{version = {gt, 10}}.

keep_while()

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()

native_keep_while() = #{khepri_path:native_path() => condition()}

An association between a native path and a condition.

This is the same as keep_while() but the paths in the map keys were converted to native paths if necessary.

re_compile_ret()

re_compile_ret() = {ok, {re_pattern, term(), term(), term(), term()}} | {error, {string(), non_neg_integer()}}

Return value of re:compile/1.

The opaque compiled regex type, re:mp(), is unfortunately not exported by re, neither is the error tuple (at least up to Erlang/OTP 25.1).

Function Index

ensure_native_keep_while/1

Function Details

ensure_native_keep_while/1

ensure_native_keep_while(KeepWhile) -> NativeKeepWhile


Generated by EDoc