提交 10919bfe 编写于 作者: R Ryuta Kamizono

Refactor `Relation#cache_key` is moved from `CollectionCacheKey#collection_cache_key`

The implementation of `Relation#cache_key` depends on some internal
relation methods (e.g. `apply_join_dependency`, `build_subquery`), but
somehow that implementation exists on the model class
(`collection_cache_key`), it sometimes bothers to me.

This refactors that implementation moves to `Relation#cache_key`, then
we can avoid `send` to call internal methods.
上级 d49761cd
......@@ -55,7 +55,6 @@ module ActiveRecord
autoload :Persistence
autoload :QueryCache
autoload :Querying
autoload :CollectionCacheKey
autoload :ReadonlyAttributes
autoload :RecordInvalid, "active_record/validations"
autoload :Reflection
......
......@@ -288,7 +288,6 @@ class Base
extend Explain
extend Enum
extend Delegation::DelegateCache
extend CollectionCacheKey
extend Aggregations::ClassMethods
include Core
......
# frozen_string_literal: true
module ActiveRecord
module CollectionCacheKey
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
key = "#{collection.model_name.cache_key}/query-#{query_signature}"
if collection.loaded? || collection.distinct_value
size = collection.records.size
if size > 0
timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
end
else
if collection.eager_loading?
collection = collection.send(:apply_join_dependency)
end
column_type = type_for_attribute(timestamp_column)
column = connection.visitor.compile(collection.arel_attribute(timestamp_column))
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
if collection.has_limit_or_offset?
query = collection.select("#{column} AS collection_cache_key_timestamp")
subquery_alias = "subquery_for_cache_key"
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
arel = query.send(:build_subquery, subquery_alias, select_values % subquery_column)
else
query = collection.unscope(:order)
query.select_values = [select_values % column]
arel = query.arel
end
result = connection.select_one(arel, nil)
if result.blank?
size = 0
timestamp = nil
else
size = result["size"]
timestamp = column_type.deserialize(result["timestamp"])
end
end
if timestamp
"#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
else
"#{key}-#{size}"
end
end
end
end
......@@ -152,6 +152,10 @@ def to_param(method_name = nil)
end
end
end
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
collection.compute_cache_key(timestamp_column)
end
end
private
......
......@@ -317,6 +317,51 @@ def cache_key(timestamp_column = :updated_at)
@cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
end
def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
key = "#{klass.model_name.cache_key}/query-#{query_signature}"
if loaded? || distinct_value
size = records.size
if size > 0
timestamp = max_by(&timestamp_column)._read_attribute(timestamp_column)
end
else
collection = eager_loading? ? apply_join_dependency : self
column = connection.visitor.compile(arel_attribute(timestamp_column))
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
if collection.has_limit_or_offset?
query = collection.select("#{column} AS collection_cache_key_timestamp")
subquery_alias = "subquery_for_cache_key"
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
arel = query.build_subquery(subquery_alias, select_values % subquery_column)
else
query = collection.unscope(:order)
query.select_values = [select_values % column]
arel = query.arel
end
result = connection.select_one(arel, nil)
if result
column_type = klass.type_for_attribute(timestamp_column)
timestamp = column_type.deserialize(result["timestamp"])
size = result["size"]
else
timestamp = nil
size = 0
end
end
if timestamp
"#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
else
"#{key}-#{size}"
end
end
# Scope all queries to the current scope.
#
# Comment.where(post_id: 1).scoping do
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册