Skip to main content

fraiseql_functions/migrations/
mod.rs

1//! Database migrations for functions infrastructure tables.
2//!
3//! Exposes DDL that `fraiseql-cli migrate up` can execute to create the
4//! `_fraiseql_cron_state` table, which persists cron scheduler state between
5//! server restarts.
6
7#[cfg(test)]
8mod tests;
9
10/// Returns the SQL DDL to create the cron state table and indexes.
11///
12/// The DDL uses `IF NOT EXISTS` for idempotency — running it multiple times
13/// is safe and produces no errors.
14///
15/// # Table Schema
16///
17/// | Column | Type | Notes |
18/// |--------|------|-------|
19/// | `pk_cron_state` | `BIGINT GENERATED ALWAYS AS IDENTITY` | Trinity-style PK |
20/// | `function_name` | `TEXT NOT NULL` | Function with the cron trigger |
21/// | `cron_expr` | `TEXT NOT NULL` | Cron expression that fired |
22/// | `last_fired_at` | `TIMESTAMPTZ NOT NULL` | When the cron last fired |
23/// | `next_fire_at` | `TIMESTAMPTZ` | Computed next fire time (optional) |
24/// | `fire_count` | `BIGINT NOT NULL DEFAULT 0` | Total number of fires |
25/// | `updated_at` | `TIMESTAMPTZ NOT NULL DEFAULT now()` | Last row update |
26///
27/// # Example
28///
29/// ```
30/// let sql = fraiseql_functions::migrations::cron_migration_sql();
31/// assert!(sql.contains("_fraiseql_cron_state"));
32/// ```
33#[must_use]
34pub const fn cron_migration_sql() -> &'static str {
35    "\
36CREATE TABLE IF NOT EXISTS _fraiseql_cron_state (
37    pk_cron_state   BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
38    function_name   TEXT        NOT NULL,
39    cron_expr       TEXT        NOT NULL,
40    last_fired_at   TIMESTAMPTZ NOT NULL,
41    next_fire_at    TIMESTAMPTZ,
42    fire_count      BIGINT      NOT NULL DEFAULT 0,
43    updated_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
44    UNIQUE (function_name, cron_expr)
45);
46
47CREATE INDEX IF NOT EXISTS idx_cron_state_function
48    ON _fraiseql_cron_state (function_name);
49
50CREATE INDEX IF NOT EXISTS idx_cron_state_next_fire
51    ON _fraiseql_cron_state (next_fire_at)
52    WHERE next_fire_at IS NOT NULL;
53"
54}