小橘 d84a860d15 feat: initial ograph repo — engine (85 tests) + cli (31 tests)
Extracted from uncaged monorepo (oc-xiaoju/uncaged).
Resolves oc-xiaoju/uncaged#224.

- @uncaged/ograph: CF Worker engine (events, projections, reactions)
- @uncaged/ograph-cli: CLI for managing OGraph instances
- Removed @uncaged/oid dependency (unused)
- 116 tests, all passing
- CI: GitHub Actions

小橘 🍊(NEKO Team)
2026-04-12 23:43:56 +00:00

83 lines
2.5 KiB
SQL

-- OGraph v2.2 Schema
-- RFC-016 v2.2: Event, Projection, Reaction (8 tables)
-- Drop all v2.1 tables
DROP TABLE IF EXISTS projection_deps;
DROP TABLE IF EXISTS projections;
DROP TABLE IF EXISTS projection_defs;
DROP TABLE IF EXISTS event_refs;
DROP TABLE IF EXISTS events;
DROP TABLE IF EXISTS event_defs;
DROP TABLE IF EXISTS objects;
DROP TABLE IF EXISTS object_defs;
DROP TABLE IF EXISTS reactions;
-- ============================================
-- Definition Layer (3 tables)
-- ============================================
CREATE TABLE object_defs (
name TEXT PRIMARY KEY
);
CREATE TABLE event_defs (
name TEXT PRIMARY KEY,
schema TEXT NOT NULL -- JSON: { properties: { ... } }
);
CREATE TABLE projection_defs (
name TEXT PRIMARY KEY,
driven_by TEXT NOT NULL, -- JSON: ["assigned", "reassigned"]
params TEXT NOT NULL, -- JSON: input schema, e.g. {"task": {"type": "ref"}}
filter TEXT NOT NULL, -- JSONata: $event 精筛
expression TEXT NOT NULL, -- JSONata: ($state, $events) → new_state
initial_value TEXT -- JSON: 初始值
);
-- ============================================
-- Instance Layer (5 tables)
-- ============================================
CREATE TABLE objects (
id TEXT PRIMARY KEY,
type TEXT NOT NULL REFERENCES object_defs(name),
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
);
CREATE TABLE events (
id TEXT PRIMARY KEY,
type TEXT NOT NULL REFERENCES event_defs(name),
payload TEXT NOT NULL, -- JSON: flat key-value
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
);
CREATE TABLE event_refs (
event_id TEXT NOT NULL REFERENCES events(id),
property TEXT NOT NULL,
ref_id TEXT NOT NULL REFERENCES objects(id),
PRIMARY KEY (event_id, property)
);
CREATE INDEX idx_event_refs_obj ON event_refs(ref_id);
CREATE TABLE projections (
def TEXT NOT NULL REFERENCES projection_defs(name),
params_hash TEXT NOT NULL,
params TEXT NOT NULL, -- JSON: 实际参数值
value TEXT, -- JSON: 当前值
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
updated_at INTEGER,
PRIMARY KEY (def, params_hash)
);
CREATE TABLE reactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
projection_def TEXT NOT NULL REFERENCES projection_defs(name),
params_hash TEXT NOT NULL,
params TEXT NOT NULL, -- JSON: 监听哪个 projection 实例的参数
webhook_url TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
);
CREATE INDEX idx_reactions_projection ON reactions(projection_def, params_hash);