Set Tables
Set tables store key-value pairs where each key maps to exactly one value. Inserting with an existing key overwrites the previous value. This is the most common table type, ideal for caches, configuration, and general-purpose persistence.
Set tables are provided by the slate/set module and correspond to the set table type in Erlang's DETS.
Opening and closing
Section titled “Opening and closing”import gleam/dynamic/decodeimport slate/set
let assert Ok(table) = set.open("data/users.dets", key_decoder: decode.string, value_decoder: decode.int)
// ... use the table ...
let assert Ok(Nil) = set.close(table)For short-lived operations, use with_table to close the table when the callback returns.
Inserting data
Section titled “Inserting data”// Insert a single key-value pair (overwrites if key exists)let assert Ok(Nil) = set.insert(table, "alice", 42)
// Batch insert multiple pairslet assert Ok(Nil) = set.insert_list(table, [ #("alice", 42), #("bob", 37), #("charlie", 25),])Insert without overwriting
Section titled “Insert without overwriting”Use insert_new to insert only if the key does not already exist. Returns Error(KeyAlreadyPresent) if the key is taken.
let assert Ok(Nil) = set.insert_new(table, "alice", 42)let assert Error(slate.KeyAlreadyPresent) = set.insert_new(table, "alice", 99)Looking up data
Section titled “Looking up data”// Get the value for a key (returns Error(NotFound) if missing)let assert Ok(42) = set.lookup(table, key: "alice")let assert Error(slate.NotFound) = set.lookup(table, key: "unknown")
// Check if a key exists without retrieving the valuelet assert Ok(True) = set.member(table, key: "alice")let assert Ok(False) = set.member(table, key: "unknown")Deleting data
Section titled “Deleting data”// Delete a single keylet assert Ok(Nil) = set.delete_key(table, key: "alice")
// Delete only if both the key and value matchlet assert Ok(Nil) = set.delete_object(table, key: "bob", value: 37)
// Clear all entrieslet assert Ok(Nil) = set.delete_all(table)Iterating over entries
Section titled “Iterating over entries”// Get all entries as a list (loads entire table into memory)let assert Ok(entries) = set.to_list(table)
// Fold over entries to compute a resultlet assert Ok(total) = set.fold(table, from: 0, with: fn(acc, _key, value) { acc + value})
// Get the number of stored entrieslet assert Ok(count) = set.size(table)Atomic counters
Section titled “Atomic counters”Set tables support atomic counter increments for integer values:
let assert Ok(Nil) = set.insert(table, "page_views", 0)let assert Ok(1) = set.update_counter(table, "page_views", 1)let assert Ok(3) = set.update_counter(table, "page_views", 2)let assert Ok(1) = set.update_counter(table, "page_views", -2)Flushing writes
Section titled “Flushing writes”Use sync to flush pending writes to disk without closing the table. This is useful for long-lived tables where you want to ensure durability at a specific point:
let assert Ok(Nil) = set.insert(table, "checkpoint", 42)let assert Ok(Nil) = set.sync(table)// Data is guaranteed to be on disk, table stays openTable info
Section titled “Table info”let assert Ok(info) = set.info(table)// info.file_size — size of the file on disk in bytes// info.object_count — number of entriesOpening with options
Section titled “Opening with options”Repair policy
Section titled “Repair policy”Control how slate handles improperly closed tables:
import slate.{AutoRepair, ForceRepair, NoRepair}import gleam/dynamic/decode
// Default: auto-repair if neededlet assert Ok(table) = set.open_with(path: "data/users.dets", repair: AutoRepair, key_decoder: decode.string, value_decoder: decode.int)
// Force repair even if file appears cleanlet assert Ok(table) = set.open_with(path: "data/users.dets", repair: ForceRepair, key_decoder: decode.string, value_decoder: decode.int)
// Return an error instead of repairinglet assert Ok(table) = set.open_with(path: "data/users.dets", repair: NoRepair, key_decoder: decode.string, value_decoder: decode.int)Access mode
Section titled “Access mode”Open a table as read-only to prevent accidental writes:
import slate.{AutoRepair, ReadOnly}import gleam/dynamic/decode
let assert Ok(table) = set.open_with_access(path: "data/users.dets", repair: AutoRepair, access: ReadOnly, key_decoder: decode.string, value_decoder: decode.int)let assert Ok(42) = set.lookup(table, key: "alice")// set.insert(table, "alice", 99) would return Error(AccessDenied)