Set tables
Set tables store one value per key. An entry is one key-value pair. If you insert a pair with an existing key, it replaces that key's value. Use set tables for caches, configuration, and key lookup.
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”Create the parent directory before opening the table. open uses AutoRepair and ReadWrite.
import gleam/dynamic/decodeimport slateimport 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 exist. It returns Error(KeyAlreadyPresent) if the key exists.
let assert Ok(Nil) = set.insert_new(table, "carol", 42)let assert Error(slate.KeyAlreadyPresent) = set.insert_new(table, "carol", 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 in an unspecified order (loads the entire table into memory)let assert Ok(entries) = set.to_list(table)
// Fold over entries in an unspecified order 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 write pending updates to disk without closing the table. DETS saves after an idle period, not at fixed intervals during continuous use. Call sync and handle its result when you need to save before continuing:
let assert Ok(Nil) = set.insert(table, "checkpoint", 42)let assert Ok(Nil) = set.sync(table)// Pending updates are written to disk; the table remains 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 entries// info.file_path - absolute path of the table filefile_path uses the normalized path from open; it does not resolve symlinks.
For the 2.0 record change, see migration guidance.
Opening with options
Section titled “Opening with options”Repair policy
Section titled “Repair policy”Select what happens when a table file needs repair. Make a backup before you repair a file with data you need to keep. Repair does not guarantee recovery of all data.
Choose one of these calls. The repair policy has no effect if the table is already open.
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)
// Repair even if the file was closed properlylet assert Ok(table) = set.open_with(path: "data/users.dets", repair: ForceRepair, key_decoder: decode.string, value_decoder: decode.int)
// Return NeedsRepair if the file requires repairlet 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”Use ReadOnly to prevent writes through the table handle. The file must exist.
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(context))