ff_backend_sqlite/queries/dispatch.rs
1//! SQLite dialect-forked queries for outbox writes + broadcast
2//! wakeup drains (RFC-023 §4.2).
3//!
4//! The outbox rows are the **durable** record of each dispatch event;
5//! the broadcast channel is the wakeup. Subscribers catch up via
6//! `event_id > cursor` reads on these tables.
7
8// `INSERT_COMPLETION_EVENT_SQL` lives in `queries::attempt` (it pre-dates
9// Phase 2b.1 — the attempt-ops family wrote completion events from
10// Phase 2a.2 onward). We reuse that shape here rather than duplicating.
11// See `crates/ff-backend-sqlite/src/queries/attempt.rs`.
12
13// ── lease_event outbox ────────────────────────────────────────────────
14
15/// Insert one lease-lifecycle outbox row, back-filling `namespace` +
16/// `instance_tag` from the co-transactional `ff_exec_core.raw_fields`
17/// row so tag-filtered subscribers do not silently drop the event
18/// (Phase 3.2 fix — pre-fix, both columns landed NULL and a filter
19/// with `instance_tag=...` matched zero rows). Mirrors the
20/// `INSERT_SIGNAL_EVENT_SQL` SELECT+UNION-ALL shape from
21/// `queries/signal.rs`: the first branch reads exec_core (usual
22/// path); the second branch fires only when the exec row does not
23/// exist so the insert is still guaranteed by the 4 shipped binds
24/// and never lost.
25///
26/// Binds:
27/// 1. execution_id (TEXT — UUID string) — emitted on the outbox row
28/// 2. event_type (TEXT)
29/// 3. occurred_at_ms (i64)
30/// 4. partition_key (i64) — used both on the outbox row and the
31/// co-transactional exec_core lookup
32/// 5. execution_id (BLOB) — `ff_exec_core.execution_id` is BLOB, so
33/// the lookup binds the Uuid-as-bytes form
34pub(crate) const INSERT_LEASE_EVENT_SQL: &str = r#"
35 INSERT INTO ff_lease_event
36 (execution_id, lease_id, event_type, occurred_at_ms, partition_key,
37 namespace, instance_tag)
38 SELECT ?1, NULL, ?2, ?3, ?4,
39 json_extract(raw_fields, '$.namespace'),
40 json_extract(raw_fields, '$.tags."cairn.instance_id"')
41 FROM ff_exec_core
42 WHERE partition_key = ?4 AND execution_id = ?5
43 UNION ALL
44 SELECT ?1, NULL, ?2, ?3, ?4, NULL, NULL
45 WHERE NOT EXISTS (
46 SELECT 1 FROM ff_exec_core
47 WHERE partition_key = ?4 AND execution_id = ?5
48 )
49"#;
50
51// ── signal_event outbox ───────────────────────────────────────────────
52
53/// Insert one signal-delivery outbox row. Consumer-side (Phase 2b.2
54/// `deliver_signal` + subscribe_signal_delivery) drains via
55/// `event_id > cursor`.
56///
57/// Binds:
58/// 1. execution_id (TEXT)
59/// 2. signal_id (TEXT)
60/// 3. waitpoint_id (Option<TEXT>)
61/// 4. source_identity (Option<TEXT>)
62/// 5. delivered_at_ms (i64)
63/// 6. partition_key (i64)
64#[allow(dead_code)] // Consumed by Phase 2b.2 deliver_signal
65pub(crate) const INSERT_SIGNAL_EVENT_SQL: &str = r#"
66 INSERT INTO ff_signal_event
67 (execution_id, signal_id, waitpoint_id, source_identity,
68 delivered_at_ms, partition_key)
69 VALUES (?1, ?2, ?3, ?4, ?5, ?6)
70"#;
71
72// Operator-event outbox inserts live in `queries::operator`
73// (Phase 3.2). See `queries/operator.rs::INSERT_OPERATOR_EVENT_SQL` —
74// the Wave-9 producer back-fills namespace + instance_tag from
75// exec_core.raw_fields via co-transactional SELECT, matching the
76// lease/completion/signal producer shape.