13db384648
Patch load_schmema! to set the default value for UUID primary keys. This removes the need to patch ApplicationRecord + Rails models individually. It also means we no longer need to patch the default in for the integer primary key in Search::Record::SQLite.
125 lines
3.3 KiB
Ruby
125 lines
3.3 KiB
Ruby
# Automatically use UUID type for all binary(16) columns and generate defaults
|
|
|
|
module UuidPrimaryKeyDefault
|
|
def load_schema!
|
|
define_uuid_primary_key_pending_default
|
|
super
|
|
end
|
|
|
|
private
|
|
def define_uuid_primary_key_pending_default
|
|
if uuid_primary_key?
|
|
pending_attribute_modifications << PendingUuidDefault.new(primary_key)
|
|
end
|
|
rescue ActiveRecord::StatementInvalid
|
|
# Table doesn't exist yet
|
|
end
|
|
|
|
def uuid_primary_key?
|
|
table_name && primary_key && schema_cache.columns_hash(table_name)[primary_key]&.type == :uuid
|
|
end
|
|
|
|
PendingUuidDefault = Struct.new(:name) do
|
|
def apply_to(attribute_set)
|
|
attribute_set[name] = attribute_set[name].with_user_default(-> { ActiveRecord::Type::Uuid.generate })
|
|
end
|
|
end
|
|
end
|
|
|
|
module MysqlUuidAdapter
|
|
extend ActiveSupport::Concern
|
|
|
|
# Override lookup_cast_type to recognize binary(16) as UUID type
|
|
def lookup_cast_type(sql_type)
|
|
if sql_type == "binary(16)"
|
|
ActiveRecord::Type.lookup(:uuid, adapter: :trilogy)
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
# Override fetch_type_metadata to preserve UUID type and limit
|
|
def fetch_type_metadata(sql_type, extra = "")
|
|
if sql_type == "binary(16)"
|
|
simple_type = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(
|
|
sql_type: sql_type,
|
|
type: :uuid,
|
|
limit: 16
|
|
)
|
|
ActiveRecord::ConnectionAdapters::MySQL::TypeMetadata.new(simple_type, extra: extra)
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
class_methods do
|
|
def native_database_types
|
|
@native_database_types_with_uuid ||= super.merge(uuid: { name: "binary", limit: 16 })
|
|
end
|
|
end
|
|
end
|
|
|
|
module SqliteUuidAdapter
|
|
extend ActiveSupport::Concern
|
|
|
|
# Override lookup_cast_type to recognize BLOB as UUID type
|
|
def lookup_cast_type(sql_type)
|
|
if sql_type == "blob(16)"
|
|
ActiveRecord::Type.lookup(:uuid, adapter: :sqlite3)
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
# Override fetch_type_metadata to preserve UUID type and limit
|
|
def fetch_type_metadata(sql_type)
|
|
if sql_type == "blob(16)"
|
|
ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(
|
|
sql_type: sql_type,
|
|
type: :uuid,
|
|
limit: 16
|
|
)
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
class_methods do
|
|
def native_database_types
|
|
@native_database_types_with_uuid ||= super.merge(uuid: { name: "blob", limit: 16 })
|
|
end
|
|
end
|
|
end
|
|
|
|
module SchemaDumperUuidType
|
|
# Map binary(16) and blob(16) columns to :uuid type in schema.rb
|
|
def schema_type(column)
|
|
if column.sql_type == "binary(16)" || column.sql_type == "blob(16)"
|
|
:uuid
|
|
else
|
|
super
|
|
end
|
|
end
|
|
end
|
|
|
|
module TableDefinitionUuidSupport
|
|
def uuid(name, **options)
|
|
column(name, :uuid, **options)
|
|
end
|
|
end
|
|
|
|
ActiveSupport.on_load(:active_record) do
|
|
ActiveRecord::Base.singleton_class.prepend(UuidPrimaryKeyDefault)
|
|
ActiveRecord::ConnectionAdapters::TableDefinition.prepend(TableDefinitionUuidSupport)
|
|
end
|
|
|
|
ActiveSupport.on_load(:active_record_trilogyadapter) do
|
|
ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.prepend(MysqlUuidAdapter)
|
|
ActiveRecord::ConnectionAdapters::MySQL::SchemaDumper.prepend(SchemaDumperUuidType)
|
|
end
|
|
|
|
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(SqliteUuidAdapter)
|
|
ActiveRecord::ConnectionAdapters::SQLite3::SchemaDumper.prepend(SchemaDumperUuidType)
|
|
end
|