mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 16:56:33 +00:00
fix: dynamic FK drop in UUIDv7 migration — handle all constraints
Previous migration hard-coded FK constraint names and missed firmware_releases.uploaded_by, firmware_rollouts.created_by/release_id, os_update_releases.uploaded_by, os_update_rollouts.created_by/release_id, pairing_codes.consumed_by_kiosk_id, entities.camera_id. Now uses information_schema to dynamically drop ALL FK constraints before type conversion, and dynamically finds ALL integer id/*_id columns to convert. No more missed FKs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b4032ca8a
commit
108123fb86
1 changed files with 94 additions and 103 deletions
|
|
@ -495,8 +495,8 @@ export const TENANT_MIGRATIONS: readonly string[] = [
|
|||
`DO $$
|
||||
DECLARE
|
||||
col_type text;
|
||||
r record;
|
||||
BEGIN
|
||||
-- Only run if users.id is still integer (proxy for "needs migration").
|
||||
SELECT data_type INTO col_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = current_schema()
|
||||
|
|
@ -509,112 +509,103 @@ export const TENANT_MIGRATIONS: readonly string[] = [
|
|||
|
||||
RAISE NOTICE 'UUIDv7 migration: converting INTEGER PKs to TEXT...';
|
||||
|
||||
-- 1. Drop all FK constraints first (PG won't let us alter referenced types).
|
||||
-- sessions → users
|
||||
ALTER TABLE sessions DROP CONSTRAINT IF EXISTS sessions_user_id_fkey;
|
||||
-- api_keys → users
|
||||
ALTER TABLE api_keys DROP CONSTRAINT IF EXISTS api_keys_user_id_fkey;
|
||||
-- cameras — no FK to other tables with integer PK
|
||||
-- camera_streams → cameras
|
||||
ALTER TABLE camera_streams DROP CONSTRAINT IF EXISTS camera_streams_camera_id_fkey;
|
||||
-- layouts — no FK from layout.id
|
||||
-- display_layouts → displays, layouts
|
||||
ALTER TABLE display_layouts DROP CONSTRAINT IF EXISTS display_layouts_display_id_fkey;
|
||||
ALTER TABLE display_layouts DROP CONSTRAINT IF EXISTS display_layouts_layout_id_fkey;
|
||||
-- layout_cells → layouts, cameras
|
||||
ALTER TABLE layout_cells DROP CONSTRAINT IF EXISTS layout_cells_layout_id_fkey;
|
||||
ALTER TABLE layout_cells DROP CONSTRAINT IF EXISTS layout_cells_camera_id_fkey;
|
||||
-- kiosks → displays
|
||||
ALTER TABLE kiosks DROP CONSTRAINT IF EXISTS kiosks_display_id_fkey;
|
||||
-- labels — standalone
|
||||
-- kiosk_labels → kiosks, labels
|
||||
ALTER TABLE kiosk_labels DROP CONSTRAINT IF EXISTS kiosk_labels_kiosk_id_fkey;
|
||||
ALTER TABLE kiosk_labels DROP CONSTRAINT IF EXISTS kiosk_labels_label_id_fkey;
|
||||
-- camera_labels → cameras, labels
|
||||
ALTER TABLE camera_labels DROP CONSTRAINT IF EXISTS camera_labels_camera_id_fkey;
|
||||
ALTER TABLE camera_labels DROP CONSTRAINT IF EXISTS camera_labels_label_id_fkey;
|
||||
-- layout_labels → layouts, labels
|
||||
ALTER TABLE layout_labels DROP CONSTRAINT IF EXISTS layout_labels_layout_id_fkey;
|
||||
ALTER TABLE layout_labels DROP CONSTRAINT IF EXISTS layout_labels_label_id_fkey;
|
||||
-- event_log → kiosks, cameras
|
||||
ALTER TABLE event_log DROP CONSTRAINT IF EXISTS event_log_source_kiosk_id_fkey;
|
||||
ALTER TABLE event_log DROP CONSTRAINT IF EXISTS event_log_source_camera_id_fkey;
|
||||
-- kiosk_gpio_bindings → kiosks
|
||||
ALTER TABLE kiosk_gpio_bindings DROP CONSTRAINT IF EXISTS kiosk_gpio_bindings_kiosk_id_fkey;
|
||||
-- kiosk_logs → kiosks
|
||||
ALTER TABLE kiosk_logs DROP CONSTRAINT IF EXISTS kiosk_logs_kiosk_id_fkey;
|
||||
-- camera_event_subscriptions → cameras, kiosks
|
||||
ALTER TABLE camera_event_subscriptions DROP CONSTRAINT IF EXISTS camera_event_subscriptions_camera_id_fkey;
|
||||
ALTER TABLE camera_event_subscriptions DROP CONSTRAINT IF EXISTS camera_event_subscriptions_subscribed_by_kiosk_id_fkey;
|
||||
-- entities — standalone
|
||||
-- audit_log — standalone
|
||||
-- cloud_accounts — standalone (already TEXT PK)
|
||||
-- 1. Drop ALL foreign key constraints in current schema dynamically.
|
||||
FOR r IN
|
||||
SELECT tc.constraint_name, tc.table_name
|
||||
FROM information_schema.table_constraints tc
|
||||
WHERE tc.table_schema = current_schema()
|
||||
AND tc.constraint_type = 'FOREIGN KEY'
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE %I DROP CONSTRAINT IF EXISTS %I', r.table_name, r.constraint_name);
|
||||
END LOOP;
|
||||
|
||||
-- 2. Convert PK columns: add TEXT column, backfill, swap.
|
||||
-- Helper: for each table, ALTER COLUMN TYPE works if data is castable.
|
||||
-- Integer → TEXT cast is safe.
|
||||
ALTER TABLE users ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE api_keys ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE displays ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE cameras ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE camera_streams ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE layouts ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE layout_cells ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE kiosks ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE labels ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE event_log ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE entities ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE kiosk_gpio_bindings ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE audit_log ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE kiosk_logs ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
ALTER TABLE camera_event_subscriptions ALTER COLUMN id TYPE TEXT USING id::TEXT;
|
||||
-- 2. Convert every integer/bigint column that is a PK or FK to TEXT.
|
||||
FOR r IN
|
||||
SELECT c.table_name, c.column_name
|
||||
FROM information_schema.columns c
|
||||
WHERE c.table_schema = current_schema()
|
||||
AND c.data_type IN ('integer', 'bigint')
|
||||
AND (
|
||||
c.column_name = 'id'
|
||||
OR c.column_name LIKE '%_id'
|
||||
)
|
||||
AND c.table_name NOT IN ('schema_migrations')
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE %I ALTER COLUMN %I TYPE TEXT USING %I::TEXT',
|
||||
r.table_name, r.column_name, r.column_name);
|
||||
-- Drop any leftover default (sequences from old SERIAL columns).
|
||||
EXECUTE format('ALTER TABLE %I ALTER COLUMN %I DROP DEFAULT', r.table_name, r.column_name);
|
||||
END LOOP;
|
||||
|
||||
-- 3. Convert FK columns to TEXT too.
|
||||
ALTER TABLE sessions ALTER COLUMN user_id TYPE TEXT USING user_id::TEXT;
|
||||
ALTER TABLE api_keys ALTER COLUMN user_id TYPE TEXT USING user_id::TEXT;
|
||||
ALTER TABLE camera_streams ALTER COLUMN camera_id TYPE TEXT USING camera_id::TEXT;
|
||||
ALTER TABLE display_layouts ALTER COLUMN display_id TYPE TEXT USING display_id::TEXT;
|
||||
ALTER TABLE display_layouts ALTER COLUMN layout_id TYPE TEXT USING layout_id::TEXT;
|
||||
ALTER TABLE layout_cells ALTER COLUMN layout_id TYPE TEXT USING layout_id::TEXT;
|
||||
ALTER TABLE layout_cells ALTER COLUMN camera_id TYPE TEXT USING camera_id::TEXT;
|
||||
ALTER TABLE kiosks ALTER COLUMN display_id TYPE TEXT USING display_id::TEXT;
|
||||
ALTER TABLE kiosk_labels ALTER COLUMN kiosk_id TYPE TEXT USING kiosk_id::TEXT;
|
||||
ALTER TABLE kiosk_labels ALTER COLUMN label_id TYPE TEXT USING label_id::TEXT;
|
||||
ALTER TABLE camera_labels ALTER COLUMN camera_id TYPE TEXT USING camera_id::TEXT;
|
||||
ALTER TABLE camera_labels ALTER COLUMN label_id TYPE TEXT USING label_id::TEXT;
|
||||
ALTER TABLE layout_labels ALTER COLUMN layout_id TYPE TEXT USING layout_id::TEXT;
|
||||
ALTER TABLE layout_labels ALTER COLUMN label_id TYPE TEXT USING label_id::TEXT;
|
||||
ALTER TABLE event_log ALTER COLUMN source_kiosk_id TYPE TEXT USING source_kiosk_id::TEXT;
|
||||
ALTER TABLE event_log ALTER COLUMN source_camera_id TYPE TEXT USING source_camera_id::TEXT;
|
||||
ALTER TABLE kiosk_gpio_bindings ALTER COLUMN kiosk_id TYPE TEXT USING kiosk_id::TEXT;
|
||||
ALTER TABLE kiosk_logs ALTER COLUMN kiosk_id TYPE TEXT USING kiosk_id::TEXT;
|
||||
ALTER TABLE camera_event_subscriptions ALTER COLUMN camera_id TYPE TEXT USING camera_id::TEXT;
|
||||
ALTER TABLE camera_event_subscriptions ALTER COLUMN subscribed_by_kiosk_id TYPE TEXT USING subscribed_by_kiosk_id::TEXT;
|
||||
-- displays.default_layout_id
|
||||
ALTER TABLE displays ALTER COLUMN default_layout_id TYPE TEXT USING default_layout_id::TEXT;
|
||||
-- 3. Drop orphan sequences (leftover from SERIAL columns).
|
||||
FOR r IN
|
||||
SELECT sequence_name
|
||||
FROM information_schema.sequences
|
||||
WHERE sequence_schema = current_schema()
|
||||
AND sequence_name LIKE '%_id_seq'
|
||||
LOOP
|
||||
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 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;
|
||||
|
||||
RAISE NOTICE 'UUIDv7 migration: complete — all PKs and FKs are now TEXT';
|
||||
END $$`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue