Packages
reckon_db
2.3.3
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_stream_id.erl
%% @doc Stream-id format validator.
%%
%% Single source of truth for what "a valid stream id" means in
%% reckon-db. Used by {@link reckon_db_streams:append/4} to reject
%% malformed ids at write time so the store never accumulates
%% polluted paths.
%%
%% == Accepted formats ==
%%
%% <ul>
%% <li>**User stream:** `<prefix>-<hex>', where:
%% <ul>
%% <li>`<prefix>' is `[A-Za-z]+' — one or more ASCII letters,
%% no digits, no hyphens, no `$'.</li>
%% <li>`-' is a single mandatory separator.</li>
%% <li>`<hex>' is `[A-Fa-f0-9]+' — one or more hex digits,
%% typically a UUIDv7 with dashes stripped.</li>
%% </ul>
%% Examples: `account-018f6a7b8c9d4abc8901234567890abc',
%% `order-deadbeef'.</li>
%% <li>**System stream:** `$<namespace>:<name>', where:
%% <ul>
%% <li>`$' is a mandatory prefix.</li>
%% <li>`<namespace>' is `[a-z][a-z0-9-]*' — lowercase
%% identifier, may contain hyphens (e.g. `link-sub').</li>
%% <li>`:' is a single mandatory separator.</li>
%% <li>`<name>' is `[A-Za-z0-9][A-Za-z0-9_.-]*' — intentionally
%% human-readable; the whole point of system streams is
%% operational legibility.</li>
%% </ul>
%% Examples: `$link:high-value-orders', `$link-sub:revenue'.</li>
%% </ul>
%%
%% See `guides/system_streams.md' for the rationale.
%%
%% == Rejected (returns `{error, Reason}') ==
%%
%% <ul>
%% <li>Empty binary — `empty'</li>
%% <li>Not a binary — `not_binary'</li>
%% <li>Anything starting with `$' that isn't a well-formed system
%% id — `malformed_system_id'</li>
%% <li>Anything not starting with `$' that isn't a well-formed
%% user id — `malformed_user_id'</li>
%% </ul>
%%
%% Rejected examples: `test$basic-stream' (mid-string `$' in a
%% user id), `partition$XYZ' (ditto), `$weird' (no `:'),
%% `MYAPP-abc' (prefix is fine but `abc' starts compliant — and
%% `xyz' isn't hex; `g' would be rejected), `account-' (empty
%% hex), `-deadbeef' (empty prefix).
-module(reckon_db_stream_id).
-export([
validate/1,
is_valid/1,
is_system/1
]).
-export_type([validation_error/0]).
-type validation_error() ::
empty
| not_binary
| malformed_user_id
| malformed_system_id.
%% Compile the regexes once at module load via persistent_term so
%% the hot path doesn't pay for re:compile per call.
-define(USER_RE,
{?MODULE, user_re}).
-define(SYSTEM_RE,
{?MODULE, system_re}).
%% @doc Validate StreamId. Returns `ok' if it matches either
%% accepted format, or `{error, Reason}'.
-spec validate(term()) -> ok | {error, validation_error()}.
validate(<<>>) ->
{error, empty};
validate(<<"$", _/binary>> = Id) ->
case re:run(Id, system_re(), [{capture, none}]) of
match -> ok;
nomatch -> {error, malformed_system_id}
end;
validate(Id) when is_binary(Id) ->
case re:run(Id, user_re(), [{capture, none}]) of
match -> ok;
nomatch -> {error, malformed_user_id}
end;
validate(_) ->
{error, not_binary}.
%% @doc Boolean wrapper for use in guards / list-comprehensions.
-spec is_valid(term()) -> boolean().
is_valid(StreamId) ->
validate(StreamId) =:= ok.
%% @doc True if StreamId is in the system namespace (starts with
%% `$' and is well-formed). Note: `$all' is NOT a valid stream id
%% — it's a subscription-selector sentinel only.
-spec is_system(binary()) -> boolean().
is_system(<<"$", _/binary>> = Id) ->
validate(Id) =:= ok;
is_system(_) ->
false.
%%====================================================================
%% Internal — regex caching
%%====================================================================
user_re() ->
case persistent_term:get(?USER_RE, undefined) of
undefined ->
{ok, MP} = re:compile(<<"^[A-Za-z]+-[A-Fa-f0-9]+$">>),
persistent_term:put(?USER_RE, MP),
MP;
MP ->
MP
end.
system_re() ->
case persistent_term:get(?SYSTEM_RE, undefined) of
undefined ->
{ok, MP} = re:compile(
<<"^\\$[a-z][a-z0-9-]*:[A-Za-z0-9][A-Za-z0-9_.-]*$">>),
persistent_term:put(?SYSTEM_RE, MP),
MP;
MP ->
MP
end.