soma.cell

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).

Generated from soma describe on this file.

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