//! Template-suppression markers (ยง11 tail) โ€” the `template_suppressions` table //! (0058, made owner-polymorphic in 0060). A marker `(owner, target_kind, //! reference)` records that an OWNER opts OUT of an inherited group template: a //! handler script name it declines (`target_kind='trigger'`) or a path it //! declines (`target_kind='route'`). //! //! Owner-polymorphic (like `extension_points`): an **app** declines for itself; //! a **group** declines for its whole subtree. The functions take a //! `ScriptOwner` and bind the matching owner column. Same tx-function style: //! read over `&PgPool`, write over a `&mut Transaction`. use picloud_shared::ScriptOwner; use sqlx::{PgPool, Postgres, Transaction}; /// The two suppressible template kinds, as stored in `target_kind`. pub const TARGET_TRIGGER: &str = "trigger"; pub const TARGET_ROUTE: &str = "route"; /// List the suppression markers declared at `owner`, as `(target_kind, /// reference)` pairs, stably ordered. Backs `load_current` (the apply diff) and /// the read-only `suppress ls`. pub async fn list_for_owner( pool: &PgPool, owner: ScriptOwner, ) -> Result, sqlx::Error> { let sql = match owner { ScriptOwner::App(_) => { "SELECT target_kind, reference FROM template_suppressions \ WHERE app_id = $1 ORDER BY target_kind, LOWER(reference)" } ScriptOwner::Group(_) => { "SELECT target_kind, reference FROM template_suppressions \ WHERE group_id = $1 ORDER BY target_kind, LOWER(reference)" } }; sqlx::query_as(sql) .bind(owner_uuid(owner)) .fetch_all(pool) .await } /// Insert a suppression marker in the apply transaction. Idempotent: re-apply /// of an already-declared `(kind, reference)` is a no-op (`ON CONFLICT DO /// NOTHING` against the per-owner partial unique index), so the marker survives /// without a spurious version bump. pub async fn insert_suppression_tx( tx: &mut Transaction<'_, Postgres>, owner: ScriptOwner, target_kind: &str, reference: &str, ) -> Result<(), sqlx::Error> { let (app_id, group_id) = owner_columns(owner); sqlx::query( "INSERT INTO template_suppressions (app_id, group_id, target_kind, reference) \ VALUES ($1, $2, $3, $4) \ ON CONFLICT DO NOTHING", ) .bind(app_id) .bind(group_id) .bind(target_kind) .bind(reference) .execute(&mut **tx) .await?; Ok(()) } /// Delete a suppression marker in the apply transaction. Used by `--prune` when /// the manifest stops declaring the reference โ†’ the template re-inherits. pub async fn delete_suppression_tx( tx: &mut Transaction<'_, Postgres>, owner: ScriptOwner, target_kind: &str, reference: &str, ) -> Result<(), sqlx::Error> { let sql = match owner { ScriptOwner::App(_) => { "DELETE FROM template_suppressions \ WHERE app_id = $1 AND target_kind = $2 AND reference = $3" } ScriptOwner::Group(_) => { "DELETE FROM template_suppressions \ WHERE group_id = $1 AND target_kind = $2 AND reference = $3" } }; sqlx::query(sql) .bind(owner_uuid(owner)) .bind(target_kind) .bind(reference) .execute(&mut **tx) .await?; Ok(()) } /// `(app_id, group_id)` bind pair for the polymorphic owner โ€” exactly one set. fn owner_columns(owner: ScriptOwner) -> (Option, Option) { match owner { ScriptOwner::App(a) => (Some(a.into_inner()), None), ScriptOwner::Group(g) => (None, Some(g.into_inner())), } } /// The single owner UUID (app or group), for the WHERE-on-one-column queries. fn owner_uuid(owner: ScriptOwner) -> uuid::Uuid { match owner { ScriptOwner::App(a) => a.into_inner(), ScriptOwner::Group(g) => g.into_inner(), } }