Packages

Persistent ETS tables backed by DETS — fast in-memory access with automatic disk persistence for the BEAM

Current section

Files

Jump to
shelf src shelf@duplicate_bag.erl
Raw

src/shelf@duplicate_bag.erl

-module(shelf@duplicate_bag).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/shelf/duplicate_bag.gleam").
-export([open_config/1, open/2, close/1, with_table/3, lookup/2, member/2, to_list/1, fold/3, size/1, save/1, insert/3, insert_list/2, delete_key/2, delete_object/3, delete_all/1, reload/1, sync/1]).
-export_type([p_duplicate_bag/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque p_duplicate_bag(LXP, LXQ) :: {p_duplicate_bag,
shelf@internal:ets_ref(),
shelf@internal:dets_ref(),
shelf:write_mode()} |
{gleam_phantom, LXP, LXQ}.
-file("src/shelf/duplicate_bag.gleam", 34).
?DOC(" Open a persistent duplicate bag table with full configuration.\n").
-spec open_config(shelf:config()) -> {ok, p_duplicate_bag(any(), any())} |
{error, shelf:shelf_error()}.
open_config(Config) ->
{config, Name, Path, Write_mode} = Config,
_pipe = shelf_ffi:open_duplicate_bag(Name, Path),
gleam@result:map(
_pipe,
fun(Refs) ->
{p_duplicate_bag,
erlang:element(1, Refs),
erlang:element(2, Refs),
Write_mode}
end
).
-file("src/shelf/duplicate_bag.gleam", 48).
?DOC(
" Open a persistent duplicate bag table with defaults (WriteBack mode).\n"
"\n"
" ```gleam\n"
" let assert Ok(table) = duplicate_bag.open(\"events\", \"data/events.dets\")\n"
" ```\n"
).
-spec open(binary(), binary()) -> {ok, p_duplicate_bag(any(), any())} |
{error, shelf:shelf_error()}.
open(Name, Path) ->
open_config(shelf:config(Name, Path)).
-file("src/shelf/duplicate_bag.gleam", 57).
?DOC(" Close the table, saving all data to disk.\n").
-spec close(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
close(Table) ->
shelf_ffi:close(erlang:element(2, Table), erlang:element(3, Table)).
-file("src/shelf/duplicate_bag.gleam", 68).
?DOC(
" Use a table within a callback, ensuring it is closed afterward.\n"
"\n"
" ```gleam\n"
" use table <- duplicate_bag.with_table(\"events\", \"data/events.dets\")\n"
" duplicate_bag.insert(table, \"click\", \"btn_1\")\n"
" ```\n"
).
-spec with_table(
binary(),
binary(),
fun((p_duplicate_bag(any(), any())) -> {ok, LYN} |
{error, shelf:shelf_error()})
) -> {ok, LYN} | {error, shelf:shelf_error()}.
with_table(Name, Path, Fun) ->
gleam@result:'try'(
open(Name, Path),
fun(Table) ->
Result = Fun(Table),
_ = close(Table),
Result
end
).
-file("src/shelf/duplicate_bag.gleam", 85).
?DOC(
" Look up all values for a key.\n"
"\n"
" Returns `Error(NotFound)` if the key does not exist.\n"
).
-spec lookup(p_duplicate_bag(LYS, LYT), LYS) -> {ok, list(LYT)} |
{error, shelf:shelf_error()}.
lookup(Table, Key) ->
shelf_ffi:lookup_bag(erlang:element(2, Table), Key).
-file("src/shelf/duplicate_bag.gleam", 94).
?DOC(" Check if a key exists without returning the values.\n").
-spec member(p_duplicate_bag(LYZ, any()), LYZ) -> {ok, boolean()} |
{error, shelf:shelf_error()}.
member(Table, Key) ->
shelf_ffi:member(erlang:element(2, Table), Key).
-file("src/shelf/duplicate_bag.gleam", 105).
?DOC(
" Return all key-value pairs as a list.\n"
"\n"
" **Warning**: loads entire table into memory.\n"
).
-spec to_list(p_duplicate_bag(LZF, LZG)) -> {ok, list({LZF, LZG})} |
{error, shelf:shelf_error()}.
to_list(Table) ->
shelf_ffi:to_list(erlang:element(2, Table)).
-file("src/shelf/duplicate_bag.gleam", 113).
?DOC(" Fold over all entries. Order is unspecified.\n").
-spec fold(p_duplicate_bag(LZM, LZN), LZQ, fun((LZQ, LZM, LZN) -> LZQ)) -> {ok,
LZQ} |
{error, shelf:shelf_error()}.
fold(Table, Initial, Fun) ->
Wrapper = fun(Entry, Acc) ->
Fun(Acc, erlang:element(1, Entry), erlang:element(2, Entry))
end,
shelf_ffi:fold(erlang:element(2, Table), Wrapper, Initial).
-file("src/shelf/duplicate_bag.gleam", 126).
?DOC(" Return the number of objects stored.\n").
-spec size(p_duplicate_bag(any(), any())) -> {ok, integer()} |
{error, shelf:shelf_error()}.
size(Table) ->
shelf_ffi:size(erlang:element(2, Table)).
-file("src/shelf/duplicate_bag.gleam", 190).
?DOC(" Snapshot the current ETS contents to DETS.\n").
-spec save(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
save(Table) ->
shelf_ffi:save(erlang:element(2, Table), erlang:element(3, Table)).
-file("src/shelf/duplicate_bag.gleam", 208).
-spec maybe_write_through(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
maybe_write_through(Table) ->
case erlang:element(4, Table) of
write_through ->
shelf_ffi:save(erlang:element(2, Table), erlang:element(3, Table));
write_back ->
{ok, nil}
end.
-file("src/shelf/duplicate_bag.gleam", 134).
?DOC(" Insert a key-value pair. Duplicates are preserved.\n").
-spec insert(p_duplicate_bag(LZZ, MAA), LZZ, MAA) -> {ok, nil} |
{error, shelf:shelf_error()}.
insert(Table, Key, Value) ->
gleam@result:'try'(
shelf_ffi:insert(
erlang:element(2, Table),
erlang:element(3, Table),
{Key, Value}
),
fun(_) -> maybe_write_through(Table) end
).
-file("src/shelf/duplicate_bag.gleam", 145).
?DOC(" Insert multiple key-value pairs.\n").
-spec insert_list(p_duplicate_bag(MAF, MAG), list({MAF, MAG})) -> {ok, nil} |
{error, shelf:shelf_error()}.
insert_list(Table, Entries) ->
gleam@result:'try'(
shelf_ffi:insert_list(
erlang:element(2, Table),
erlang:element(3, Table),
Entries
),
fun(_) -> maybe_write_through(Table) end
).
-file("src/shelf/duplicate_bag.gleam", 157).
?DOC(" Delete all values for the given key.\n").
-spec delete_key(p_duplicate_bag(MAM, any()), MAM) -> {ok, nil} |
{error, shelf:shelf_error()}.
delete_key(Table, Key) ->
gleam@result:'try'(
shelf_ffi:delete_key(erlang:element(2, Table), Key),
fun(_) -> maybe_write_through(Table) end
).
-file("src/shelf/duplicate_bag.gleam", 170).
?DOC(
" Delete a specific key-value pair.\n"
"\n"
" Only the exact matching pair is removed. Other values for the same\n"
" key are preserved.\n"
).
-spec delete_object(p_duplicate_bag(MAS, MAT), MAS, MAT) -> {ok, nil} |
{error, shelf:shelf_error()}.
delete_object(Table, Key, Value) ->
gleam@result:'try'(
shelf_ffi:delete_object(erlang:element(2, Table), Key, Value),
fun(_) -> maybe_write_through(Table) end
).
-file("src/shelf/duplicate_bag.gleam", 181).
?DOC(" Delete all entries (keeps the table open).\n").
-spec delete_all(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
delete_all(Table) ->
gleam@result:'try'(
shelf_ffi:delete_all(erlang:element(2, Table)),
fun(_) -> maybe_write_through(Table) end
).
-file("src/shelf/duplicate_bag.gleam", 196).
?DOC(" Discard unsaved ETS changes and reload from DETS.\n").
-spec reload(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
reload(Table) ->
shelf_ffi:load(erlang:element(2, Table), erlang:element(3, Table)).
-file("src/shelf/duplicate_bag.gleam", 202).
?DOC(" Flush the DETS write buffer to the OS.\n").
-spec sync(p_duplicate_bag(any(), any())) -> {ok, nil} |
{error, shelf:shelf_error()}.
sync(Table) ->
shelf_ffi:sync_dets(erlang:element(3, Table)).