soma.cell

Voting / poll API: fixed options, one counter per option, results sorted

POST /vote/<option> increments; GET /results returns sorted tallies.

A Soma program from the web part of the verified corpus: 63 lines, cells Poll, PollTest. It passes soma check with soma 3.2.4.

How it is built

The cell Poll declares 4 signals in its face: request(method: String, path: String, body: String) -> Map, vote(option: String) -> Map, results() -> List and leader() -> String; keeps 1 memory slot: tally (Map<String, Int>, persistent and consistent). Handlers: vote (line 19), results (line 28), leader (line 38) and request (line 43). Private helpers: _options.

The file also holds 1 test cell (PollTest) with 6 assertions, run by soma test.

Generated from soma describe on this file.

The source

soma.toml

[package]
name = "web-corpus"
version = "0.1.0"
entry = "todo_state.cell"

[verify]
cells = ["TodoService"]
deadlock_free = true
eventually = ["Done", "Cancelled"]

poll_api.cell

// Voting / poll API: fixed options, one counter per option, results sorted.
// POST /vote/<option> increments; GET /results returns sorted tallies.

cell Poll {
    face {
        signal request(method: String, path: String, body: String) -> Map
        signal vote(option: String) -> Map
        signal results() -> List
        signal leader() -> String
        promise all_persistent
    }

    memory {
        tally: Map<String, Int> [persistent, consistent]
    }

    on _options() { return list("cats", "dogs", "birds") }

    on vote(option: String) {
        let valid = _options() |> any(o => o == option)
        if valid == false { return response(400, map("error", "unknown option")) }
        let cur = tally.get(option)
        if cur == () { cur = 0 }
        tally.set(option, cur + 1)
        return map("option", option, "votes", cur + 1)
    }

    on results() {
        let rows = list()
        for o in _options() {
            let v = tally.get(o)
            if v == () { v = 0 }
            rows = push(rows, map("option", o, "votes", v))
        }
        return rows |> sort_by("votes", "desc")
    }

    on leader() {
        let r = results()
        return r[0].option
    }

    on request(method: String, path: String, body: String) {
        let req = map("method", method, "path", path)
        match req {
            {method: "POST", path: "/vote/" + opt} -> vote(opt)
            {method: "GET",  path: "/results"}     -> results()
            _                                      -> response(404, map("error", "no route"))
        }
    }
}

cell test PollTest {
    rules {
        assert vote("cats").votes == 1
        assert vote("dogs").votes == 1
        assert vote("dogs").votes == 2
        assert leader() == "dogs"
        assert len(results()) == 3
        assert vote("fish")._status == 400
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check poll_api.cell
✓ All checks passed.
$ soma test poll_api.cell
test PollTest ...
  ✓ assert vote("cats").votes == 1
  ✓ assert vote("dogs").votes == 1
  ✓ assert vote("dogs").votes == 2
  ✓ assert leader() == "dogs"
  ✓ assert len(results()) == 3
  ✓ assert vote("fish")._status == 400

6 tests: 6 passed, 0 failed
$ soma verify poll_api.cell
Verifying poll_api.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
note: the soma.toml beside this file declares [verify] properties; none applies here (no state machine)
VERIFY OK (vacuous — no state machine)

Builtins used

any, len, list, map, push, response, sort_by

Source file: /corpus/web/poll_api.cell · examples/corpus/web/poll_api.cell