Comprehensive Example: Employee Directory
Combines multiple Soma features in one realistic application: - Memory with properties - Data pipelines with filter/sort/aggregate - String operations - JSON serialization
Example 099 of the basic Soma programs: a small, commented program that teaches one thing. Every output below was printed by soma 3.2.4 when this page was built.
How it is built
The cell EmployeeDirectory keeps 2 memory slots: employees (Map<String, String>, persistent and consistent) and meta (Map<String, Int>, persistent and consistent). Handlers: add_employee (line 31), get_all (line 45), search_dept (line 54) and demo (line 59).
The source
099_comprehensive.cell
// ============================================================================
// 099 — Comprehensive Example: Employee Directory
// ============================================================================
// Combines multiple Soma features in one realistic application:
// - Memory with properties
// - Data pipelines with filter/sort/aggregate
// - String operations
// - JSON serialization
//
// Run: soma run 099_comprehensive.cell demo
// Expect:
// Loaded 6 employees
// === Department Summary ===
// Engineering: 3 employees, avg salary 110k
// Marketing: 2 employees, avg salary 87k
// Design: 1 employees, avg salary 95k
// === Top Earners ===
// 1. Dave (Engineering): 130k
// 2. Alice (Engineering): 120k
// 3. Eve (Design): 95k
// === Search: 'engineering' ===
// Alice, Bob, Dave
cell EmployeeDirectory {
memory {
employees: Map<String, String> [persistent, consistent]
meta: Map<String, Int> [persistent, consistent]
}
on add_employee(name: String, dept: String, salary: Int) {
let current = meta.get("next_id")
if current == () {
meta.set("next_id", 1)
}
let id = meta.get("next_id")
meta.set("next_id", id + 1)
let id_str = to_string(id)
let emp = map("id", id, "name", name, "dept", dept, "salary", salary)
employees.set(id_str, to_json(emp))
return emp
}
on get_all() {
let keys = employees.keys()
let result = list()
for key in keys {
result = list(result, from_json(employees.get(key)))
}
return result
}
on search_dept(dept: String) {
let all = get_all()
return all |> filter_by("dept", "=", dept) |> sort_by("name", "asc")
}
on demo() {
// Load data
add_employee("Alice", "Engineering", 120)
add_employee("Bob", "Engineering", 80)
add_employee("Carol", "Marketing", 90)
add_employee("Dave", "Engineering", 130)
add_employee("Eve", "Design", 95)
add_employee("Frank", "Marketing", 85)
let all = get_all()
let count = all.length
print("Loaded {count} employees")
// Department summary using pipelines
let summary = all |> agg("dept", "salary:sum", "salary:avg") |> sort_by("count", "desc")
print("=== Department Summary ===")
for row in summary {
print("{row.dept}: {row.count} employees, avg salary {row.salary_avg}k")
}
// Top earners
let top3 = all |> sort_by("salary", "desc") |> top(3)
print("=== Top Earners ===")
let rank = 1
for emp in top3 {
let rank_str = to_string(rank)
print("{rank_str}. {emp.name} ({emp.dept}): {emp.salary}k")
rank = rank + 1
}
// Search
let eng = search_dept("Engineering")
let names = eng |> pluck("name")
print("=== Search: 'engineering' ===")
// Join names manually
let name_str = ""
let idx = 0
for n in names {
if idx > 0 {
name_str += ", "
}
name_str += n
idx = idx + 1
}
print(name_str)
return "done"
}
}What the toolchain says
$ soma check 099_comprehensive.cell
warning: `name_str` grows by concatenation inside a loop — each step copies the whole value, so the loop is quadratic (8 MB took 32 s, a list + join() 30 ms): push the pieces to a List and `join(parts, "")` once
--> 099_comprehensive.cell:98:17
|
98 | name_str += ", "
| ^
✓ 1 warning(s), no errors.$ soma run 099_comprehensive.cell demo
Loaded 6 employees
=== Department Summary ===
Engineering: 3 employees, avg salary 110k
Marketing: 2 employees, avg salary 87.5k
Design: 1 employees, avg salary 95k
=== Top Earners ===
1. Dave (Engineering): 130k
2. Alice (Engineering): 120k
3. Eve (Design): 95k
=== Search: 'engineering' ===
Alice, Bob, Dave
done