Packages
reckon_db
5.2.1
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_index_config.erl
%% @doc Per-store secondary-index declaration registry.
%%
%% A store declares which secondary indexes it maintains in
%% `#store_config.indexes' (none by default). This module installs that
%% declared list into persistent_term at store startup so the append hot
%% path can read it without process-state coupling — exactly the pattern
%% {@link reckon_db_integrity_key} uses for the HMAC key.
%%
%% == Storage ==
%%
%% The declared index list is placed in persistent_term under
%% `{reckon_db, indexes, StoreId}'. Callers read it via `declared/1' on
%% every append; the lookup is sub-microsecond.
%%
%% == Index kinds ==
%%
%% <ul>
%% <li>`tags' — index every tag in `#event.tags'.</li>
%% <li>`event_type' — index `#event.event_type'.</li>
%% <li>`{meta, Key}' — index `maps:get(Key, metadata)' when present.</li>
%% </ul>
%%
%% See plans/DESIGN_SECONDARY_INDEX.md.
-module(reckon_db_index_config).
-include("reckon_db.hrl").
-export([
load/1,
declared/1,
is_indexed/2,
clear/1
]).
%%====================================================================
%% Public API
%%====================================================================
%% @doc Install a store's declared index list into persistent_term at
%% startup. Idempotent: re-loading overwrites the previous declaration.
-spec load(store_config()) -> ok.
load(#store_config{store_id = StoreId, indexes = Indexes})
when is_list(Indexes) ->
persistent_term:put({reckon_db, indexes, StoreId}, normalize(Indexes)),
ok.
%% @doc The declared index list for a store ([] if none / not loaded).
-spec declared(StoreId :: atom()) -> [index_decl()].
declared(StoreId) ->
persistent_term:get({reckon_db, indexes, StoreId}, []).
%% @doc Whether a given index kind is declared for a store. `Kind' is an
%% `index_decl()' (`tags', `event_type', or `{meta, Key}'). Drives the
%% read-path "use index vs scan-and-warn" decision.
-spec is_indexed(StoreId :: atom(), Kind :: index_decl()) -> boolean().
is_indexed(StoreId, Kind) ->
lists:member(Kind, declared(StoreId)).
%% @doc Remove a store's index declaration from persistent_term (shutdown
%% / test isolation).
-spec clear(StoreId :: atom()) -> ok.
clear(StoreId) ->
persistent_term:erase({reckon_db, indexes, StoreId}),
ok.
%%====================================================================
%% Internal
%%====================================================================
%% @private Drop anything that isn't a recognised index declaration and
%% de-duplicate, so the hot path can trust the list shape.
-spec normalize([term()]) -> [index_decl()].
normalize(Indexes) ->
lists:usort([D || D <- Indexes, is_valid_decl(D)]).
-spec is_valid_decl(term()) -> boolean().
is_valid_decl(tags) -> true;
is_valid_decl(event_type) -> true;
is_valid_decl({meta, Key}) when is_binary(Key) -> true;
is_valid_decl(_) -> false.