246 lines
7.3 KiB
Ruby
246 lines
7.3 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
class CorrectSchemaDiscrepancies < ActiveRecord::Migration[6.0]
|
||
|
disable_ddl_transaction!
|
||
|
|
||
|
def up
|
||
|
timestamp_columns = %w{
|
||
|
category_tag_groups.created_at
|
||
|
category_tag_groups.updated_at
|
||
|
category_tags.created_at
|
||
|
category_tags.updated_at
|
||
|
child_themes.created_at
|
||
|
child_themes.updated_at
|
||
|
embeddable_hosts.created_at
|
||
|
embeddable_hosts.updated_at
|
||
|
group_archived_messages.created_at
|
||
|
group_archived_messages.updated_at
|
||
|
group_mentions.created_at
|
||
|
group_mentions.updated_at
|
||
|
muted_users.created_at
|
||
|
muted_users.updated_at
|
||
|
permalinks.created_at
|
||
|
permalinks.updated_at
|
||
|
post_stats.created_at
|
||
|
post_stats.updated_at
|
||
|
remote_themes.created_at
|
||
|
remote_themes.updated_at
|
||
|
stylesheet_cache.created_at
|
||
|
stylesheet_cache.updated_at
|
||
|
tag_group_memberships.created_at
|
||
|
tag_group_memberships.updated_at
|
||
|
tag_groups.created_at
|
||
|
tag_groups.updated_at
|
||
|
tag_users.created_at
|
||
|
tag_users.updated_at
|
||
|
tags.created_at
|
||
|
tags.updated_at
|
||
|
theme_fields.created_at
|
||
|
theme_fields.updated_at
|
||
|
topic_tags.created_at
|
||
|
topic_tags.updated_at
|
||
|
topic_timers.created_at
|
||
|
topic_timers.updated_at
|
||
|
unsubscribe_keys.created_at
|
||
|
unsubscribe_keys.updated_at
|
||
|
user_api_keys.created_at
|
||
|
user_api_keys.updated_at
|
||
|
user_archived_messages.created_at
|
||
|
user_archived_messages.updated_at
|
||
|
user_auth_tokens.created_at
|
||
|
user_auth_tokens.updated_at
|
||
|
user_emails.created_at
|
||
|
user_emails.updated_at
|
||
|
user_exports.created_at
|
||
|
user_exports.updated_at
|
||
|
user_field_options.created_at
|
||
|
user_field_options.updated_at
|
||
|
user_fields.created_at
|
||
|
user_fields.updated_at
|
||
|
user_warnings.created_at
|
||
|
user_warnings.updated_at
|
||
|
watched_words.created_at
|
||
|
watched_words.updated_at
|
||
|
web_hook_events.created_at
|
||
|
web_hook_events.updated_at
|
||
|
web_hooks.created_at
|
||
|
web_hooks.updated_at
|
||
|
}
|
||
|
|
||
|
char_limit_columns = %w{
|
||
|
badge_groupings.name
|
||
|
badge_types.name
|
||
|
badges.icon
|
||
|
badges.name
|
||
|
categories.email_in
|
||
|
categories.slug
|
||
|
color_scheme_colors.hex
|
||
|
color_scheme_colors.name
|
||
|
color_schemes.name
|
||
|
draft_sequences.draft_key
|
||
|
drafts.draft_key
|
||
|
email_logs.email_type
|
||
|
email_logs.to_address
|
||
|
email_tokens.email
|
||
|
email_tokens.token
|
||
|
embeddable_hosts.host
|
||
|
github_user_infos.screen_name
|
||
|
groups.name
|
||
|
groups.title
|
||
|
invites.email
|
||
|
message_bus.context
|
||
|
message_bus.name
|
||
|
oauth2_user_infos.email
|
||
|
oauth2_user_infos.name
|
||
|
oauth2_user_infos.provider
|
||
|
oauth2_user_infos.uid
|
||
|
optimized_images.url
|
||
|
plugin_store_rows.key
|
||
|
plugin_store_rows.plugin_name
|
||
|
plugin_store_rows.type_name
|
||
|
post_details.key
|
||
|
post_details.value
|
||
|
post_search_data.locale
|
||
|
schema_migrations.version
|
||
|
screened_emails.email
|
||
|
screened_urls.domain
|
||
|
screened_urls.url
|
||
|
single_sign_on_records.external_email
|
||
|
single_sign_on_records.external_id
|
||
|
single_sign_on_records.external_name
|
||
|
single_sign_on_records.external_username
|
||
|
site_settings.name
|
||
|
stylesheet_cache.digest
|
||
|
stylesheet_cache.target
|
||
|
themes.name
|
||
|
topic_links.title
|
||
|
topic_search_data.locale
|
||
|
topics.archetype
|
||
|
topics.slug
|
||
|
topics.subtype
|
||
|
topics.title
|
||
|
uploads.original_filename
|
||
|
uploads.url
|
||
|
user_exports.file_name
|
||
|
user_field_options.value
|
||
|
user_fields.description
|
||
|
user_fields.field_type
|
||
|
user_fields.name
|
||
|
user_histories.context
|
||
|
user_histories.custom_type
|
||
|
user_histories.email
|
||
|
user_histories.ip_address
|
||
|
user_open_ids.email
|
||
|
user_open_ids.url
|
||
|
user_profiles.location
|
||
|
user_profiles.website
|
||
|
users.name
|
||
|
users.title
|
||
|
}
|
||
|
|
||
|
float_default_columns = %w{
|
||
|
top_topics.all_score
|
||
|
top_topics.daily_score
|
||
|
top_topics.monthly_score
|
||
|
top_topics.weekly_score
|
||
|
top_topics.yearly_score
|
||
|
}
|
||
|
|
||
|
other_default_columns = %w{
|
||
|
categories.color
|
||
|
topic_search_data.topic_id
|
||
|
}
|
||
|
|
||
|
lookup_sql = (
|
||
|
timestamp_columns +
|
||
|
char_limit_columns +
|
||
|
float_default_columns +
|
||
|
other_default_columns
|
||
|
).map do |ref|
|
||
|
table, column = ref.split(".")
|
||
|
"(table_name='#{table}' AND column_name='#{column}')"
|
||
|
end.join(" OR ")
|
||
|
|
||
|
raw_info = DB.query_hash <<~SQL
|
||
|
SELECT table_name, column_name, is_nullable, character_maximum_length, column_default
|
||
|
FROM information_schema.columns
|
||
|
WHERE table_schema='public'
|
||
|
AND (
|
||
|
#{lookup_sql}
|
||
|
)
|
||
|
SQL
|
||
|
|
||
|
schema_hash = {}
|
||
|
|
||
|
raw_info.each do |row|
|
||
|
schema_hash["#{row["table_name"]}.#{row["column_name"]}"] = row
|
||
|
end
|
||
|
|
||
|
# In the past, rails changed the default behavior for timestamp columns
|
||
|
# This only affects older discourse installations
|
||
|
# This migration will make old database schemas match modern behavior
|
||
|
timestamp_columns.each do |ref|
|
||
|
current_value = schema_hash[ref]["is_nullable"]
|
||
|
next if current_value == "NO"
|
||
|
|
||
|
table, column = ref.split(".")
|
||
|
|
||
|
# There shouldn't be any null values - rails inserts timestamps automatically
|
||
|
# But just in case, set them to now() if there are any nulls
|
||
|
DB.exec <<~SQL
|
||
|
UPDATE #{table} SET #{column} = now() WHERE #{column} IS NULL
|
||
|
SQL
|
||
|
|
||
|
DB.exec <<~SQL
|
||
|
ALTER TABLE #{table} ALTER COLUMN #{column} SET NOT NULL
|
||
|
SQL
|
||
|
end
|
||
|
|
||
|
# In the past, rails changed the default behavior for varchar columns
|
||
|
# This only affects older discourse installations
|
||
|
# This migration removes the character limits from columns, so that they match modern behavior
|
||
|
char_limit_columns.each do |ref|
|
||
|
current_value = schema_hash[ref]["character_maximum_length"]
|
||
|
next if current_value == nil
|
||
|
table, column = ref.split(".")
|
||
|
|
||
|
DB.exec <<~SQL
|
||
|
ALTER TABLE #{table} ALTER COLUMN #{column} TYPE varchar
|
||
|
SQL
|
||
|
end
|
||
|
|
||
|
# In the past, rails changed the default behavior for float columns
|
||
|
# This only affects older discourse installations
|
||
|
# This migration updates the default values, so that they match modern behavior
|
||
|
float_default_columns.each do |ref|
|
||
|
current_value = schema_hash[ref]["column_default"]
|
||
|
next if current_value == "0.0"
|
||
|
table, column = ref.split(".")
|
||
|
|
||
|
DB.exec <<~SQL
|
||
|
ALTER TABLE #{table} ALTER COLUMN #{column} SET DEFAULT 0.0
|
||
|
SQL
|
||
|
end
|
||
|
|
||
|
# Category color default was changed in https://github.com/discourse/discourse/commit/faf09bb8c80fcb28b132a5a644ac689cc9abffc2
|
||
|
# But should have been added in a new migration
|
||
|
if schema_hash["categories.color"]["column_default"] != "'0088CC'::character varying"
|
||
|
DB.exec <<~SQL
|
||
|
ALTER TABLE categories ALTER COLUMN color SET DEFAULT '0088CC'
|
||
|
SQL
|
||
|
end
|
||
|
|
||
|
# Older sites have a default value like nextval('topic_search_data_topic_id_seq'::regclass)
|
||
|
# Modern sites do not. This is likely caused by another historical change in rails
|
||
|
if schema_hash["topic_search_data.topic_id"]["column_default"] != nil
|
||
|
DB.exec <<~SQL
|
||
|
ALTER TABLE topic_search_data ALTER COLUMN topic_id SET DEFAULT NULL
|
||
|
SQL
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def down
|
||
|
raise ActiveRecord::IrreversibleMigration
|
||
|
end
|
||
|
end
|