Skip to content

Commit 88ec15b

Browse files
authored
Merge pull request rails#42773 from Shopify/static-typemaps
Define adapter type maps statically when possible
2 parents 75d6ea3 + d79fb96 commit 88ec15b

File tree

7 files changed

+229
-190
lines changed

7 files changed

+229
-190
lines changed

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 57 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -632,78 +632,76 @@ def database_version # :nodoc:
632632
def check_version # :nodoc:
633633
end
634634

635-
private
636-
def type_map
637-
@type_map ||= Type::TypeMap.new.tap do |mapping|
638-
initialize_type_map(mapping)
635+
class << self
636+
private
637+
def initialize_type_map(m)
638+
register_class_with_limit m, %r(boolean)i, Type::Boolean
639+
register_class_with_limit m, %r(char)i, Type::String
640+
register_class_with_limit m, %r(binary)i, Type::Binary
641+
register_class_with_limit m, %r(text)i, Type::Text
642+
register_class_with_precision m, %r(date)i, Type::Date
643+
register_class_with_precision m, %r(time)i, Type::Time
644+
register_class_with_precision m, %r(datetime)i, Type::DateTime
645+
register_class_with_limit m, %r(float)i, Type::Float
646+
register_class_with_limit m, %r(int)i, Type::Integer
647+
648+
m.alias_type %r(blob)i, "binary"
649+
m.alias_type %r(clob)i, "text"
650+
m.alias_type %r(timestamp)i, "datetime"
651+
m.alias_type %r(numeric)i, "decimal"
652+
m.alias_type %r(number)i, "decimal"
653+
m.alias_type %r(double)i, "float"
654+
655+
m.register_type %r(^json)i, Type::Json.new
656+
657+
m.register_type(%r(decimal)i) do |sql_type|
658+
scale = extract_scale(sql_type)
659+
precision = extract_precision(sql_type)
660+
661+
if scale == 0
662+
# FIXME: Remove this class as well
663+
Type::DecimalWithoutScale.new(precision: precision)
664+
else
665+
Type::Decimal.new(precision: precision, scale: scale)
666+
end
667+
end
639668
end
640-
end
641669

642-
def initialize_type_map(m = type_map)
643-
register_class_with_limit m, %r(boolean)i, Type::Boolean
644-
register_class_with_limit m, %r(char)i, Type::String
645-
register_class_with_limit m, %r(binary)i, Type::Binary
646-
register_class_with_limit m, %r(text)i, Type::Text
647-
register_class_with_precision m, %r(date)i, Type::Date
648-
register_class_with_precision m, %r(time)i, Type::Time
649-
register_class_with_precision m, %r(datetime)i, Type::DateTime
650-
register_class_with_limit m, %r(float)i, Type::Float
651-
register_class_with_limit m, %r(int)i, Type::Integer
652-
653-
m.alias_type %r(blob)i, "binary"
654-
m.alias_type %r(clob)i, "text"
655-
m.alias_type %r(timestamp)i, "datetime"
656-
m.alias_type %r(numeric)i, "decimal"
657-
m.alias_type %r(number)i, "decimal"
658-
m.alias_type %r(double)i, "float"
659-
660-
m.register_type %r(^json)i, Type::Json.new
661-
662-
m.register_type(%r(decimal)i) do |sql_type|
663-
scale = extract_scale(sql_type)
664-
precision = extract_precision(sql_type)
665-
666-
if scale == 0
667-
# FIXME: Remove this class as well
668-
Type::DecimalWithoutScale.new(precision: precision)
669-
else
670-
Type::Decimal.new(precision: precision, scale: scale)
670+
def register_class_with_limit(mapping, key, klass)
671+
mapping.register_type(key) do |*args|
672+
limit = extract_limit(args.last)
673+
klass.new(limit: limit)
671674
end
672675
end
673-
end
674676

675-
def reload_type_map
676-
type_map.clear
677-
initialize_type_map
678-
end
677+
def register_class_with_precision(mapping, key, klass)
678+
mapping.register_type(key) do |*args|
679+
precision = extract_precision(args.last)
680+
klass.new(precision: precision)
681+
end
682+
end
679683

680-
def register_class_with_limit(mapping, key, klass)
681-
mapping.register_type(key) do |*args|
682-
limit = extract_limit(args.last)
683-
klass.new(limit: limit)
684+
def extract_scale(sql_type)
685+
case sql_type
686+
when /\((\d+)\)/ then 0
687+
when /\((\d+)(,(\d+))\)/ then $3.to_i
688+
end
684689
end
685-
end
686690

687-
def register_class_with_precision(mapping, key, klass)
688-
mapping.register_type(key) do |*args|
689-
precision = extract_precision(args.last)
690-
klass.new(precision: precision)
691+
def extract_precision(sql_type)
692+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
691693
end
692-
end
693694

694-
def extract_scale(sql_type)
695-
case sql_type
696-
when /\((\d+)\)/ then 0
697-
when /\((\d+)(,(\d+))\)/ then $3.to_i
695+
def extract_limit(sql_type)
696+
$1.to_i if sql_type =~ /\((.*)\)/
698697
end
699-
end
698+
end
700699

701-
def extract_precision(sql_type)
702-
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
703-
end
700+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
704701

705-
def extract_limit(sql_type)
706-
$1.to_i if sql_type =~ /\((.*)\)/
702+
private
703+
def type_map
704+
TYPE_MAP
707705
end
708706

709707
def translate_exception_class(e, sql, binds)

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,6 @@ def disable_referential_integrity #:nodoc:
185185
end
186186
end
187187

188-
# CONNECTION MANAGEMENT ====================================
189-
190-
def clear_cache! # :nodoc:
191-
reload_type_map
192-
super
193-
end
194-
195188
#--
196189
# DATABASE STATEMENTS ======================================
197190
#++
@@ -568,56 +561,67 @@ def check_version # :nodoc:
568561
end
569562
end
570563

571-
private
572-
def initialize_type_map(m = type_map)
573-
super
564+
class << self
565+
private
566+
def initialize_type_map(m)
567+
super
568+
569+
m.register_type(%r(char)i) do |sql_type|
570+
limit = extract_limit(sql_type)
571+
Type.lookup(:string, adapter: :mysql2, limit: limit)
572+
end
574573

575-
m.register_type(%r(char)i) do |sql_type|
576-
limit = extract_limit(sql_type)
577-
Type.lookup(:string, adapter: :mysql2, limit: limit)
574+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
575+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
576+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
577+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
578+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
579+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
580+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
581+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
582+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
583+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
584+
585+
register_integer_type m, %r(^bigint)i, limit: 8
586+
register_integer_type m, %r(^int)i, limit: 4
587+
register_integer_type m, %r(^mediumint)i, limit: 3
588+
register_integer_type m, %r(^smallint)i, limit: 2
589+
register_integer_type m, %r(^tinyint)i, limit: 1
590+
591+
m.alias_type %r(year)i, "integer"
592+
m.alias_type %r(bit)i, "binary"
593+
594+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
595+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
578596
end
579597

580-
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
581-
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
582-
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
583-
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
584-
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
585-
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
586-
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
587-
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
588-
m.register_type %r(^float)i, Type::Float.new(limit: 24)
589-
m.register_type %r(^double)i, Type::Float.new(limit: 53)
590-
591-
register_integer_type m, %r(^bigint)i, limit: 8
592-
register_integer_type m, %r(^int)i, limit: 4
593-
register_integer_type m, %r(^mediumint)i, limit: 3
594-
register_integer_type m, %r(^smallint)i, limit: 2
595-
register_integer_type m, %r(^tinyint)i, limit: 1
596-
597-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
598-
m.alias_type %r(year)i, "integer"
599-
m.alias_type %r(bit)i, "binary"
600-
601-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
602-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
603-
end
598+
def register_integer_type(mapping, key, **options)
599+
mapping.register_type(key) do |sql_type|
600+
if /\bunsigned\b/.match?(sql_type)
601+
Type::UnsignedInteger.new(**options)
602+
else
603+
Type::Integer.new(**options)
604+
end
605+
end
606+
end
604607

605-
def register_integer_type(mapping, key, **options)
606-
mapping.register_type(key) do |sql_type|
607-
if /\bunsigned\b/.match?(sql_type)
608-
Type::UnsignedInteger.new(**options)
608+
def extract_precision(sql_type)
609+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
610+
super || 0
609611
else
610-
Type::Integer.new(**options)
612+
super
611613
end
612614
end
613-
end
615+
end
614616

615-
def extract_precision(sql_type)
616-
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
617-
super || 0
618-
else
619-
super
620-
end
617+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
618+
TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
619+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
620+
end
621+
622+
private
623+
def type_map
624+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
621625
end
622626

623627
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html

0 commit comments

Comments
 (0)