Skip to main content

ff_backend_sqlite/queries/
waitpoint.rs

1//! SQL statements for waitpoint + HMAC secret ops
2//! (RFC-023 Phase 2b.2.1).
3//!
4//! Mirrors `ff-backend-postgres/src/signal.rs` +
5//! `ff-backend-postgres/src/suspend_ops.rs` at the statement level;
6//! dialect deltas are the usual `jsonb → TEXT`, `$n → ?n`, no
7//! `ON CONFLICT (cols) DO UPDATE SET col = EXCLUDED.col` array
8//! binding (we bind lists via JSON strings where PG used `text[]`).
9
10// ── HMAC keystore (ff_waitpoint_hmac) ─────────────────────────────────
11
12pub const SELECT_ACTIVE_HMAC_SQL: &str = "SELECT kid, secret FROM ff_waitpoint_hmac \
13     WHERE active = 1 \
14     ORDER BY rotated_at_ms DESC LIMIT 1";
15
16pub const SELECT_HMAC_SECRET_BY_KID_SQL: &str =
17    "SELECT secret FROM ff_waitpoint_hmac WHERE kid = ?1";
18
19pub const DEACTIVATE_ALL_HMAC_SQL: &str =
20    "UPDATE ff_waitpoint_hmac SET active = 0 WHERE active = 1";
21
22pub const INSERT_HMAC_ROW_SQL: &str = "INSERT INTO ff_waitpoint_hmac \
23     (kid, secret, rotated_at_ms, active) \
24     VALUES (?1, ?2, ?3, 1)";
25
26pub const SELECT_ACTIVE_KID_SQL: &str = "SELECT kid FROM ff_waitpoint_hmac \
27     WHERE active = 1 \
28     ORDER BY rotated_at_ms DESC LIMIT 1";
29
30// ── Pending waitpoint row (ff_waitpoint_pending) ──────────────────────
31
32/// Insert-or-overwrite a waitpoint row. `required_signal_names` goes in
33/// as a JSON-encoded TEXT column (SQLite has no native text[]).
34/// Binds: 1=partition_key, 2=waitpoint_id, 3=execution_id,
35///        4=token_kid, 5=token, 6=created_at_ms, 7=expires_at_ms,
36///        8=waitpoint_key, 9=required_signal_names_json.
37pub const UPSERT_WAITPOINT_PENDING_ACTIVE_SQL: &str = "INSERT INTO ff_waitpoint_pending \
38     (partition_key, waitpoint_id, execution_id, token_kid, token, \
39      created_at_ms, expires_at_ms, waitpoint_key, \
40      state, required_signal_names, activated_at_ms) \
41     VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, 'active', ?9, ?6) \
42     ON CONFLICT (partition_key, waitpoint_id) DO UPDATE SET \
43       token_kid = excluded.token_kid, token = excluded.token, \
44       waitpoint_key = excluded.waitpoint_key, \
45       state = excluded.state, \
46       required_signal_names = excluded.required_signal_names, \
47       activated_at_ms = excluded.activated_at_ms";
48
49/// Fresh pending-waitpoint row for `create_waitpoint` — state stays
50/// `pending`, no `activated_at_ms`.
51/// Binds: 1=partition, 2=waitpoint_id, 3=execution_id, 4=kid,
52///        5=token, 6=created_at_ms, 7=expires_at_ms, 8=waitpoint_key.
53pub const INSERT_WAITPOINT_PENDING_SQL: &str = "INSERT INTO ff_waitpoint_pending \
54     (partition_key, waitpoint_id, execution_id, token_kid, token, \
55      created_at_ms, expires_at_ms, waitpoint_key, state, required_signal_names) \
56     VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, 'pending', '[]')";
57
58pub const SELECT_WAITPOINT_KEY_BY_ID_SQL: &str =
59    "SELECT waitpoint_key FROM ff_waitpoint_pending \
60     WHERE partition_key = ?1 AND waitpoint_id = ?2";
61
62/// For deliver_signal: read kid + token + wp_key + bound execution.
63/// Returns (token_kid, token, waitpoint_key, execution_id).
64pub const SELECT_WAITPOINT_FOR_DELIVER_SQL: &str =
65    "SELECT token_kid, token, waitpoint_key, execution_id \
66       FROM ff_waitpoint_pending \
67      WHERE partition_key = ?1 AND waitpoint_id = ?2";
68
69/// Delete every waitpoint row for a resolved execution.
70pub const DELETE_WAITPOINTS_BY_EXEC_SQL: &str =
71    "DELETE FROM ff_waitpoint_pending \
72      WHERE partition_key = ?1 AND execution_id = ?2";
73
74// ── list_pending_waitpoints (RFC-020 §4.5, Phase 3.3) ──────────────
75
76/// Existence probe — matches PG reference's `EXISTS exec_core`
77/// pre-check so a non-existent execution surfaces `NotFound` rather
78/// than an empty page. Binds: ?1 partition_key, ?2 execution_id BLOB.
79pub const SELECT_EXEC_EXISTS_SQL: &str =
80    "SELECT 1 FROM ff_exec_core WHERE partition_key = ?1 AND execution_id = ?2";
81
82/// Cursor-paginated scan of `ff_waitpoint_pending` for one execution.
83/// Filters to `state IN ('pending','active')` (matches Valkey's
84/// client-side keep filter). Fetches `limit + 1` to detect "more to
85/// come" without a second round-trip.
86///
87/// Binds:
88///   1. partition_key (i64)
89///   2. execution_id BLOB
90///   3. after_waitpoint_id BLOB — NULL → no cursor
91///   4. limit_plus_one (i64)
92pub const SELECT_PENDING_WAITPOINTS_PAGE_SQL: &str =
93    "SELECT waitpoint_id, waitpoint_key, state, required_signal_names, \
94            created_at_ms, activated_at_ms, expires_at_ms, token_kid, token \
95       FROM ff_waitpoint_pending \
96      WHERE partition_key = ?1 \
97        AND execution_id  = ?2 \
98        AND state IN ('pending', 'active') \
99        AND (?3 IS NULL OR waitpoint_id > ?3) \
100      ORDER BY waitpoint_id \
101      LIMIT ?4";