Skip to content

Set Tables

import { Aside } from '@astrojs/starlight/components';

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.

import slate/set
let assert Ok(table) = set.open("data/users.dets")
// ... use the table ...
let assert Ok(Nil) = set.close(table)

For safer lifecycle management, use with_table instead.

// Insert a single key-value pair (overwrites if key exists)
let assert Ok(Nil) = set.insert(table, "alice", 42)
// Batch insert multiple pairs
let assert Ok(Nil) = set.insert_list(table, [
#("alice", 42),
#("bob", 37),
#("charlie", 25),
])

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)
// 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 value
let assert Ok(True) = set.member(table, key: "alice")
let assert Ok(False) = set.member(table, key: "unknown")
// Delete a single key
let assert Ok(Nil) = set.delete_key(table, key: "alice")
// Delete a specific key-value pair (equivalent to delete_key for sets)
let assert Ok(Nil) = set.delete_object(table, key: "bob", value: 37)
// Clear all entries
let assert Ok(Nil) = set.delete_all(table)
// 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 result
let assert Ok(total) = set.fold(table, from: 0, with: fn(acc, _key, value) {
acc + value
})
// Get the number of stored entries
let assert Ok(count) = set.size(table)

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)
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.kind — slate.Set

Control how slate handles improperly closed tables:

import slate.{AutoRepair, ForceRepair, NoRepair}
// Default: auto-repair if needed
let assert Ok(table) = set.open_with("data/users.dets", AutoRepair)
// Force repair even if file appears clean
let assert Ok(table) = set.open_with("data/users.dets", ForceRepair)
// Return an error instead of repairing
let assert Ok(table) = set.open_with("data/users.dets", NoRepair)

Open a table as read-only to prevent accidental writes:

import slate.{AutoRepair, ReadOnly}
let assert Ok(table) = set.open_with_access("data/users.dets", AutoRepair, ReadOnly)
let assert Ok(42) = set.lookup(table, key: "alice")
// set.insert(table, "alice", 99) would return Error(AccessDenied)