module SorbetRails::ModelUtils

Public Instance Methods

add_relation_query_method(root, method_name, parameters: nil, builtin_query_method: false) click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 95
def add_relation_query_method(root, method_name, parameters: nil, builtin_query_method: false)
  # a relation querying method will be available on
  # - model (as a class method)
  # - activerecord relation
  # - asocciation collection proxy
  # - association relation
  # in case (1) and (2), it returns a Model::ActiveRecord_Relation
  # in case (3) and (4), it returns a Model::ActiveRecord_AssociationRelation

  # 'unscoped' is a special case where it always returns a ActiveRecord_Relation
  assoc_return_value = method_name == 'unscoped' ? self.model_relation_class_name : self.model_assoc_relation_class_name

  # We can put methods onto modules which are extended/included by the model
  # and relation classes which reduces the RBI footprint for an individual
  # model. However, in Rails 5 query methods that come from scopes or enums
  # get overridden in hidden-definitions so we need to explicitly define them
  # on the model and relation classes.
  if builtin_query_method
    relation_module_rbi = root.create_module(self.model_query_methods_returning_relation_module_name)
    relation_module_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
    )

    assoc_relation_module_rbi = root.create_module(self.model_query_methods_returning_assoc_relation_module_name)
    assoc_relation_module_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )
  else
    # force generating these methods because sorbet's hidden-definitions generate & override them
    model_class_rbi = root.create_class(self.model_class_name)
    model_class_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
      class_method: true,
    )

    model_relation_rbi = root.create_class(self.model_relation_class_name)
    model_relation_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: self.model_relation_class_name,
    )

    model_assoc_relation_rbi = root.create_class(self.model_assoc_relation_class_name)
    model_assoc_relation_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )

    collection_proxy_rbi = root.create_class(self.model_assoc_proxy_class_name)
    collection_proxy_rbi.create_method(
      method_name,
      parameters: parameters,
      return_type: assoc_return_value,
    )
  end
end
exists_class_method?(method_name) click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 80
def exists_class_method?(method_name)
  model_class.respond_to?(method_name)
end
exists_instance_method?(method_name) click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 75
def exists_instance_method?(method_name)
  model_class.method_defined?(method_name)
end
habtm_class?() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 17
def habtm_class?
  # checking the class name seems to be the cleanest way to figure this out, see:
  # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb#L54
  T.must(model_class.name).start_with?('HABTM_')
end
model_assoc_proxy_class_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 34
def model_assoc_proxy_class_name
  "#{model_class_name}::ActiveRecord_Associations_CollectionProxy"
end
model_assoc_relation_class_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 39
def model_assoc_relation_class_name
  "#{model_class_name}::ActiveRecord_AssociationRelation"
end
model_class_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 24
def model_class_name
  model_class.to_s
end
model_module_name(module_name) click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 70
def model_module_name(module_name)
  "#{model_class_name}::#{module_name}"
end
model_query_methods_returning_assoc_relation_module_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 49
def model_query_methods_returning_assoc_relation_module_name
  "#{model_class_name}::QueryMethodsReturningAssociationRelation"
end
model_query_methods_returning_relation_module_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 44
def model_query_methods_returning_relation_module_name
  "#{model_class_name}::QueryMethodsReturningRelation"
end
model_relation_class_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 29
def model_relation_class_name
  "#{model_class_name}::ActiveRecord_Relation"
end
model_relation_type_alias() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 54
def model_relation_type_alias
  types = [
    self.model_relation_class_name,
    self.model_assoc_proxy_class_name,
    self.model_assoc_relation_class_name
  ].join(', ')

  "T.any(#{types})"
end
model_relation_type_class_name() click to toggle source
# File lib/sorbet-rails/model_utils.rb, line 65
def model_relation_type_class_name
  'RelationType'
end