-module(shelf@bag). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/shelf/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_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_bag(LNB, LNC) :: {p_bag, shelf@internal:ets_ref(), shelf@internal:dets_ref(), shelf:write_mode()} | {gleam_phantom, LNB, LNC}. -file("src/shelf/bag.gleam", 35). ?DOC(" Open a persistent bag table with full configuration.\n"). -spec open_config(shelf:config()) -> {ok, p_bag(any(), any())} | {error, shelf:shelf_error()}. open_config(Config) -> {config, Name, Path, Write_mode} = Config, _pipe = shelf_ffi:open_bag(Name, Path), gleam@result:map( _pipe, fun(Refs) -> {p_bag, erlang:element(1, Refs), erlang:element(2, Refs), Write_mode} end ). -file("src/shelf/bag.gleam", 47). ?DOC( " Open a persistent bag table with defaults (WriteBack mode).\n" "\n" " ```gleam\n" " let assert Ok(table) = bag.open(\"tags\", \"data/tags.dets\")\n" " ```\n" ). -spec open(binary(), binary()) -> {ok, p_bag(any(), any())} | {error, shelf:shelf_error()}. open(Name, Path) -> open_config(shelf:config(Name, Path)). -file("src/shelf/bag.gleam", 56). ?DOC(" Close the table, saving all data to disk.\n"). -spec close(p_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/bag.gleam", 67). ?DOC( " Use a table within a callback, ensuring it is closed afterward.\n" "\n" " ```gleam\n" " use table <- bag.with_table(\"tags\", \"data/tags.dets\")\n" " bag.insert(table, \"color\", \"red\")\n" " ```\n" ). -spec with_table( binary(), binary(), fun((p_bag(any(), any())) -> {ok, LNZ} | {error, shelf:shelf_error()}) ) -> {ok, LNZ} | {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/bag.gleam", 84). ?DOC( " Look up all values for a key.\n" "\n" " Returns `Error(NotFound)` if the key does not exist.\n" ). -spec lookup(p_bag(LOE, LOF), LOE) -> {ok, list(LOF)} | {error, shelf:shelf_error()}. lookup(Table, Key) -> shelf_ffi:lookup_bag(erlang:element(2, Table), Key). -file("src/shelf/bag.gleam", 90). ?DOC(" Check if a key exists without returning the values.\n"). -spec member(p_bag(LOL, any()), LOL) -> {ok, boolean()} | {error, shelf:shelf_error()}. member(Table, Key) -> shelf_ffi:member(erlang:element(2, Table), Key). -file("src/shelf/bag.gleam", 98). ?DOC( " Return all key-value pairs as a list.\n" "\n" " **Warning**: loads entire table into memory.\n" ). -spec to_list(p_bag(LOR, LOS)) -> {ok, list({LOR, LOS})} | {error, shelf:shelf_error()}. to_list(Table) -> shelf_ffi:to_list(erlang:element(2, Table)). -file("src/shelf/bag.gleam", 104). ?DOC(" Fold over all entries. Order is unspecified.\n"). -spec fold(p_bag(LOY, LOZ), LPC, fun((LPC, LOY, LOZ) -> LPC)) -> {ok, LPC} | {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/bag.gleam", 117). ?DOC(" Return the number of objects stored.\n"). -spec size(p_bag(any(), any())) -> {ok, integer()} | {error, shelf:shelf_error()}. size(Table) -> shelf_ffi:size(erlang:element(2, Table)). -file("src/shelf/bag.gleam", 178). ?DOC(" Snapshot the current ETS contents to DETS.\n"). -spec save(p_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/bag.gleam", 196). -spec maybe_write_through(p_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/bag.gleam", 125). ?DOC(" Insert a key-value pair. Duplicate key-value pairs are ignored.\n"). -spec insert(p_bag(LPL, LPM), LPL, LPM) -> {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/bag.gleam", 136). ?DOC(" Insert multiple key-value pairs.\n"). -spec insert_list(p_bag(LPR, LPS), list({LPR, LPS})) -> {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/bag.gleam", 148). ?DOC(" Delete all values for the given key.\n"). -spec delete_key(p_bag(LPY, any()), LPY) -> {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/bag.gleam", 158). ?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_bag(LQE, LQF), LQE, LQF) -> {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/bag.gleam", 169). ?DOC(" Delete all entries (keeps the table open).\n"). -spec delete_all(p_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/bag.gleam", 184). ?DOC(" Discard unsaved ETS changes and reload from DETS.\n"). -spec reload(p_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/bag.gleam", 190). ?DOC(" Flush the DETS write buffer to the OS.\n"). -spec sync(p_bag(any(), any())) -> {ok, nil} | {error, shelf:shelf_error()}. sync(Table) -> shelf_ffi:sync_dets(erlang:element(3, Table)).