param( [string]$OldNamespace = "ircs-system", [string]$NewNamespace = "ircs-prod", [string]$Database = "ircs", [switch]$Execute, [switch]$TruncateTarget ) $ErrorActionPreference = "Stop" $tables = @( 'actors', 'collection_tasks', 'cover_images', 'data_sources', 'directors', 'episodes', 'failed_messages', 'magnet_links', 'magnet_provider_runs', 'magnet_providers', 'magnet_search_jobs', 'member_favorites', 'member_watch_histories', 'members', 'playlists', 'raw_areas', 'raw_category', 'raw_genres', 'raw_languages', 'raw_video_unified_video', 'raw_videos', 'request_audit_logs', 'search_sync_tasks', 'source_domains', 'standard_areas', 'standard_category', 'standard_genre', 'standard_languages', 'sys_credentials', 'system_configs', 'unified_video_actors', 'unified_video_directors', 'unified_video_genres', 'unified_video_standard_areas', 'unified_video_standard_languages', 'unified_videos', 'user_messages', 'video_actors', 'video_directors', 'video_raw_areas', 'video_raw_genres', 'video_raw_languages', 'video_resolver_sources' ) function Invoke-Postgres($Namespace, $Sql) { $escapedSql = $Sql.Replace("'", "'\''") kubectl -n $Namespace exec statefulset/postgres -- sh -lc "PGPASSWORD=\`$POSTGRES_PASSWORD psql -U postgres -d $Database -Atc '$escapedSql'" } Write-Host "Compatible business tables planned for migration: $($tables.Count)" Write-Host "Excluded tables: databasechangelog, databasechangeloglock, V3 runtime audit/outbox/maintenance derived tables." $oldTables = Invoke-Postgres $OldNamespace "select tablename from pg_tables where schemaname='public' order by tablename" $newTables = Invoke-Postgres $NewNamespace "select tablename from pg_tables where schemaname='public' order by tablename" $missingOld = $tables | Where-Object { $_ -notin $oldTables } $missingNew = $tables | Where-Object { $_ -notin $newTables } if ($missingOld) { throw "Old namespace is missing expected tables: $($missingOld -join ', ')" } if ($missingNew) { throw "New namespace is missing expected tables. Run ircs-prod core migrator first: $($missingNew -join ', ')" } if (-not $Execute) { Write-Host "Dry run only. Add -Execute to stream data from $OldNamespace to $NewNamespace." exit 0 } if ($TruncateTarget) { $quoted = ($tables | ForEach-Object { 'public."' + $_ + '"' }) -join ', ' Invoke-Postgres $NewNamespace "truncate table $quoted restart identity cascade" | Out-Null } $tableArgs = ($tables | ForEach-Object { "--table=public.$_" }) -join ' ' $dumpCmd = "PGPASSWORD=\`$POSTGRES_PASSWORD pg_dump -U postgres -d $Database --data-only --column-inserts --disable-triggers $tableArgs" $loadCmd = "PGPASSWORD=\`$POSTGRES_PASSWORD psql -U postgres -d $Database -v ON_ERROR_STOP=1" kubectl -n $OldNamespace exec statefulset/postgres -- sh -lc $dumpCmd | kubectl -n $NewNamespace exec -i statefulset/postgres -- sh -lc $loadCmd Write-Host "Compatible data migration stream finished."