Module: SorbetRails::ModelColumnUtils
- Extended by:
- T::Helpers, T::Sig
- Included in:
- ModelUtils
- Defined in:
- lib/sorbet-rails/model_column_utils.rb
Overview
typed: strict
Defined Under Namespace
Classes: ColumnType
Instance Method Summary collapse
- #active_record_type_to_sorbet_type(klass, time_zone_aware: false) ⇒ Object
- #attribute_has_unconditional_presence_validation?(attribute) ⇒ Boolean
- #model_class ⇒ Object
- #nilable_column?(column_def) ⇒ Boolean
- #time_zone_aware_column?(column_def, cast_type) ⇒ Boolean
- #type_for_column_def(column_def) ⇒ Object
Instance Method Details
#active_record_type_to_sorbet_type(klass, time_zone_aware: false) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 86 def active_record_type_to_sorbet_type(klass, time_zone_aware: false) case klass when ActiveRecord::Type::Boolean "T::Boolean" when ActiveRecord::Type::DateTime, ActiveRecord::Type::Time time_zone_aware ? ActiveSupport::TimeWithZone : Time when ActiveRecord::Type::Date Date when ActiveRecord::Type::Decimal BigDecimal when ActiveRecord::Type::Float Float when ActiveRecord::Type::BigInteger, ActiveRecord::Type::Integer, ActiveRecord::Type::DecimalWithoutScale, ActiveRecord::Type::UnsignedInteger Integer when ActiveRecord::Type::Binary, ActiveRecord::Type::String, ActiveRecord::Type::Text String else # Json type is only supported in Rails 5.2 and above case when Object.const_defined?('ActiveRecord::Type::Json') && klass.is_a?(ActiveRecord::Type::Json) "T.any(T::Array[T.untyped], T::Boolean, Float, T::Hash[T.untyped, T.untyped], Integer, String)" when Object.const_defined?('ActiveRecord::Enum::EnumType') && klass.is_a?(ActiveRecord::Enum::EnumType) String # For Postgres UUIDs, they're represented as Strings when Object.const_defined?('ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid') && klass.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid) String else "T.untyped" end end end |
#attribute_has_unconditional_presence_validation?(attribute) ⇒ Boolean
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 119 def attribute_has_unconditional_presence_validation?(attribute) model_class_srb = model_class model_class_srb < ActiveRecord::Base && model_class_srb.validators_on(attribute).any? do |validator| validator.is_a?(ActiveModel::Validations::PresenceValidator) && !validator..key?(:if) && !validator..key?(:unless) && !validator..key?(:on) end end |
#model_class ⇒ Object
28 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 28 def model_class; end |
#nilable_column?(column_def) ⇒ Boolean
76 77 78 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 76 def nilable_column?(column_def) !!(column_def.null && !attribute_has_unconditional_presence_validation?(column_def.name)) end |
#time_zone_aware_column?(column_def, cast_type) ⇒ Boolean
60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 60 def time_zone_aware_column?(column_def, cast_type) # this private class method returns true if the attribute should be "time # zone aware"; it takes into account various global and model-specific # configuration options as described here: # https://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html # # although it's private, it's better this than trying to reimplement the "is # this attribute tz aware?" logic ourselves model_class.send( :create_time_zone_conversion_attribute?, column_def.name, cast_type ) end |
#type_for_column_def(column_def) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/sorbet-rails/model_column_utils.rb', line 31 def type_for_column_def(column_def) cast_type = ActiveRecord::Base.connection.respond_to?(:lookup_cast_type_from_column) ? ActiveRecord::Base.connection.lookup_cast_type_from_column(column_def) : column_def.cast_type array_type = false if column_def.try(:array?) cast_type = cast_type.subtype if cast_type.try(:subtype) array_type = true end strict_type = active_record_type_to_sorbet_type( cast_type, time_zone_aware: time_zone_aware_column?(column_def, cast_type), ) ColumnType.new( base_type: strict_type, nilable: nilable_column?(column_def), array_type: array_type, ) end |