lib/tapioca/compilers/dsl/identity_cache.rb in tapioca-0.4.27 vs lib/tapioca/compilers/dsl/identity_cache.rb in tapioca-0.5.0

- old
+ new

@@ -1,10 +1,8 @@ # typed: strict # frozen_string_literal: true -require "parlour" - begin require "rails/railtie" require "identity_cache" rescue LoadError # means IdentityCache is not installed, @@ -65,27 +63,20 @@ class IdentityCache < Base extend T::Sig COLLECTION_TYPE = T.let( ->(type) { "T::Array[::#{type}]" }, - T.proc.params(type: Module).returns(String) + T.proc.params(type: T.any(Module, String)).returns(String) ) - sig do - override - .params( - root: Parlour::RbiGenerator::Namespace, - constant: T.class_of(::ActiveRecord::Base) - ) - .void - end + sig { override.params(root: RBI::Tree, constant: T.class_of(::ActiveRecord::Base)).void } def decorate(root, constant) caches = constant.send(:all_cached_associations) cache_indexes = constant.send(:cache_indexes) return if caches.empty? && cache_indexes.empty? - root.path(constant) do |model| + root.create_path(constant) do |model| cache_manys = constant.send(:cached_has_manys) cache_ones = constant.send(:cached_has_ones) cache_belongs = constant.send(:cached_belongs_tos) cache_indexes.each do |field| @@ -106,23 +97,22 @@ end end sig { override.returns(T::Enumerable[Module]) } def gather_constants - ::ActiveRecord::Base.descendants.select do |klass| + descendants_of(::ActiveRecord::Base).select do |klass| klass < ::IdentityCache::WithoutPrimaryIndex end end private sig do params( field: T.untyped, returns_collection: T::Boolean - ) - .returns(String) + ).returns(String) end def type_for_field(field, returns_collection:) cache_type = field.reflection.compute_class(field.reflection.class_name) if returns_collection COLLECTION_TYPE.call(cache_type) @@ -134,14 +124,13 @@ end sig do params( field: T.untyped, - klass: Parlour::RbiGenerator::Namespace, + klass: RBI::Scope, returns_collection: T::Boolean - ) - .void + ).void end def create_fetch_field_methods(field, klass, returns_collection:) name = field.cached_accessor_name.to_s type = type_for_field(field, returns_collection: returns_collection) klass.create_method(name, return_type: type) @@ -154,25 +143,40 @@ end sig do params( field: T.untyped, - klass: Parlour::RbiGenerator::Namespace, + klass: RBI::Scope, constant: T.class_of(::ActiveRecord::Base), - ) - .void + ).void end def create_fetch_by_methods(field, klass, constant) + is_cache_index = field.instance_variable_defined?(:@attribute_proc) + + # Both `cache_index` and `cache_attribute` generate aliased methods + create_aliased_fetch_by_methods(field, klass, constant) + + # If the method used was `cache_index` a few extra methods are created + create_index_fetch_by_methods(field, klass, constant) if is_cache_index + end + + sig do + params( + field: T.untyped, + klass: RBI::Scope, + constant: T.class_of(::ActiveRecord::Base), + ).void + end + def create_index_fetch_by_methods(field, klass, constant) field_length = field.key_fields.length fields_name = field.key_fields.join("_and_") - + name = "fetch_by_#{fields_name}" parameters = field.key_fields.map do |arg| - Parlour::RbiGenerator::Parameter.new(arg.to_s, type: "T.untyped") + create_param(arg.to_s, type: "T.untyped") end - parameters << Parlour::RbiGenerator::Parameter.new("includes:", default: "nil", type: "T.untyped") + parameters << create_kw_opt_param("includes", default: "nil", type: "T.untyped") - name = "fetch_by_#{fields_name}" if field.unique klass.create_method( "#{name}!", class_method: true, parameters: parameters, @@ -193,18 +197,51 @@ return_type: COLLECTION_TYPE.call(constant) ) end if field_length == 1 - name = "fetch_multi_by_#{fields_name}" klass.create_method( - name, + "fetch_multi_by_#{fields_name}", class_method: true, parameters: [ - Parlour::RbiGenerator::Parameter.new("index_values", type: "T.untyped"), - Parlour::RbiGenerator::Parameter.new("includes:", default: "nil", type: "T.untyped"), + create_param("index_values", type: "T::Enumerable[T.untyped]"), + create_kw_opt_param("includes", default: "nil", type: "T.untyped"), ], return_type: COLLECTION_TYPE.call(constant) + ) + end + end + + sig do + params( + field: T.untyped, + klass: RBI::Scope, + constant: T.class_of(::ActiveRecord::Base), + ).void + end + def create_aliased_fetch_by_methods(field, klass, constant) + type, _ = ActiveRecordColumnTypeHelper.new(constant).type_for(field.alias_name.to_s) + multi_type = type.delete_prefix("T.nilable(").delete_suffix(")").delete_prefix("::") + length = field.key_fields.length + suffix = field.send(:fetch_method_suffix) + + parameters = field.key_fields.map do |arg| + create_param(arg.to_s, type: "T.untyped") + end + + klass.create_method( + "fetch_#{suffix}", + class_method: true, + parameters: parameters, + return_type: type + ) + + if length == 1 + klass.create_method( + "fetch_multi_#{suffix}", + class_method: true, + parameters: [create_param("keys", type: "T::Enumerable[T.untyped]")], + return_type: COLLECTION_TYPE.call(multi_type) ) end end end end