/** * Migration: Update foreign key references to use new UUID columns * * Phase 2 of 3 for migrating Serial primary keys to UUID * This migration adds UUID foreign key columns and migrates the data * * Foreign Key Relationships to Update: * - weather_forecasts.station_id -> weather_stations.id * - weather_observations.weather_station_id -> weather_stations.id * - user_subscriptions.subscription_plan_id -> subscription_plans.id * - subscription_history.user_subscription_id -> user_subscriptions.id * - payment_records.user_subscription_id -> user_subscriptions.id * * @type {import('node-pg-migrate').ColumnDefinitions | undefined} */ export const shorthands = undefined; /** * @param pgm {import('node-pg-migrate').MigrationBuilder} * @param run {() => void | undefined} * @returns {Promise | void} */ export const up = (pgm) => { console.log('Phase 2: Updating foreign key references to use UUID...'); // ===================================================== // 1. weather_forecasts.station_id -> weather_stations // ===================================================== console.log(' Updating weather_forecasts.station_id...'); pgm.addColumn('weather_forecasts', { new_station_id: { type: 'uuid', notNull: false, comment: 'Temporary UUID FK for migration', }, }); pgm.sql(` UPDATE weather_forecasts wf SET new_station_id = ws.new_id FROM weather_stations ws WHERE wf.station_id = ws.id; `); // ===================================================== // 2. weather_observations.weather_station_id -> weather_stations // ===================================================== console.log(' Updating weather_observations.weather_station_id...'); pgm.addColumn('weather_observations', { new_weather_station_id: { type: 'uuid', notNull: false, comment: 'Temporary UUID FK for migration', }, }); pgm.sql(` UPDATE weather_observations wo SET new_weather_station_id = ws.new_id FROM weather_stations ws WHERE wo.weather_station_id = ws.id; `); // ===================================================== // 3. user_subscriptions.subscription_plan_id -> subscription_plans // ===================================================== console.log(' Updating user_subscriptions.subscription_plan_id...'); pgm.addColumn('user_subscriptions', { new_subscription_plan_id: { type: 'uuid', notNull: false, comment: 'Temporary UUID FK for migration', }, }); pgm.sql(` UPDATE user_subscriptions us SET new_subscription_plan_id = sp.new_id FROM subscription_plans sp WHERE us.subscription_plan_id = sp.id; `); // ===================================================== // 4. subscription_history.user_subscription_id -> user_subscriptions // ===================================================== console.log(' Updating subscription_history.user_subscription_id...'); pgm.addColumn('subscription_history', { new_user_subscription_id: { type: 'uuid', notNull: false, comment: 'Temporary UUID FK for migration', }, }); pgm.sql(` UPDATE subscription_history sh SET new_user_subscription_id = us.new_id FROM user_subscriptions us WHERE sh.user_subscription_id = us.id; `); // ===================================================== // 5. payment_records.user_subscription_id -> user_subscriptions // ===================================================== console.log(' Updating payment_records.user_subscription_id...'); pgm.addColumn('payment_records', { new_user_subscription_id: { type: 'uuid', notNull: false, comment: 'Temporary UUID FK for migration', }, }); pgm.sql(` UPDATE payment_records pr SET new_user_subscription_id = us.new_id FROM user_subscriptions us WHERE pr.user_subscription_id = us.id; `); // Create indexes on new FK columns for validation pgm.createIndex('weather_forecasts', 'new_station_id', { name: 'idx_weather_forecasts_new_station_id', }); pgm.createIndex('weather_observations', 'new_weather_station_id', { name: 'idx_weather_observations_new_station_id', }); pgm.createIndex('user_subscriptions', 'new_subscription_plan_id', { name: 'idx_user_subscriptions_new_plan_id', }); pgm.createIndex('subscription_history', 'new_user_subscription_id', { name: 'idx_subscription_history_new_sub_id', }); pgm.createIndex('payment_records', 'new_user_subscription_id', { name: 'idx_payment_records_new_sub_id', }); console.log('Phase 2 complete: Foreign key references updated.'); }; /** * @param pgm {import('node-pg-migrate').MigrationBuilder} * @param run {() => void | undefined} * @returns {Promise | void} */ export const down = (pgm) => { console.log('Rolling back Phase 2: Removing UUID FK columns...'); // Drop indexes const indexes = [ { table: 'weather_forecasts', name: 'idx_weather_forecasts_new_station_id' }, { table: 'weather_observations', name: 'idx_weather_observations_new_station_id' }, { table: 'user_subscriptions', name: 'idx_user_subscriptions_new_plan_id' }, { table: 'subscription_history', name: 'idx_subscription_history_new_sub_id' }, { table: 'payment_records', name: 'idx_payment_records_new_sub_id' }, ]; indexes.forEach(({ table, name }) => { pgm.dropIndex(table, [], { name, ifExists: true }); }); // Drop columns pgm.dropColumn('weather_forecasts', 'new_station_id', { ifExists: true }); pgm.dropColumn('weather_observations', 'new_weather_station_id', { ifExists: true }); pgm.dropColumn('user_subscriptions', 'new_subscription_plan_id', { ifExists: true }); pgm.dropColumn('subscription_history', 'new_user_subscription_id', { ifExists: true }); pgm.dropColumn('payment_records', 'new_user_subscription_id', { ifExists: true }); console.log('Phase 2 rollback complete.'); };