mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 16:56:33 +00:00
fix: dynamic FK re-add with column existence check
Previous migration hardcoded ALTER TABLE ADD CONSTRAINT for FK re-add, but production DB may have different columns than CREATE TABLE schema (api_keys had no user_id). Now uses _bf_add_fk() helper that checks both source column and target column exist before adding FK. Skips silently if either is missing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fe9c51d3f0
commit
02b69713c3
1 changed files with 54 additions and 59 deletions
|
|
@ -492,6 +492,30 @@ export const TENANT_MIGRATIONS: readonly string[] = [
|
|||
// databases that already have TEXT PKs (DO NOTHING on conflict).
|
||||
// gen_random_uuid() generates UUIDv4 — close enough for backfill.
|
||||
// New rows already use app-generated UUIDv7 from repository.ts.
|
||||
`CREATE OR REPLACE FUNCTION _bf_add_fk(
|
||||
src_table text, src_col text, ref_table text, ref_col text, on_del text
|
||||
) RETURNS void LANGUAGE plpgsql AS $fn$
|
||||
DECLARE
|
||||
col_exists boolean;
|
||||
ref_exists boolean;
|
||||
cname text;
|
||||
BEGIN
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = current_schema() AND table_name = src_table AND column_name = src_col
|
||||
) INTO col_exists;
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = current_schema() AND table_name = ref_table AND column_name = ref_col
|
||||
) INTO ref_exists;
|
||||
IF NOT col_exists OR NOT ref_exists THEN RETURN; END IF;
|
||||
cname := src_table || '_' || src_col || '_fkey';
|
||||
EXECUTE format(
|
||||
'ALTER TABLE %I ADD CONSTRAINT %I FOREIGN KEY (%I) REFERENCES %I(%I) ON DELETE %s',
|
||||
src_table, cname, src_col, ref_table, ref_col, on_del
|
||||
);
|
||||
END $fn$`,
|
||||
|
||||
`DO $$
|
||||
DECLARE
|
||||
col_type text;
|
||||
|
|
@ -547,65 +571,36 @@ export const TENANT_MIGRATIONS: readonly string[] = [
|
|||
EXECUTE format('DROP SEQUENCE IF EXISTS %I CASCADE', r.sequence_name);
|
||||
END LOOP;
|
||||
|
||||
-- 4. Re-add FK constraints.
|
||||
ALTER TABLE sessions ADD CONSTRAINT sessions_user_id_fkey
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
ALTER TABLE api_keys ADD CONSTRAINT api_keys_user_id_fkey
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
ALTER TABLE camera_streams ADD CONSTRAINT camera_streams_camera_id_fkey
|
||||
FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE CASCADE;
|
||||
ALTER TABLE display_layouts ADD CONSTRAINT display_layouts_display_id_fkey
|
||||
FOREIGN KEY (display_id) REFERENCES displays(id) ON DELETE CASCADE;
|
||||
ALTER TABLE display_layouts ADD CONSTRAINT display_layouts_layout_id_fkey
|
||||
FOREIGN KEY (layout_id) REFERENCES layouts(id) ON DELETE CASCADE;
|
||||
ALTER TABLE layout_cells ADD CONSTRAINT layout_cells_layout_id_fkey
|
||||
FOREIGN KEY (layout_id) REFERENCES layouts(id) ON DELETE CASCADE;
|
||||
ALTER TABLE layout_cells ADD CONSTRAINT layout_cells_camera_id_fkey
|
||||
FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE SET NULL;
|
||||
ALTER TABLE kiosks ADD CONSTRAINT kiosks_display_id_fkey
|
||||
FOREIGN KEY (display_id) REFERENCES displays(id) ON DELETE SET NULL;
|
||||
ALTER TABLE kiosk_labels ADD CONSTRAINT kiosk_labels_kiosk_id_fkey
|
||||
FOREIGN KEY (kiosk_id) REFERENCES kiosks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE kiosk_labels ADD CONSTRAINT kiosk_labels_label_id_fkey
|
||||
FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE;
|
||||
ALTER TABLE camera_labels ADD CONSTRAINT camera_labels_camera_id_fkey
|
||||
FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE CASCADE;
|
||||
ALTER TABLE camera_labels ADD CONSTRAINT camera_labels_label_id_fkey
|
||||
FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE;
|
||||
ALTER TABLE layout_labels ADD CONSTRAINT layout_labels_layout_id_fkey
|
||||
FOREIGN KEY (layout_id) REFERENCES layouts(id) ON DELETE CASCADE;
|
||||
ALTER TABLE layout_labels ADD CONSTRAINT layout_labels_label_id_fkey
|
||||
FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE;
|
||||
ALTER TABLE event_log ADD CONSTRAINT event_log_source_kiosk_id_fkey
|
||||
FOREIGN KEY (source_kiosk_id) REFERENCES kiosks(id) ON DELETE SET NULL;
|
||||
ALTER TABLE event_log ADD CONSTRAINT event_log_source_camera_id_fkey
|
||||
FOREIGN KEY (source_camera_id) REFERENCES cameras(id) ON DELETE SET NULL;
|
||||
ALTER TABLE kiosk_gpio_bindings ADD CONSTRAINT kiosk_gpio_bindings_kiosk_id_fkey
|
||||
FOREIGN KEY (kiosk_id) REFERENCES kiosks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE kiosk_logs ADD CONSTRAINT kiosk_logs_kiosk_id_fkey
|
||||
FOREIGN KEY (kiosk_id) REFERENCES kiosks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE camera_event_subscriptions ADD CONSTRAINT camera_event_subscriptions_camera_id_fkey
|
||||
FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE CASCADE;
|
||||
ALTER TABLE camera_event_subscriptions ADD CONSTRAINT camera_event_subscriptions_subscribed_by_kiosk_id_fkey
|
||||
FOREIGN KEY (subscribed_by_kiosk_id) REFERENCES kiosks(id) ON DELETE SET NULL;
|
||||
ALTER TABLE displays ADD CONSTRAINT displays_default_layout_id_fkey
|
||||
FOREIGN KEY (default_layout_id) REFERENCES layouts(id) ON DELETE SET NULL;
|
||||
ALTER TABLE pairing_codes ADD CONSTRAINT pairing_codes_consumed_by_kiosk_id_fkey
|
||||
FOREIGN KEY (consumed_by_kiosk_id) REFERENCES kiosks(id) ON DELETE SET NULL;
|
||||
ALTER TABLE firmware_releases ADD CONSTRAINT firmware_releases_uploaded_by_fkey
|
||||
FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL;
|
||||
ALTER TABLE firmware_rollouts ADD CONSTRAINT firmware_rollouts_release_id_fkey
|
||||
FOREIGN KEY (release_id) REFERENCES firmware_releases(id) ON DELETE CASCADE;
|
||||
ALTER TABLE firmware_rollouts ADD CONSTRAINT firmware_rollouts_created_by_fkey
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL;
|
||||
ALTER TABLE os_update_releases ADD CONSTRAINT os_update_releases_uploaded_by_fkey
|
||||
FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL;
|
||||
ALTER TABLE os_update_rollouts ADD CONSTRAINT os_update_rollouts_release_id_fkey
|
||||
FOREIGN KEY (release_id) REFERENCES os_update_releases(id) ON DELETE CASCADE;
|
||||
ALTER TABLE os_update_rollouts ADD CONSTRAINT os_update_rollouts_created_by_fkey
|
||||
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL;
|
||||
ALTER TABLE entities ADD CONSTRAINT entities_camera_id_fkey
|
||||
FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE CASCADE;
|
||||
-- 4. Re-add FK constraints (only if both table and column exist).
|
||||
PERFORM _bf_add_fk('sessions', 'user_id', 'users', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('api_keys', 'user_id', 'users', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('camera_streams', 'camera_id', 'cameras', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('display_layouts','display_id', 'displays', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('display_layouts','layout_id', 'layouts', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('layout_cells', 'layout_id', 'layouts', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('layout_cells', 'camera_id', 'cameras', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('kiosks', 'display_id', 'displays', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('kiosk_labels', 'kiosk_id', 'kiosks', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('kiosk_labels', 'label_id', 'labels', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('camera_labels', 'camera_id', 'cameras', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('camera_labels', 'label_id', 'labels', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('layout_labels', 'layout_id', 'layouts', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('layout_labels', 'label_id', 'labels', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('event_log', 'source_kiosk_id', 'kiosks', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('event_log', 'source_camera_id', 'cameras', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('kiosk_gpio_bindings','kiosk_id', 'kiosks', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('kiosk_logs', 'kiosk_id', 'kiosks', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('camera_event_subscriptions','camera_id', 'cameras', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('camera_event_subscriptions','subscribed_by_kiosk_id','kiosks', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('displays', 'default_layout_id', 'layouts', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('pairing_codes', 'consumed_by_kiosk_id', 'kiosks', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('firmware_releases','uploaded_by', 'users', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('firmware_rollouts','release_id', 'firmware_releases', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('firmware_rollouts','created_by', 'users', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('os_update_releases','uploaded_by', 'users', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('os_update_rollouts','release_id', 'os_update_releases', 'id', 'CASCADE');
|
||||
PERFORM _bf_add_fk('os_update_rollouts','created_by', 'users', 'id', 'SET NULL');
|
||||
PERFORM _bf_add_fk('entities', 'camera_id', 'cameras', 'id', 'CASCADE');
|
||||
|
||||
RAISE NOTICE 'UUIDv7 migration: complete — all PKs and FKs are now TEXT';
|
||||
END $$`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue