hensei-api/db/migrate/20250307075433_convert_game_raw_columns_to_jsonb.rb
Justin Edmund 07e5488e0b Add custom page size support via X-Per-Page header
- Add page_size helper method to read from X-Per-Page header
- Set min (1) and max (100) bounds for page sizes
- Update all paginated endpoints to use dynamic page size
- Maintain backward compatibility with default sizes
2025-09-17 05:44:14 -07:00

86 lines
3.1 KiB
Ruby

# frozen_string_literal: true
class ConvertGameRawColumnsToJsonb < ActiveRecord::Migration[8.0]
def up
tables = %w[characters summons weapons]
tables.each do |table|
# Create a backup of game_raw_en to prevent data loss
add_column table, :game_raw_en_backup, :text
execute("UPDATE #{table} SET game_raw_en_backup = game_raw_en WHERE game_raw_en IS NOT NULL")
# Verify backup integrity
backup_validation = execute(<<~SQL).first
SELECT COUNT(*) AS missing_backups
FROM #{table}
WHERE game_raw_en IS NOT NULL#{' '}
AND game_raw_en_backup IS NULL
SQL
if backup_validation['missing_backups'].to_i.positive?
raise ActiveRecord::MigrationError, "Backup failed for #{table}. Aborting migration."
end
# Convert game_raw_en with data validation
begin
execute("ALTER TABLE #{table} ALTER COLUMN game_raw_en TYPE JSONB USING game_raw_en::JSONB")
rescue StandardError => e
# Find and report problematic rows
create_invalid_rows_table(table)
invalid_count = execute("SELECT COUNT(*) FROM invalid_#{table}_rows").first['count']
raise ActiveRecord::MigrationError, <<~ERROR
Failed to convert game_raw_en in #{table} to JSONB.
#{invalid_count} rows contain invalid JSON.
Original error: #{e.message}
See temporary table invalid_#{table}_rows for details.
ERROR
end
# Simply convert game_raw_jp (empty column)
execute("ALTER TABLE #{table} ALTER COLUMN game_raw_jp TYPE JSONB USING COALESCE(game_raw_jp::JSONB, 'null'::JSONB)")
# Add comment to indicate column purpose
execute("COMMENT ON COLUMN #{table}.game_raw_en IS 'JSON data from game (English)'")
execute("COMMENT ON COLUMN #{table}.game_raw_jp IS 'JSON data from game (Japanese)'")
end
# Leave a note about backup columns in migration output
say 'Migration successful. Backup columns (game_raw_en_backup) remain for verification.'
say 'Run a separate migration to remove backup columns after verification.'
end
def down
tables = %w[characters summons weapons]
tables.each do |table|
# Check if we can restore from backup
if column_exists?(table, :game_raw_en_backup)
say "Restoring #{table}.game_raw_en from backup..."
execute("UPDATE #{table} SET game_raw_en = game_raw_en_backup WHERE game_raw_en_backup IS NOT NULL")
remove_column table, :game_raw_en_backup
end
# Convert both columns back to TEXT
execute("ALTER TABLE #{table} ALTER COLUMN game_raw_en TYPE TEXT")
execute("ALTER TABLE #{table} ALTER COLUMN game_raw_jp TYPE TEXT")
end
end
private
def create_invalid_rows_table(table)
execute(<<~SQL)
CREATE TEMPORARY TABLE invalid_#{table}_rows AS
SELECT id, game_raw_en#{' '}
FROM #{table}
WHERE game_raw_en IS NOT NULL
AND pg_typeof(game_raw_en) = 'text'::regtype
AND (
TRIM(game_raw_en) = ''#{' '}
OR#{' '}
(game_raw_en::JSONB) IS NULL
);
SQL
end
end