ar_cache 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eab4ff7873091b901a45bfa48e948679d7feda3e0e547201d3f5ab931bbf77e
4
- data.tar.gz: 642654c010e8ced742980a0657480305be9904835a23715d884df3a90d42eef8
3
+ metadata.gz: '09eeda930c7263476f3b09e53747f9ec87ac070e65f18031856cdb05ad57a083'
4
+ data.tar.gz: 425c321debdcc05d81d4c0815abecb0d9e19fa417bb251265ba6dab420dd03e1
5
5
  SHA512:
6
- metadata.gz: a41629683860591506020f8ee516d6d3948ac0daf5381dff1c1b3410fc659be978a4f27d31c0ba49be3fbdf9fd608e7c424a215f5efd75842f5fbe47b31a2d75
7
- data.tar.gz: 71dc11fbccc0816af45df3a1e3e3b3460c595f67fed0376afb9202237367970593441937131e80514d7dfd6bd601d4d2bdc3e3329267c9f6370efb36708291ec
6
+ metadata.gz: 827f0ecdf9e583870a454c16cfaa44c95b9d7b0ba4f3942097daf1c76fed218adfdafcd5733b68fa6476297c8b6d35c728e1a1b6f66db615d9fde834183ea4e8
7
+ data.tar.gz: 273bef3daea68391d681045c384488bf9266a1f75cd5ea7057b6aaf70928ebe97934cb65daadf3f6a3442177d948923116867be503f479c6ac8ab06ac23bb286
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Change log
2
+
3
+ ## main
4
+
5
+ ## 1.0.0 (2021-03-02)
6
+
7
+ - Initial version.
8
+
9
+ ## 1.1.0 (2021-03-11)
10
+
11
+ - Fully automatic delete cache when call delete_all/update_all method.
12
+ - Optimize has_one(through:) cache implementation.
13
+ - ActiveRecord::Relation#reload and ActiveRecord::Associations::Association#reload should skip read cache if associated target is already loaded.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ar_cache (1.0.0)
4
+ ar_cache (1.1.0)
5
5
  activerecord (>= 6.1, < 7)
6
6
 
7
7
  GEM
@@ -129,9 +129,9 @@ GEM
129
129
  thor (~> 1.0)
130
130
  rainbow (3.0.0)
131
131
  rake (13.0.3)
132
- regexp_parser (2.0.3)
132
+ regexp_parser (2.1.1)
133
133
  rexml (3.2.4)
134
- rubocop (1.9.0)
134
+ rubocop (1.11.0)
135
135
  parallel (~> 1.10)
136
136
  parser (>= 3.0.0.0)
137
137
  rainbow (>= 2.2.2, < 4.0)
data/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # ArCache
2
2
 
3
+ ![Test Status](https://github.com/OuYangJinTing/ar_cache/workflows/CI/badge.svg)
4
+ [![Gem Version](https://badge.fury.io/rb/ar_cache.svg)](https://badge.fury.io/rb/ar_cache)
5
+
3
6
  `ArCache` is an modern cacheing library for `ActiveRecord` inspired by cache-money and second_level_cache.
4
- It works automatically by copied `ActiveRecord` related code.
7
+ It works automatically by overridden `ActiveRecord` related CURD code.
5
8
  When executing standard `ActiveRecord` query, it will first query the cache, and if there is none in the cache,
6
9
  then query the database and write the result to the cache.
7
10
 
@@ -82,41 +85,35 @@ For configuration information, please see [configuration](lib/generators/ar_cach
82
85
 
83
86
  If all the following conditions are met, ArCache will try to read the cache:
84
87
 
85
- - Use hash as `#where` parameter.
88
+ - **Use hash as `#where` parameter**.
86
89
  - Query condition contains unique index.
87
90
  - Condition of unique index is only one array or no array.
88
91
  - No call `#select` or select value is table column.
89
92
  - No call `#order` or order value is table column and only one.
90
93
  - No call `#limit` or value of the unique index isn't array.
91
- - No call `#joins`.
92
- - No call `#left_joins`.
93
- - No call `#skip_query_cache!`.
94
- - No call `#skip_ar_cache`.
95
- - No call `#explain`.
96
- - No call `#from`.
97
- - No call `#group`.
98
- - No call `value`.
94
+ - No call `#joins`, `#left_joins`, `#skip_query_cache!`, `#skip_ar_cache`, `#explain`, `#from`, `#group`, `#offset`, `#lock`
99
95
  - ...
100
96
 
101
97
  **Cacheable example:**
102
98
 
103
99
  ```ruby
104
- User.find(1) # primary key cache
105
- User.where(id: [1, 2]) # array query cache
106
- User.where(email: 'foobar@gmail.com') # sigle-column unique index cache
107
- User.where(name: 'foobar', status: :active) # multi-column unique index cache
108
- User.includes(:account).where(id: [1, 2]) # association cache
109
- User.first.account # association model cache
100
+ User.find(1) # support primary key cache
101
+ User.where(id: [1, 2]) # support multi-value unique index cache
102
+ User.where(email: 'foobar@gmail.com') # support sigle-column unique index cache
103
+ User.where(name: 'foobar', status: :active) # support multi-column unique index cache
104
+ User.includes(:account).where(id: [1, 2]) # support association preload cache
105
+ User.first.account # support association reader cach
110
106
  ```
111
107
 
108
+ The association cache support belongs_to and has_one, small amount of complex has_one(scope, through:, as:) don't support, then has_many cache support, please watch to future version.
109
+
112
110
  ## Cache iteration
113
111
 
114
112
  The following cases will cause cache iteration:
115
113
 
116
114
  - Table field changes.
117
- - Open `ArCache` or close `ArCache`.
118
- - `ActiveRecord` update/delete condition does not hit the unique index.
119
- - `ActiveRecord` update/delete join other tables.
115
+ - Turn on `ArCache` or turn off `ArCache`.
116
+ - Call `#upsert_all` method.
120
117
 
121
118
  **Notice: After iteration, all existing caches of the table will be expired!**
122
119
 
@@ -130,6 +127,8 @@ The following cases will cause cache iteration:
130
127
  - Prohibit use `ActiveRecord` other underlying methods to directly update/delete data! (You is a fake activerecord user if this code appears)
131
128
  - Prohibit skip `ActiveRecord` directly update/delete data!
132
129
 
130
+ If you have to do this, please consider turning off ArCache.
131
+
133
132
  ## Alternatives
134
133
 
135
134
  There are some other gems implementations for `ActiveRecord` cache such as:
data/lib/ar_cache.rb CHANGED
@@ -18,5 +18,31 @@ require 'ar_cache/active_record'
18
18
  require_relative './generators/ar_cache/install_generator' if defined?(Rails)
19
19
 
20
20
  module ArCache
21
- singleton_class.delegate :configure, to: Configuration
21
+ PRELOADER = ::ActiveRecord::Associations::Preloader.new
22
+
23
+ class << self
24
+ delegate :configure, to: Configuration
25
+
26
+ def skip_cache?
27
+ Thread.current[:ar_cache_skip_cache]
28
+ end
29
+
30
+ def skip_cache
31
+ Thread.current[:ar_cache_skip_cache] = true
32
+ yield
33
+ ensure
34
+ Thread.current[:ar_cache_skip_cache] = false
35
+ end
36
+
37
+ def pre_expire?
38
+ Thread.current[:ar_cache_pre_expire]
39
+ end
40
+
41
+ def pre_expire
42
+ Thread.current[:ar_cache_pre_expire] = true
43
+ yield
44
+ ensure
45
+ Thread.current[:ar_cache_pre_expire] = false
46
+ end
47
+ end
22
48
  end
@@ -5,6 +5,7 @@ require 'ar_cache/active_record/relation'
5
5
  require 'ar_cache/active_record/core'
6
6
  require 'ar_cache/active_record/persistence'
7
7
  require 'ar_cache/active_record/insert_all'
8
+ require 'ar_cache/active_record/associations/association'
8
9
  require 'ar_cache/active_record/associations/singular_association'
9
10
  require 'ar_cache/active_record/associations/has_one_through_association'
10
11
  require 'ar_cache/active_record/connection_adapters/abstract/transaction'
@@ -18,11 +19,13 @@ ActiveSupport.on_load(:active_record, run_once: true) do
18
19
  ActiveRecord::ModelSchema::ClassMethods.prepend(ArCache::ActiveRecord::ModelSchema::ClassMethods)
19
20
 
20
21
  ActiveRecord::Persistence.prepend(ArCache::ActiveRecord::Persistence)
22
+ ActiveRecord::Persistence::ClassMethods.prepend(ArCache::ActiveRecord::Persistence::ClassMethods)
21
23
 
22
24
  ActiveRecord::InsertAll.prepend(ArCache::ActiveRecord::InsertAll)
23
25
 
24
26
  ActiveRecord::Relation.prepend(ArCache::ActiveRecord::Relation)
25
27
 
28
+ ActiveRecord::Associations::Association.prepend(ArCache::ActiveRecord::Associations::Association)
26
29
  ActiveRecord::Associations::SingularAssociation.prepend(ArCache::ActiveRecord::Associations::SingularAssociation)
27
30
  ActiveRecord::Associations::HasOneThroughAssociation.prepend(ArCache::ActiveRecord::Associations::HasOneThroughAssociation)
28
31
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArCache
4
+ module ActiveRecord
5
+ module Associations
6
+ module Association
7
+ def reload(...)
8
+ loaded? ? ArCache.skip_cache { super } : super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -4,33 +4,17 @@ module ArCache
4
4
  module ActiveRecord
5
5
  module Associations
6
6
  module HasOneThroughAssociation
7
- private def find_target # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
7
+ private def find_target
8
8
  return super if reflection.klass.ar_cache_table.disabled?
9
9
  return super if reflection.through_reflection.klass.ar_cache_table.disabled?
10
10
 
11
- if owner.strict_loading? && owner.validation_context.nil?
12
- Base.strict_loading_violation!(owner: owner.class, association: reflection.klass)
11
+ if (owner.strict_loading? || reflection.strict_loading?) && owner.validation_context.nil?
12
+ Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
13
13
  end
14
14
 
15
- if reflection.strict_loading? && owner.validation_context.nil?
16
- Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
17
- end
18
-
19
- # TODO: Should not instantiate AR
20
- through_record = if reflection.scope
21
- owner.association(reflection.through_reflection.name).scope.merge(reflection.scope).first
22
- else
23
- owner.send(reflection.through_reflection.name)
24
- end
25
- return super if through_record.is_a?(::ActiveRecord::Associations::CollectionProxy)
26
- return nil if !through_record || through_record.destroyed?
27
-
28
- record = through_record.send(reflection.source_reflection.name)
29
- record = record.first if record.is_a?(::ActiveRecord::Associations::CollectionProxy)
30
- return nil unless record
31
-
32
- record.tap { |r| set_inverse_instance(r) }
33
- rescue StandardError # If scope depend on other table, will raise exception
15
+ ArCache::PRELOADER.preload(owner, reflection.name)
16
+ owner.send(reflection.name)
17
+ rescue StandardError
34
18
  super
35
19
  end
36
20
  end
@@ -4,71 +4,67 @@ module ArCache
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  module DatabaseStatements
7
- def insert(arel, ...)
8
- super.tap do
9
- if arel.is_a?(String)
10
- sql = arel.downcase
11
- ArCache::Table.all.each do |table|
12
- current_transaction.add_changed_table(table.name) if sql.include?(table.name)
13
- end
14
- else # is Arel::InsertManager
15
- klass = arel.ast.relation.instance_variable_get(:@klass)
16
- current_transaction.add_changed_table(klass.table_name)
17
- end
18
- end
19
- end
20
- alias create insert
7
+ # def insert(arel, ...)
8
+ # super.tap do
9
+ # if arel.is_a?(String)
10
+ # sql = arel.downcase
11
+ # ArCache::Table.all.each do |table|
12
+ # current_transaction.add_changed_table(table.name) if sql.include?(table.name)
13
+ # end
14
+ # else # is Arel::InsertManager
15
+ # klass = arel.ast.relation.instance_variable_get(:@klass)
16
+ # current_transaction.add_changed_table(klass.table_name)
17
+ # end
18
+ # end
19
+ # end
20
+ # alias create insert
21
21
 
22
22
  def update(arel, ...)
23
- super.tap { |num| update_ar_cache_version(arel) unless num.zero? }
23
+ super.tap { |num| update_ar_cache(arel) unless num.zero? }
24
24
  end
25
25
 
26
26
  def delete(arel, ...)
27
- super.tap { |num| update_ar_cache_version(arel) unless num.zero? }
27
+ super.tap { |num| update_ar_cache(arel) unless num.zero? }
28
28
  end
29
29
 
30
30
  def truncate(table_name, ...)
31
- super.tap { update_ar_cache_version_by_table(table_name) }
31
+ super.tap { update_ar_cache_by_table(table_name) }
32
32
  end
33
33
 
34
34
  def truncate_tables(*table_names)
35
35
  super.tap do
36
- table_names.each { |table_name| update_ar_cache_version_by_table(table_name) }
36
+ table_names.each { |table_name| update_ar_cache_by_table(table_name) }
37
37
  end
38
38
  end
39
39
 
40
- private def update_ar_cache_version(arel_or_sql_string)
40
+ private def update_ar_cache(arel_or_sql_string)
41
41
  if arel_or_sql_string.is_a?(String)
42
- update_ar_cache_version_by_sql(arel_or_sql_string)
42
+ update_ar_cache_by_sql(arel_or_sql_string)
43
43
  else # is Arel::TreeManager
44
- update_ar_cache_version_by_arel(arel_or_sql_string)
44
+ update_ar_cache_by_arel(arel_or_sql_string)
45
45
  end
46
46
  end
47
47
 
48
- private def update_ar_cache_version_by_arel(arel)
49
- # arel.ast.relation may be of the following types:
50
- # - Arel::Nodes::JoinSource
51
- # - Arel::Table
48
+ private def update_ar_cache_by_arel(arel)
49
+ return if ArCache.pre_expire?
50
+
52
51
  arel_table = arel.ast.relation.is_a?(Arel::Table) ? arel.ast.relation : arel.ast.relation.left
53
52
  klass = arel_table.instance_variable_get(:@klass)
54
- return if klass.ar_cache_table.disabled?
55
-
56
- where_clause = ArCache::WhereClause.new(klass, arel.ast.wheres)
57
- if where_clause.cacheable?
58
- current_transaction.add_changed_table(klass.table_name)
59
- current_transaction.add_ar_cache_keys(where_clause.cache_keys)
60
- else
61
- current_transaction.add_ar_cache_table(klass.ar_cache_table)
62
- end
53
+ current_transaction.update_ar_cache_table(klass.ar_cache_table) if klass.ar_cache_table.enabled?
63
54
  end
64
55
 
65
- private def update_ar_cache_version_by_sql(sql)
56
+ private def update_ar_cache_by_sql(sql)
66
57
  sql = sql.downcase
67
- ArCache::Table.all.each { |table| current_transaction.add_ar_cache_table(table) if sql.include?(table.name) }
58
+
59
+ ArCache::Table.all.each do |table|
60
+ current_transaction.update_ar_cache_table(table) if table.enabled? && sql.include?(table.name)
61
+ end
68
62
  end
69
63
 
70
- private def update_ar_cache_version_by_table(table_name)
71
- ArCache::Table.all.each { |table| table.update_version if table_name.casecmp?(table.name) }
64
+ private def update_ar_cache_by_table(table_name)
65
+ ArCache::Table.all.each do |table|
66
+ current_transaction.update_ar_cache_table(table) if table.enabled? && table_name.casecmp?(table.name)
67
+ end
72
68
  end
73
69
  end
74
70
  end
@@ -4,15 +4,15 @@ module ArCache
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  module NullTransaction
7
- def add_ar_cache_keys(keys, delay: false) # rubocop:disable Lint/UnusedMethodArgument
7
+ def delete_ar_cache_keys(keys, delay: false) # rubocop:disable Lint/UnusedMethodArgument
8
8
  ArCache::Store.delete_multi(keys)
9
9
  end
10
10
 
11
- def add_ar_cache_table(table, delay: false) # rubocop:disable Lint/UnusedMethodArgument
11
+ def update_ar_cache_table(table, delay: false) # rubocop:disable Lint/UnusedMethodArgument
12
12
  table.update_version
13
13
  end
14
14
 
15
- def add_changed_table(_); end
15
+ def add_changed_table(...); end
16
16
  end
17
17
 
18
18
  module Transaction
@@ -24,12 +24,12 @@ module ArCache
24
24
  @ar_cache_tables = []
25
25
  end
26
26
 
27
- def add_ar_cache_keys(keys, delay: false)
27
+ def delete_ar_cache_keys(keys, delay: false)
28
28
  super if !delay && read_uncommitted?
29
29
  @ar_cache_keys.push(*keys)
30
30
  end
31
31
 
32
- def add_ar_cache_table(table, delay: false)
32
+ def update_ar_cache_table(table, delay: false)
33
33
  add_changed_table(table.name) unless delay
34
34
 
35
35
  super if !delay && read_uncommitted?
@@ -49,8 +49,8 @@ module ArCache
49
49
  ArCache::Store.delete_multi(@ar_cache_keys.uniq) if @ar_cache_keys.any?
50
50
  else
51
51
  transaction = connection.current_transaction
52
- @ar_cache_tables.each { |table| transaction.add_ar_cache_table(table, delay: true) }
53
- transaction.add_ar_cache_keys(@ar_cache_keys, delay: true)
52
+ @ar_cache_tables.each { |table| transaction.update_ar_cache_table(table, delay: true) }
53
+ transaction.delete_ar_cache_keys(@ar_cache_keys, delay: true)
54
54
  end
55
55
  end
56
56
 
@@ -6,9 +6,8 @@ module ArCache
6
6
  def execute
7
7
  super.tap do
8
8
  if on_duplicate == :update
9
- connection.current_transaction.add_ar_cache_table(model.ar_cache_table)
10
- else
11
- connection.transaction_manager.add_changed_table(model.table_name)
9
+ connection.current_transaction.update_ar_cache_table(model.ar_cache_table)
10
+ connection.current_transaction.add_changed_table(model.table_name)
12
11
  end
13
12
  end
14
13
  end
@@ -3,20 +3,30 @@
3
3
  module ArCache
4
4
  module ActiveRecord
5
5
  module Persistence
6
- def reload(options = nil)
7
- self.class.connection.clear_query_cache
6
+ module ClassMethods
7
+ def _update_record(_, constraints)
8
+ ArCache.pre_expire do
9
+ delete_ar_cache_key(constraints[@primary_key])
10
+ super
11
+ end
12
+ end
8
13
 
9
- fresh_object =
10
- if options && options[:lock]
11
- self.class.unscoped { self.class.skip_ar_cache.lock(options[:lock]).find(id) }
12
- else
13
- self.class.unscoped { self.class.skip_ar_cache.find(id) }
14
+ def _delete_record(constraints)
15
+ ArCache.pre_expire do
16
+ delete_ar_cache_key(constraints[@primary_key])
17
+ super
14
18
  end
19
+ end
20
+
21
+ private def delete_ar_cache_key(id)
22
+ key = ar_cache_table.primary_cache_key(id)
23
+ connection.current_transaction.delete_ar_cache_keys([key])
24
+ connection.current_transaction.add_changed_table(table_name)
25
+ end
26
+ end
15
27
 
16
- @attributes = fresh_object.instance_variable_get(:@attributes)
17
- @new_record = false
18
- @previously_new_record = false
19
- self
28
+ def reload(...)
29
+ ArCache.skip_cache { super }
20
30
  end
21
31
  end
22
32
  end
@@ -3,6 +3,11 @@
3
3
  module ArCache
4
4
  module ActiveRecord
5
5
  module Relation
6
+ def reload
7
+ @skip_ar_cache = true if loaded?
8
+ super
9
+ end
10
+
6
11
  def skip_ar_cache
7
12
  tap { @skip_ar_cache = true }
8
13
  end
@@ -12,36 +17,33 @@ module ArCache
12
17
  super
13
18
  end
14
19
 
15
- private def exec_queries(&block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
16
- skip_query_cache_if_necessary do
17
- records =
18
- if where_clause.contradiction?
19
- []
20
- elsif eager_loading?
21
- apply_join_dependency do |relation, join_dependency|
22
- if relation.null_relation?
23
- []
24
- else
25
- relation = join_dependency.apply_column_aliases(relation)
26
- rows = connection.select_all(relation.arel, 'SQL')
27
- join_dependency.instantiate(rows, strict_loading_value, &block)
28
- end.freeze
29
- end
30
- elsif @skip_ar_cache ||
31
- klass.ar_cache_table.disabled? ||
32
- connection.transaction_manager.changed_table?(table_name)
33
- klass.find_by_sql(arel, &block).freeze
34
- else
35
- ArCache::Query.new(self).exec_queries(&block).freeze
36
- end
37
-
38
- preload_associations(records) unless skip_preloading_value
39
-
40
- records.each(&:readonly!) if readonly_value
41
- records.each(&:strict_loading!) if strict_loading_value
42
-
43
- records
44
- end
20
+ def update_all(...)
21
+ ArCache.pre_expire { delete_ar_cache_keys ? super : 0 }
22
+ end
23
+
24
+ def delete_all
25
+ ArCache.pre_expire { delete_ar_cache_keys ? super : 0 }
26
+ end
27
+
28
+ private def delete_ar_cache_keys
29
+ return true if klass.ar_cache_table.disabled?
30
+
31
+ where_clause = ArCache::WhereClause.new(klass, arel.constraints)
32
+ keys = if where_clause.cacheable? && where_clause.primary_key_index?
33
+ where_clause.primary_cache_keys
34
+ else
35
+ pluck(primary_key).map { |item| klass.ar_cache_table.primary_cache_key(item) }
36
+ end
37
+
38
+ return false if keys.empty?
39
+
40
+ @klass.connection.current_transaction.delete_ar_cache_keys(keys)
41
+ @klass.connection.current_transaction.add_changed_table(@klass.table_name)
42
+ true
43
+ end
44
+
45
+ private def exec_queries(&block)
46
+ @skip_ar_cache ? super : ArCache::Query.new(self).exec_queries(&block).freeze
45
47
  end
46
48
  end
47
49
  end
@@ -10,7 +10,8 @@ module ArCache
10
10
  @where_clause = ArCache::WhereClause.new(@relation.klass, @relation.where_clause.send(:predicates))
11
11
  end
12
12
 
13
- def exec_queries(&block)
13
+ def exec_queries(&block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
14
+ return [] if relation.where_clause.contradiction?
14
15
  return relation.skip_ar_cache.send(:exec_queries, &block) unless exec_queries_cacheable?
15
16
 
16
17
  records = table.read(where_clause, @select_values, &block)
@@ -29,15 +30,25 @@ module ArCache
29
30
  end
30
31
 
31
32
  records_order(records)
33
+
34
+ relation.preload_associations(records) unless relation.skip_preloading_value
35
+
36
+ records.each(&:readonly!) if relation.readonly_value
37
+ records.each(&:strict_loading!) if relation.strict_loading_value
38
+
39
+ records
32
40
  end
33
41
 
34
42
  private def exec_queries_cacheable? # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
43
+ return false if relation.klass.ar_cache_table.disabled?
35
44
  return false if relation.skip_query_cache_value
36
45
  return false if relation.lock_value
37
46
  return false if relation.group_values.any?
38
47
  return false if relation.joins_values.any?
39
48
  return false if relation.left_outer_joins_values.any?
40
49
  return false if relation.offset_value
50
+ return false if relation.eager_loading?
51
+ return false if relation.connection.transaction_manager.changed_table?(table.name)
41
52
  return false unless relation.from_clause.empty?
42
53
  return false unless where_clause.cacheable?
43
54
  return false unless select_values_cacheable?
@@ -43,7 +43,7 @@ module ArCache
43
43
  end
44
44
 
45
45
  def disabled?
46
- @disabled
46
+ @disabled || ArCache.skip_cache?
47
47
  end
48
48
 
49
49
  def enabled?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArCache
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -66,11 +66,10 @@ module ArCache
66
66
  @cache_hash
67
67
  end
68
68
 
69
- def cache_keys
70
- keys = cache_hash.keys
71
- keys += cache_hash.values unless primary_key_index?
69
+ def primary_cache_keys
70
+ raise 'Does not detect primary key index' unless primary_key_index?
72
71
 
73
- keys
72
+ @primary_cache_keys ||= Array(where_values_hash[table.primary_key]).map { |v| table.primary_cache_key(v) }
74
73
  end
75
74
 
76
75
  def missed_hash
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OuYangJinTing
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-02 00:00:00.000000000 Z
11
+ date: 2021-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -41,6 +41,7 @@ files:
41
41
  - ".github/workflows/main.yml"
42
42
  - ".gitignore"
43
43
  - ".rubocop.yml"
44
+ - CHANGELOG.md
44
45
  - CODE_OF_CONDUCT.md
45
46
  - Gemfile
46
47
  - Gemfile.common
@@ -56,6 +57,7 @@ files:
56
57
  - gemfiles/rails-edge
57
58
  - lib/ar_cache.rb
58
59
  - lib/ar_cache/active_record.rb
60
+ - lib/ar_cache/active_record/associations/association.rb
59
61
  - lib/ar_cache/active_record/associations/has_one_through_association.rb
60
62
  - lib/ar_cache/active_record/associations/singular_association.rb
61
63
  - lib/ar_cache/active_record/connection_adapters/abstract/database_statements.rb