slate/set
DETS set tables — one value per key.
Set tables store key-value pairs where each key maps to exactly one value. Inserting with an existing key overwrites the previous value.
Example
import gleam/dynamic/decode
import slate/set
let assert Ok(table) = set.open("users.dets",
key_decoder: decode.string, value_decoder: decode.int)
let assert Ok(Nil) = set.insert(table, "alice", 42)
let assert Ok(42) = set.lookup(table, "alice")
let assert Ok(Nil) = set.close(table)
Types
Errors returned by update_counter.
pub type UpdateCounterError {
CounterValueNotInteger
TableError(slate.DetsError)
}
Constructors
-
CounterValueNotIntegerupdate_counterrequires the stored value to be an integer. -
TableError(slate.DetsError)A shared DETS table error from the underlying operation.
Values
pub fn close(table: Set(k, v)) -> Result(Nil, slate.DetsError)
Close the table, flushing all pending writes to disk.
The table handle must not be used after closing.
pub fn delete_all(
from table: Set(k, v),
) -> Result(Nil, slate.DetsError)
Delete all objects in the table (keeps the table open).
pub fn delete_key(
from table: Set(k, v),
key key: k,
) -> Result(Nil, slate.DetsError)
Delete the entry with the given key.
This operation is idempotent — deleting a key that does not exist
succeeds with Ok(Nil).
pub fn delete_object(
from table: Set(k, v),
key key: k,
value value: v,
) -> Result(Nil, slate.DetsError)
Delete a specific key-value pair from the table.
Unlike delete_key, this only removes the entry if both the key
and value match. For set tables, this acts as a conditional delete:
the entry is removed only when the stored value equals the given value.
pub fn fold(
over table: Set(k, v),
from initial: acc,
with callback: fn(acc, k, v) -> acc,
) -> Result(acc, slate.DetsError)
Fold over all entries. Order is unspecified.
Returns Error(DecodeErrors(_)) if any entry doesn’t match the
expected types. The fold stops at the first decode error. If the callback
raises, the exception is re-raised.
pub fn fold_results(
over table: Set(k, v),
from initial: acc,
with callback: fn(
acc,
Result(#(k, v), List(decode.DecodeError)),
) -> acc,
) -> Result(acc, slate.DetsError)
Fold over all entries, passing decode results to the callback.
Unlike fold, decode failures do not abort the traversal. Each entry
is presented to the callback as Ok(#(key, value)) on success or
Error(decode_errors) on failure, letting the caller decide how to
handle bad records.
DETS-level errors (e.g., the table does not exist) still fail the
entire operation via the outer Result. If the callback raises, the
exception is re-raised.
Examples
Skip entries that fail to decode:
set.fold_results(table, [], fn(acc, entry) {
case entry {
Ok(#(key, value)) -> [#(key, value), ..acc]
Error(_) -> acc
}
})
Partition into successes and failures:
set.fold_results(table, #([], []), fn(acc, entry) {
case entry {
Ok(#(key, value)) -> #([#(key, value), ..acc.0], acc.1)
Error(errors) -> #(acc.0, [errors, ..acc.1])
}
})
pub fn info(
table: Set(k, v),
) -> Result(slate.TableInfo, slate.DetsError)
Get the file size, object count, and absolute file path of an open table.
Returns Error(TableDoesNotExist) if the table is no longer open.
pub fn insert(
into table: Set(k, v),
key key: k,
value value: v,
) -> Result(Nil, slate.DetsError)
Insert a key-value pair. Overwrites if key exists.
pub fn insert_list(
into table: Set(k, v),
entries entries: List(#(k, v)),
) -> Result(Nil, slate.DetsError)
Insert multiple key-value pairs.
pub fn insert_new(
into table: Set(k, v),
key key: k,
value value: v,
) -> Result(Nil, slate.DetsError)
Insert only if the key does not already exist.
Returns Error(KeyAlreadyPresent) if the key exists.
pub fn lookup(
from table: Set(k, v),
key key: k,
) -> Result(v, slate.DetsError)
Look up the value for a key.
Returns Error(NotFound) if the key does not exist.
Returns Error(DecodeErrors(_)) if the stored value doesn’t match the
expected type.
Note: For bag and duplicate bag tables, lookup returns Ok([])
for missing keys instead of Error(NotFound), since those table types
naturally return a list of values.
pub fn member(
of table: Set(k, v),
key key: k,
) -> Result(Bool, slate.DetsError)
Check if a key exists without returning the value.
pub fn open(
path: String,
key_decoder key_decoder: decode.Decoder(k),
value_decoder value_decoder: decode.Decoder(v),
) -> Result(Set(k, v), slate.DetsError)
Open or create a DETS set table at the given file path.
Decoders are used to validate data read from disk, ensuring type safety even when opening files created by other code or previous runs.
import gleam/dynamic/decode
let assert Ok(table) = set.open("data/cache.dets",
key_decoder: decode.string, value_decoder: decode.int)
pub fn open_with(
path path: String,
repair repair: slate.RepairPolicy,
key_decoder key_decoder: decode.Decoder(k),
value_decoder value_decoder: decode.Decoder(v),
) -> Result(Set(k, v), slate.DetsError)
Open or create a DETS set table with a specific repair policy.
The repair policy controls what happens when the table file was not closed cleanly (e.g., after a crash):
AutoRepair— silently repair the file if needed (default foropen)ForceRepair— repair even if the file appears cleanNoRepair— return an error instead of repairing
import gleam/dynamic/decode
import slate.{ForceRepair}
let assert Ok(table) = set.open_with(path: "data/cache.dets",
repair: ForceRepair,
key_decoder: decode.string, value_decoder: decode.int)
pub fn open_with_access(
path path: String,
repair repair: slate.RepairPolicy,
access access: slate.AccessMode,
key_decoder key_decoder: decode.Decoder(k),
value_decoder value_decoder: decode.Decoder(v),
) -> Result(Set(k, v), slate.DetsError)
Open a DETS set table with repair and access mode options.
Use ReadOnly to open a table for reading only. Write operations
on a read-only table will return Error(AccessDenied(context)).
import gleam/dynamic/decode
import slate.{AutoRepair, ReadOnly}
let assert Ok(table) = set.open_with_access(path: "data/cache.dets",
repair: AutoRepair, access: ReadOnly,
key_decoder: decode.string, value_decoder: decode.string)
let assert Ok(value) = set.lookup(table, key: "key")
// set.insert(table, "key", "val") would return Error(AccessDenied(context))
pub fn size(of table: Set(k, v)) -> Result(Int, slate.DetsError)
Return the number of objects stored.
pub fn sync(table: Set(k, v)) -> Result(Nil, slate.DetsError)
Flush pending writes to disk without closing the table.
DETS auto-syncs periodically, so this is only needed when you require a durability guarantee at a specific point (e.g., after a critical write).
pub fn to_list(
from table: Set(k, v),
) -> Result(List(#(k, v)), slate.DetsError)
Return all key-value pairs as a list.
Warning: loads entire table into memory.
Returns Error(DecodeErrors(_)) if any entry doesn’t match the
expected types.
pub fn update_counter(
in table: Set(k, Int),
key key: k,
increment amount: Int,
) -> Result(Int, UpdateCounterError)
Atomically increment a counter value by the given amount.
The value associated with the key must be an integer. Returns the new value after incrementing. The increment can be negative.
Returns Error(TableError(slate.NotFound)) if the key doesn’t exist,
Error(CounterValueNotInteger) if the stored value is not an integer,
or Error(TableError(error)) for other DETS table failures.
import gleam/dynamic/decode
let assert Ok(table) = set.open("counters.dets",
key_decoder: decode.string, value_decoder: decode.int)
let assert Ok(Nil) = set.insert(table, "hits", 0)
let assert Ok(1) = set.update_counter(table, "hits", 1)
let assert Ok(3) = set.update_counter(table, "hits", 2)
pub fn with_table(
path path: String,
repair repair: slate.RepairPolicy,
access access: slate.AccessMode,
key_decoder key_decoder: decode.Decoder(k),
value_decoder value_decoder: decode.Decoder(v),
callback callback: fn(Set(k, v)) -> Result(a, slate.DetsError),
) -> Result(a, slate.DetsError)
Use a table within a callback with repair and access mode options.
Pass AutoRepair and ReadWrite to keep the behavior of slate 1.x.
Uses the same options as open_with_access. ReadOnly requires an existing
file, and writes return Error(AccessDenied(context)). NoRepair returns
Error(NeedsRepair(context)) if the file was not closed cleanly.
If opening fails, returns the open error without calling the callback. Otherwise, closes the table before returning the callback result. If close fails after a successful callback, returns the close error. If both fail, returns the callback error. If the callback raises, attempts close before re-raising the original exception.
Keep the table handle within the callback; do not use it after cleanup. This cannot guarantee cleanup if the process is killed.
import gleam/dynamic/decode
import slate.{NoRepair, ReadOnly}
import slate/set
use table <- set.with_table(path: "data/cache.dets",
repair: NoRepair, access: ReadOnly,
key_decoder: decode.string, value_decoder: decode.string)
set.lookup(table, key: "key")