From f373c85c160c78b2819adc568525f2e4dc6abd74 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Mon, 27 Apr 2026 12:51:32 -0400 Subject: [PATCH] Fix false-positive stale view warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rules/mappings changes don't affect view SQL (views read from transformed, shaped by config.fields) — remove those triggers. Replace with a BEFORE UPDATE trigger on sources that only clears view_generated_at when config actually changes. Stack sources trigger now skips no-op upserts: the live SQL preview calls upsertStackSource on every edit, which was unconditionally clearing view_generated_at even when nothing changed. Co-Authored-By: Claude Sonnet 4.6 --- database/queries/status.sql | 49 +++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/database/queries/status.sql b/database/queries/status.sql index 19fc8ea..8d80235 100644 --- a/database/queries/status.sql +++ b/database/queries/status.sql @@ -10,45 +10,46 @@ ALTER TABLE dataflow.sources ADD COLUMN IF NOT EXISTS view_generated_at TIMESTAM ALTER TABLE dataflow.stacks ADD COLUMN IF NOT EXISTS view_generated_at TIMESTAMPTZ; ------------------------------------------------------ --- Trigger: clear source view_generated_at when rules change +-- Trigger: clear source view_generated_at when config (field definitions) changes +-- Rules and mappings affect transformed data, not view structure — no trigger needed there ------------------------------------------------------ -CREATE OR REPLACE FUNCTION dataflow.rules_changed() -RETURNS TRIGGER AS $$ -BEGIN - UPDATE dataflow.sources SET view_generated_at = NULL - WHERE name = COALESCE(NEW.source_name, OLD.source_name); - RETURN NULL; -END; -$$ LANGUAGE plpgsql; - DROP TRIGGER IF EXISTS trg_rules_changed ON dataflow.rules; -CREATE TRIGGER trg_rules_changed -AFTER INSERT OR UPDATE OR DELETE ON dataflow.rules -FOR EACH ROW EXECUTE FUNCTION dataflow.rules_changed(); +DROP TRIGGER IF EXISTS trg_mappings_changed ON dataflow.mappings; +DROP FUNCTION IF EXISTS dataflow.rules_changed(); +DROP FUNCTION IF EXISTS dataflow.mappings_changed(); ------------------------------------------------------- --- Trigger: clear source view_generated_at when mappings change ------------------------------------------------------- -CREATE OR REPLACE FUNCTION dataflow.mappings_changed() +CREATE OR REPLACE FUNCTION dataflow.source_config_changed() RETURNS TRIGGER AS $$ BEGIN - UPDATE dataflow.sources SET view_generated_at = NULL - WHERE name = COALESCE(NEW.source_name, OLD.source_name); - RETURN NULL; + IF NEW.config IS DISTINCT FROM OLD.config THEN + NEW.view_generated_at := NULL; + END IF; + RETURN NEW; END; $$ LANGUAGE plpgsql; -DROP TRIGGER IF EXISTS trg_mappings_changed ON dataflow.mappings; -CREATE TRIGGER trg_mappings_changed -AFTER INSERT OR UPDATE OR DELETE ON dataflow.mappings -FOR EACH ROW EXECUTE FUNCTION dataflow.mappings_changed(); +DROP TRIGGER IF EXISTS trg_source_config_changed ON dataflow.sources; +CREATE TRIGGER trg_source_config_changed +BEFORE UPDATE ON dataflow.sources +FOR EACH ROW EXECUTE FUNCTION dataflow.source_config_changed(); ------------------------------------------------------ -- Trigger: clear stack view_generated_at when sources change +-- On UPDATE, skip if all view-relevant columns are unchanged (upsert no-ops should not mark stale) ------------------------------------------------------ CREATE OR REPLACE FUNCTION dataflow.stack_sources_changed() RETURNS TRIGGER AS $$ BEGIN + IF TG_OP = 'UPDATE' THEN + IF NEW.field_map IS NOT DISTINCT FROM OLD.field_map AND + NEW.amount_sign IS NOT DISTINCT FROM OLD.amount_sign AND + NEW.balance_offset IS NOT DISTINCT FROM OLD.balance_offset AND + NEW.amount_field IS NOT DISTINCT FROM OLD.amount_field AND + NEW.date_field IS NOT DISTINCT FROM OLD.date_field AND + NEW.seq IS NOT DISTINCT FROM OLD.seq THEN + RETURN NULL; + END IF; + END IF; UPDATE dataflow.stacks SET view_generated_at = NULL WHERE name = COALESCE(NEW.stack_name, OLD.stack_name); RETURN NULL;