writeonce/docs/examples/hello/main.wo

71 lines
2.8 KiB
Text

-- main.wo — the smallest complete writeonce program.
--
-- Run it from the repo root:
--
-- cargo run --bin wo -- run docs/examples/hello (or: just hello)
-- just hello-demo -- scripted CRUD round-trip
--
-- and exercise it:
--
-- curl -X POST localhost:8080/api/notes \
-- -H "Content-Type: application/json" \
-- -d '{"title":"hello","body":"# First note"}'
-- curl localhost:8080/api/notes
-- curl localhost:8080/api/notes/1
-- curl -X PATCH localhost:8080/api/notes/1 -d '{"pinned":true}'
-- curl -X DELETE localhost:8080/api/notes/1
--
-- One type declaration is the whole app: the fields define the schema, the
-- `service` block generates the REST endpoints, and the runtime serves them
-- from a single binary — no external database, no framework.
type Note {
id: Id
title: Text
body: Markdown
pinned: Bool = false -- literal defaults populate on create
created_at: Timestamp = now() -- so does now(); computed defaults
-- like words(...) are Stage 4+
service rest "/api/notes"
expose list, get, create, update, delete, subscribe
-- list/get/create/update/delete work today (Stage 2).
-- subscribe maps to GET /api/notes/live — a documented 501 stub
-- until Stage 3 lands LIVE subscriptions over WebSocket.
}
-- A second actor that modifies Note. The closest thing to "another class" in
-- writeonce is another type with a trigger: there is no class/method model —
-- behavior attaches to data. Creating a Revision rewrites its target note's
-- title, inside the same transaction as the insert. Triggers execute from
-- Stage 4; today the block parses and is discarded.
type Revision {
id: Id
note: ref Note -- foreign key into Note
new_title: Text
at: Timestamp = now()
on create
do update Note{ id == self.note }.title = self.new_title
}
-- Procedural entry point. Stage 2 parses and discards `main` blocks
-- (see crates/rt/src/parser.rs — skip_top_level_chunk); from Phase 6 on
-- this runs once at startup, before the HTTP server binds.
main {
insert Note { title: "hello", body: "# First note" };
-- A snapshot binding would never see later changes (let n = select ...).
-- LIVE is the language's "pointer that observes stores": the handle
-- receives a delta at every commit that touches a matching row. Stage 3.
-- (Spec: docs/runtime/database/02-wo-language.md § Schema-Layer DML)
let live = LIVE select Note{ title };
-- The other actor fires: this insert runs Revision's on-create trigger,
-- the trigger updates the note, and the commit pushes one delta.
insert Revision { note: 1, new_title: "Hello World" };
for delta in live {
print(delta.kind, delta.row.title); -- update "Hello World"
}
}