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