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 +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +3 -3
- data/README.md +18 -19
- data/lib/ar_cache.rb +27 -1
- data/lib/ar_cache/active_record.rb +3 -0
- data/lib/ar_cache/active_record/associations/association.rb +13 -0
- data/lib/ar_cache/active_record/associations/has_one_through_association.rb +6 -22
- data/lib/ar_cache/active_record/connection_adapters/abstract/database_statements.rb +34 -38
- data/lib/ar_cache/active_record/connection_adapters/abstract/transaction.rb +7 -7
- data/lib/ar_cache/active_record/insert_all.rb +2 -3
- data/lib/ar_cache/active_record/persistence.rb +21 -11
- data/lib/ar_cache/active_record/relation.rb +32 -30
- data/lib/ar_cache/query.rb +12 -1
- data/lib/ar_cache/table.rb +1 -1
- data/lib/ar_cache/version.rb +1 -1
- data/lib/ar_cache/where_clause.rb +3 -4
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09eeda930c7263476f3b09e53747f9ec87ac070e65f18031856cdb05ad57a083'
|
4
|
+
data.tar.gz: 425c321debdcc05d81d4c0815abecb0d9e19fa417bb251265ba6dab420dd03e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
132
|
+
regexp_parser (2.1.1)
|
133
133
|
rexml (3.2.4)
|
134
|
-
rubocop (1.
|
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
|
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]) #
|
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
|
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
|
-
-
|
118
|
-
- `
|
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
|
-
|
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
|
|
@@ -4,33 +4,17 @@ module ArCache
|
|
4
4
|
module ActiveRecord
|
5
5
|
module Associations
|
6
6
|
module HasOneThroughAssociation
|
7
|
-
private def find_target
|
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,
|
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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|
|
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|
|
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 {
|
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|
|
36
|
+
table_names.each { |table_name| update_ar_cache_by_table(table_name) }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
private def
|
40
|
+
private def update_ar_cache(arel_or_sql_string)
|
41
41
|
if arel_or_sql_string.is_a?(String)
|
42
|
-
|
42
|
+
update_ar_cache_by_sql(arel_or_sql_string)
|
43
43
|
else # is Arel::TreeManager
|
44
|
-
|
44
|
+
update_ar_cache_by_arel(arel_or_sql_string)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
private def
|
49
|
-
|
50
|
-
|
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
|
-
|
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
|
56
|
+
private def update_ar_cache_by_sql(sql)
|
66
57
|
sql = sql.downcase
|
67
|
-
|
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
|
71
|
-
ArCache::Table.all.each
|
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
|
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
|
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(
|
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
|
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
|
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.
|
53
|
-
transaction.
|
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.
|
10
|
-
|
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
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
17
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
data/lib/ar_cache/query.rb
CHANGED
@@ -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?
|
data/lib/ar_cache/table.rb
CHANGED
data/lib/ar_cache/version.rb
CHANGED
@@ -66,11 +66,10 @@ module ArCache
|
|
66
66
|
@cache_hash
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
70
|
-
|
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
|
-
|
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.
|
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-
|
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
|