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