Packages
reckon_db
5.2.2
5.11.0
5.10.4
5.10.3
5.10.1
5.10.0
5.9.1
5.9.0
5.8.3
5.8.2
5.8.1
5.8.0
5.7.0
5.6.1
5.6.0
5.5.5
5.5.4
5.5.3
5.5.2
5.5.1
5.5.0
5.4.0
5.2.2
5.2.1
5.2.0
5.1.0
5.0.0
4.0.0
3.1.2
3.1.1
3.0.0
2.3.7
2.3.6
2.3.5
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.2
2.2.0
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.0
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
BEAM-native Event Store built on Khepri/Ra with Raft consensus. Event sourcing, persistent subscriptions, snapshots, and automatic cluster formation via UDP multicast discovery. Ships embedded Rust NIFs for 3-15x acceleration of crypto, hashing, compression, aggregation, filter matching, and grap...
Current section
Files
Jump to
Current section
Files
src/reckon_db_dcb_paths.erl
%%% @doc DCB Khepri path helpers.
%%%
%%% DCB events live under [events, ?DCB_STREAM] and are mirrored under
%%% [by_tag, Tag, SeqKey] for every tag they carry, and under
%%% [by_event_type, EventType, SeqKey] for their event_type field.
%%% Both mirrors are the consistency index: a subtree iteration on
%%% [by_tag, Tag, *] or [by_event_type, Type, *] returns all seq keys
%%% for that tag or type, lexicographically (numerically) sorted.
%%%
%%% Seq keys are fixed-width zero-padded decimal binaries (see
%%% ?DCB_SEQ_KEY_WIDTH), so lists:max/1 on a list of seq keys returns
%%% the highest, and Key > Cutoff is a lex comparison that matches the
%%% numeric comparison.
%%%
%%% All functions here are PURE; safe to call from inside a
%%% khepri:transaction/2 body.
%%%
%%% @end
-module(reckon_db_dcb_paths).
-include("reckon_db.hrl").
-include_lib("khepri/include/khepri.hrl").
-export([
event_path/1,
by_tag_path/2,
by_tag_pattern/1,
by_event_type_path/2,
by_event_type_pattern/1,
seq_key/1,
seq_from_key/1
]).
%% @doc Path to the event payload at a given seq:
%% [events, <<"_dcb">>, <<"00000000000000000042">>]
-spec event_path(non_neg_integer()) -> [term()].
event_path(Seq) when is_integer(Seq), Seq >= 0 ->
?DCB_STREAM_PATH ++ [seq_key(Seq)].
%% @doc Path to a tag-index entry:
%% [by_tag, <<"email:foo@bar">>, <<"00000000000000000042">>]
-spec by_tag_path(binary(), non_neg_integer()) -> [term()].
by_tag_path(Tag, Seq) when is_binary(Tag), is_integer(Seq), Seq >= 0 ->
?BY_TAG_PATH ++ [Tag, seq_key(Seq)].
%% @doc Pattern matching every seq under a tag (subtree wildcard).
%% Use with khepri_tx:get_many/1 inside a transaction.
-spec by_tag_pattern(binary()) -> [term()].
by_tag_pattern(Tag) when is_binary(Tag) ->
?BY_TAG_PATH ++ [Tag, ?KHEPRI_WILDCARD_STAR].
%% @doc Path to an event-type index entry for a given seq.
%% Example key: [by_event_type, <<"user_registered_v1">>, <<"00000000000000000042">>]
-spec by_event_type_path(binary(), non_neg_integer()) -> [term()].
by_event_type_path(EventType, Seq)
when is_binary(EventType), is_integer(Seq), Seq >= 0 ->
?BY_EVENT_TYPE_PATH ++ [EventType, seq_key(Seq)].
%% @doc Pattern matching every seq under an event type (subtree wildcard).
%% Use with khepri_tx:get_many/1 inside a transaction.
-spec by_event_type_pattern(binary()) -> [term()].
by_event_type_pattern(EventType) when is_binary(EventType) ->
?BY_EVENT_TYPE_PATH ++ [EventType, ?KHEPRI_WILDCARD_STAR].
%% @doc Convert a non-negative integer to a fixed-width zero-padded
%% decimal binary (?DCB_SEQ_KEY_WIDTH digits).
%%
%% Invariants:
%% - byte_size(seq_key(N)) == ?DCB_SEQ_KEY_WIDTH for all valid N
%% - seq_key(A) =< seq_key(B) iff A =< B (lex == numeric)
%% - seq_from_key(seq_key(N)) == N (roundtrip)
-spec seq_key(non_neg_integer()) -> binary().
seq_key(Seq) when is_integer(Seq), Seq >= 0 ->
Str = integer_to_list(Seq),
Padding = ?DCB_SEQ_KEY_WIDTH - length(Str),
case Padding < 0 of
true -> erlang:error({seq_overflow, Seq, ?DCB_SEQ_KEY_WIDTH});
false -> list_to_binary(lists:duplicate(Padding, $0) ++ Str)
end.
%% @doc Decode a seq_key binary back to its integer.
-spec seq_from_key(binary()) -> non_neg_integer().
seq_from_key(Bin) when is_binary(Bin) ->
binary_to_integer(Bin).