mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 14:03:39 +08:00
5f64fd0a21
Introduce new patterns for direct sql that are safe and fast. MiniSql is not prone to memory bloat that can happen with direct PG usage. It also has an extremely fast materializer and very a convenient API - DB.exec(sql, *params) => runs sql returns row count - DB.query(sql, *params) => runs sql returns usable objects (not a hash) - DB.query_hash(sql, *params) => runs sql returns an array of hashes - DB.query_single(sql, *params) => runs sql and returns a flat one dimensional array - DB.build(sql) => returns a sql builder See more at: https://github.com/discourse/mini_sql
78 lines
2.2 KiB
Ruby
78 lines
2.2 KiB
Ruby
module Migration
|
|
class BaseDropper
|
|
def initialize(after_migration, delay, on_drop)
|
|
@after_migration = after_migration
|
|
@on_drop = on_drop
|
|
|
|
# in production we need some extra delay to allow for slow migrations
|
|
@delay = delay || (Rails.env.production? ? 3600 : 0)
|
|
end
|
|
|
|
def delayed_drop
|
|
if droppable?
|
|
@on_drop&.call
|
|
execute_drop!
|
|
|
|
Discourse.reset_active_record_cache
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def droppable?
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def execute_drop!
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def previous_migration_done
|
|
<<~SQL
|
|
EXISTS(
|
|
SELECT 1
|
|
FROM schema_migration_details
|
|
WHERE name = :after_migration AND
|
|
(created_at <= (current_timestamp AT TIME ZONE 'UTC' - INTERVAL :delay) OR
|
|
(SELECT created_at
|
|
FROM schema_migration_details
|
|
ORDER BY id ASC
|
|
LIMIT 1) > (current_timestamp AT TIME ZONE 'UTC' - INTERVAL '10 minutes')
|
|
)
|
|
)
|
|
SQL
|
|
end
|
|
|
|
def self.create_readonly_function(table_name, column_name = nil)
|
|
message = column_name ?
|
|
"Discourse: #{column_name} in #{table_name} is readonly" :
|
|
"Discourse: #{table_name} is read only"
|
|
|
|
DB.exec <<~SQL
|
|
CREATE OR REPLACE FUNCTION #{readonly_function_name(table_name, column_name)} RETURNS trigger AS $rcr$
|
|
BEGIN
|
|
RAISE EXCEPTION '#{message}';
|
|
END
|
|
$rcr$ LANGUAGE plpgsql;
|
|
SQL
|
|
end
|
|
private_class_method :create_readonly_function
|
|
|
|
def self.validate_table_name(table_name)
|
|
raise ArgumentError.new("Invalid table name passed: #{table_name}") if table_name =~ /[^a-z0-9_]/i
|
|
end
|
|
|
|
def self.validate_column_name(column_name)
|
|
raise ArgumentError.new("Invalid column name passed to drop #{column_name}") if column_name =~ /[^a-z0-9_]/i
|
|
end
|
|
|
|
def self.readonly_function_name(table_name, column_name = nil)
|
|
["raise", table_name, column_name, "readonly()"].compact.join("_")
|
|
end
|
|
|
|
def self.readonly_trigger_name(table_name, column_name = nil)
|
|
[table_name, column_name, "readonly"].compact.join("_")
|
|
end
|
|
end
|
|
end
|