ar_cache 1.0.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/Gemfile.lock +70 -65
- data/README.md +35 -22
- data/lib/ar_cache.rb +39 -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 +11 -23
- data/lib/ar_cache/active_record/associations/singular_association.rb +2 -4
- 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/core.rb +2 -4
- data/lib/ar_cache/active_record/insert_all.rb +2 -3
- data/lib/ar_cache/active_record/model_schema.rb +1 -1
- data/lib/ar_cache/active_record/persistence.rb +21 -11
- data/lib/ar_cache/active_record/relation.rb +30 -34
- data/lib/ar_cache/configuration.rb +2 -3
- data/lib/ar_cache/marshal.rb +2 -2
- data/lib/ar_cache/mock_table.rb +0 -8
- data/lib/ar_cache/query.rb +19 -7
- data/lib/ar_cache/record.rb +0 -2
- data/lib/ar_cache/table.rb +9 -18
- data/lib/ar_cache/version.rb +1 -1
- data/lib/ar_cache/where_clause.rb +8 -9
- data/lib/generators/ar_cache/templates/configuration.rb +1 -2
- 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: 86d921c69c8ac7d8cbc0cefdb5614120a60f5663c5a2b8e3bc07a1c9c1d8d8a0
|
|
4
|
+
data.tar.gz: ced6d5cf673fb6e83070ba95e4daf6fb9d0994a93f8963de63692317c9c77081
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5affbd42eed0837bc8fc40fd317eac39fa79b0e18c8e27f65eefb2873b381064539374dde7b963c1993f66068177707e72421499d7ff81b5fdc394e91261f8c3
|
|
7
|
+
data.tar.gz: 1c7f9930f0a726201afa735d208c229c01693432adc1631ea5bcd6417210ad079587c18ac9e908890e4ae4fac2307361048f017a28308c92c22d9136dd36e5ce
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Change log
|
|
2
|
+
|
|
3
|
+
## main
|
|
4
|
+
|
|
5
|
+
## 1.5.0 (2021-03-22 UTC)
|
|
6
|
+
|
|
7
|
+
[Compare [#7cc9ec8..10f9eea](https://github.com/OuYangJinTing/ar_cache/compare/7cc9ec8..10f9eea)]:
|
|
8
|
+
|
|
9
|
+
- Fix `has_one thtough:` strict loading error.
|
|
10
|
+
- Fix `#detect_wrong_key`, should check `nil` value match.
|
|
11
|
+
- Rename `ArCache::Configuration#index_column_max_size` => `ArCache::Configuration#column_length`
|
|
12
|
+
|
|
13
|
+
## 1.4.0 (2021-03-15 UTC)
|
|
14
|
+
|
|
15
|
+
[Compare [#3ff0bb8..7cc9ec8](https://github.com/OuYangJinTing/ar_cache/compare/3ff0bb8..7cc9ec8)]:
|
|
16
|
+
|
|
17
|
+
- Remove `ArCache::Table` `ignored_columns` configuration.
|
|
18
|
+
- Fix `ActiveRecord` call `#select` write to cache data is incomplete.
|
|
19
|
+
|
|
20
|
+
## 1.3.0 (2021-03-13 UTC)
|
|
21
|
+
|
|
22
|
+
[Compare [#4328f38..4ec14e9](https://github.com/OuYangJinTing/ar_cache/compare/4328f38..4ec14e9)]:
|
|
23
|
+
|
|
24
|
+
- Optimize association cache, only cacheable association use ArCache query now.
|
|
25
|
+
|
|
26
|
+
## 1.2.0 (2021-03-12 UTC)
|
|
27
|
+
|
|
28
|
+
[Compare [#eb27f99..c830907](https://github.com/OuYangJinTing/ar_cache/compare/eb27f99..c830907)]:
|
|
29
|
+
|
|
30
|
+
- Remove methods: `ArCache::MockTable#enabled?`, `ArCache::MockTable#select_enabled?`, `ArCache::Table.enabled?`, `ArCache::Table.select_enabled?`, `ActiveRecord::Relation#skip_ar_cache`.
|
|
31
|
+
- Rename methods: `ArCache#skip_cache? => ArCache#skip?`, `ArCache#skip_cache => ArCache#skip`, `ArCache#pre_expire? => ArCache#expire?`, `ArCache#pre_expire => ArCache#expire`.
|
|
32
|
+
- Now, `ArCache#skip` method only skip read cache, but still try delete cache.
|
|
33
|
+
|
|
34
|
+
## 1.1.0 (2021-03-10 UTC)
|
|
35
|
+
|
|
36
|
+
[Compare [#a15d5f5..ce5444c](https://github.com/OuYangJinTing/ar_cache/compare/a15d5f5...ce5444c)]:
|
|
37
|
+
|
|
38
|
+
- Fully automatic delete cache when call delete_all/update_all method.
|
|
39
|
+
- Optimize has_one(through:) cache implementation.
|
|
40
|
+
- ActiveRecord::Relation#reload and ActiveRecord::Associations::Association#reload should skip read cache if associated target is already loaded.
|
|
41
|
+
|
|
42
|
+
## 1.0.0 (2021-03-02 UTC)
|
|
43
|
+
|
|
44
|
+
- Initial version.
|
data/Gemfile.lock
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ar_cache (1.
|
|
4
|
+
ar_cache (1.5.0)
|
|
5
5
|
activerecord (>= 6.1, < 7)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
-
actioncable (6.1.
|
|
11
|
-
actionpack (= 6.1.
|
|
12
|
-
activesupport (= 6.1.
|
|
10
|
+
actioncable (6.1.3)
|
|
11
|
+
actionpack (= 6.1.3)
|
|
12
|
+
activesupport (= 6.1.3)
|
|
13
13
|
nio4r (~> 2.0)
|
|
14
14
|
websocket-driver (>= 0.6.1)
|
|
15
|
-
actionmailbox (6.1.
|
|
16
|
-
actionpack (= 6.1.
|
|
17
|
-
activejob (= 6.1.
|
|
18
|
-
activerecord (= 6.1.
|
|
19
|
-
activestorage (= 6.1.
|
|
20
|
-
activesupport (= 6.1.
|
|
15
|
+
actionmailbox (6.1.3)
|
|
16
|
+
actionpack (= 6.1.3)
|
|
17
|
+
activejob (= 6.1.3)
|
|
18
|
+
activerecord (= 6.1.3)
|
|
19
|
+
activestorage (= 6.1.3)
|
|
20
|
+
activesupport (= 6.1.3)
|
|
21
21
|
mail (>= 2.7.1)
|
|
22
|
-
actionmailer (6.1.
|
|
23
|
-
actionpack (= 6.1.
|
|
24
|
-
actionview (= 6.1.
|
|
25
|
-
activejob (= 6.1.
|
|
26
|
-
activesupport (= 6.1.
|
|
22
|
+
actionmailer (6.1.3)
|
|
23
|
+
actionpack (= 6.1.3)
|
|
24
|
+
actionview (= 6.1.3)
|
|
25
|
+
activejob (= 6.1.3)
|
|
26
|
+
activesupport (= 6.1.3)
|
|
27
27
|
mail (~> 2.5, >= 2.5.4)
|
|
28
28
|
rails-dom-testing (~> 2.0)
|
|
29
|
-
actionpack (6.1.
|
|
30
|
-
actionview (= 6.1.
|
|
31
|
-
activesupport (= 6.1.
|
|
29
|
+
actionpack (6.1.3)
|
|
30
|
+
actionview (= 6.1.3)
|
|
31
|
+
activesupport (= 6.1.3)
|
|
32
32
|
rack (~> 2.0, >= 2.0.9)
|
|
33
33
|
rack-test (>= 0.6.3)
|
|
34
34
|
rails-dom-testing (~> 2.0)
|
|
35
35
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
36
|
-
actiontext (6.1.
|
|
37
|
-
actionpack (= 6.1.
|
|
38
|
-
activerecord (= 6.1.
|
|
39
|
-
activestorage (= 6.1.
|
|
40
|
-
activesupport (= 6.1.
|
|
36
|
+
actiontext (6.1.3)
|
|
37
|
+
actionpack (= 6.1.3)
|
|
38
|
+
activerecord (= 6.1.3)
|
|
39
|
+
activestorage (= 6.1.3)
|
|
40
|
+
activesupport (= 6.1.3)
|
|
41
41
|
nokogiri (>= 1.8.5)
|
|
42
|
-
actionview (6.1.
|
|
43
|
-
activesupport (= 6.1.
|
|
42
|
+
actionview (6.1.3)
|
|
43
|
+
activesupport (= 6.1.3)
|
|
44
44
|
builder (~> 3.1)
|
|
45
45
|
erubi (~> 1.4)
|
|
46
46
|
rails-dom-testing (~> 2.0)
|
|
47
47
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
48
|
-
activejob (6.1.
|
|
49
|
-
activesupport (= 6.1.
|
|
48
|
+
activejob (6.1.3)
|
|
49
|
+
activesupport (= 6.1.3)
|
|
50
50
|
globalid (>= 0.3.6)
|
|
51
|
-
activemodel (6.1.
|
|
52
|
-
activesupport (= 6.1.
|
|
53
|
-
activerecord (6.1.
|
|
54
|
-
activemodel (= 6.1.
|
|
55
|
-
activesupport (= 6.1.
|
|
56
|
-
activestorage (6.1.
|
|
57
|
-
actionpack (= 6.1.
|
|
58
|
-
activejob (= 6.1.
|
|
59
|
-
activerecord (= 6.1.
|
|
60
|
-
activesupport (= 6.1.
|
|
51
|
+
activemodel (6.1.3)
|
|
52
|
+
activesupport (= 6.1.3)
|
|
53
|
+
activerecord (6.1.3)
|
|
54
|
+
activemodel (= 6.1.3)
|
|
55
|
+
activesupport (= 6.1.3)
|
|
56
|
+
activestorage (6.1.3)
|
|
57
|
+
actionpack (= 6.1.3)
|
|
58
|
+
activejob (= 6.1.3)
|
|
59
|
+
activerecord (= 6.1.3)
|
|
60
|
+
activesupport (= 6.1.3)
|
|
61
61
|
marcel (~> 0.3.1)
|
|
62
62
|
mimemagic (~> 0.3.2)
|
|
63
|
-
activesupport (6.1.
|
|
63
|
+
activesupport (6.1.3)
|
|
64
64
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
65
65
|
i18n (>= 1.6, < 2)
|
|
66
66
|
minitest (>= 5.1)
|
|
@@ -71,11 +71,16 @@ GEM
|
|
|
71
71
|
coderay (1.1.3)
|
|
72
72
|
concurrent-ruby (1.1.8)
|
|
73
73
|
crass (1.0.6)
|
|
74
|
-
database_cleaner (
|
|
74
|
+
database_cleaner (2.0.1)
|
|
75
|
+
database_cleaner-active_record (~> 2.0.0)
|
|
76
|
+
database_cleaner-active_record (2.0.0)
|
|
77
|
+
activerecord (>= 5.a)
|
|
78
|
+
database_cleaner-core (~> 2.0.0)
|
|
79
|
+
database_cleaner-core (2.0.1)
|
|
75
80
|
erubi (1.10.0)
|
|
76
81
|
globalid (0.4.2)
|
|
77
82
|
activesupport (>= 4.2.0)
|
|
78
|
-
i18n (1.8.
|
|
83
|
+
i18n (1.8.9)
|
|
79
84
|
concurrent-ruby (~> 1.0)
|
|
80
85
|
loofah (2.9.0)
|
|
81
86
|
crass (~> 1.0.2)
|
|
@@ -87,51 +92,51 @@ GEM
|
|
|
87
92
|
method_source (1.0.0)
|
|
88
93
|
mimemagic (0.3.5)
|
|
89
94
|
mini_mime (1.0.2)
|
|
90
|
-
minitest (5.14.
|
|
91
|
-
nio4r (2.5.
|
|
92
|
-
nokogiri (1.11.
|
|
95
|
+
minitest (5.14.4)
|
|
96
|
+
nio4r (2.5.7)
|
|
97
|
+
nokogiri (1.11.2-x86_64-linux)
|
|
93
98
|
racc (~> 1.4)
|
|
94
99
|
parallel (1.20.1)
|
|
95
100
|
parser (3.0.0.0)
|
|
96
101
|
ast (~> 2.4.1)
|
|
97
|
-
pry (0.
|
|
102
|
+
pry (0.14.0)
|
|
98
103
|
coderay (~> 1.1)
|
|
99
104
|
method_source (~> 1.0)
|
|
100
105
|
racc (1.5.2)
|
|
101
106
|
rack (2.2.3)
|
|
102
107
|
rack-test (1.1.0)
|
|
103
108
|
rack (>= 1.0, < 3)
|
|
104
|
-
rails (6.1.
|
|
105
|
-
actioncable (= 6.1.
|
|
106
|
-
actionmailbox (= 6.1.
|
|
107
|
-
actionmailer (= 6.1.
|
|
108
|
-
actionpack (= 6.1.
|
|
109
|
-
actiontext (= 6.1.
|
|
110
|
-
actionview (= 6.1.
|
|
111
|
-
activejob (= 6.1.
|
|
112
|
-
activemodel (= 6.1.
|
|
113
|
-
activerecord (= 6.1.
|
|
114
|
-
activestorage (= 6.1.
|
|
115
|
-
activesupport (= 6.1.
|
|
109
|
+
rails (6.1.3)
|
|
110
|
+
actioncable (= 6.1.3)
|
|
111
|
+
actionmailbox (= 6.1.3)
|
|
112
|
+
actionmailer (= 6.1.3)
|
|
113
|
+
actionpack (= 6.1.3)
|
|
114
|
+
actiontext (= 6.1.3)
|
|
115
|
+
actionview (= 6.1.3)
|
|
116
|
+
activejob (= 6.1.3)
|
|
117
|
+
activemodel (= 6.1.3)
|
|
118
|
+
activerecord (= 6.1.3)
|
|
119
|
+
activestorage (= 6.1.3)
|
|
120
|
+
activesupport (= 6.1.3)
|
|
116
121
|
bundler (>= 1.15.0)
|
|
117
|
-
railties (= 6.1.
|
|
122
|
+
railties (= 6.1.3)
|
|
118
123
|
sprockets-rails (>= 2.0.0)
|
|
119
124
|
rails-dom-testing (2.0.3)
|
|
120
125
|
activesupport (>= 4.2.0)
|
|
121
126
|
nokogiri (>= 1.6)
|
|
122
127
|
rails-html-sanitizer (1.3.0)
|
|
123
128
|
loofah (~> 2.3)
|
|
124
|
-
railties (6.1.
|
|
125
|
-
actionpack (= 6.1.
|
|
126
|
-
activesupport (= 6.1.
|
|
129
|
+
railties (6.1.3)
|
|
130
|
+
actionpack (= 6.1.3)
|
|
131
|
+
activesupport (= 6.1.3)
|
|
127
132
|
method_source
|
|
128
133
|
rake (>= 0.8.7)
|
|
129
134
|
thor (~> 1.0)
|
|
130
135
|
rainbow (3.0.0)
|
|
131
136
|
rake (13.0.3)
|
|
132
|
-
regexp_parser (2.
|
|
137
|
+
regexp_parser (2.1.1)
|
|
133
138
|
rexml (3.2.4)
|
|
134
|
-
rubocop (1.
|
|
139
|
+
rubocop (1.11.0)
|
|
135
140
|
parallel (~> 1.10)
|
|
136
141
|
parser (>= 3.0.0.0)
|
|
137
142
|
rainbow (>= 2.2.2, < 4.0)
|
|
@@ -142,9 +147,9 @@ GEM
|
|
|
142
147
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
143
148
|
rubocop-ast (1.4.1)
|
|
144
149
|
parser (>= 2.7.1.5)
|
|
145
|
-
rubocop-minitest (0.
|
|
146
|
-
rubocop (>= 0.
|
|
147
|
-
rubocop-performance (1.
|
|
150
|
+
rubocop-minitest (0.11.0)
|
|
151
|
+
rubocop (>= 0.90, < 2.0)
|
|
152
|
+
rubocop-performance (1.10.1)
|
|
148
153
|
rubocop (>= 0.90.0, < 2.0)
|
|
149
154
|
rubocop-ast (>= 0.4.0)
|
|
150
155
|
rubocop-rails (2.9.1)
|
data/README.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# ArCache
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
[](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
|
|
|
@@ -52,17 +55,31 @@ rake db:migrate
|
|
|
52
55
|
|
|
53
56
|
Skip cache:
|
|
54
57
|
|
|
58
|
+
- `ArCache#skip`, eg:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
# All queries in the block will not use the cache.
|
|
62
|
+
ArCache.skip { User.find(1) }
|
|
63
|
+
```
|
|
64
|
+
|
|
55
65
|
- `ActiveRecord::Persistence#reload`, eg:
|
|
56
66
|
|
|
57
67
|
```ruby
|
|
58
68
|
User.find(1).reload
|
|
59
69
|
```
|
|
60
70
|
|
|
61
|
-
- `ActiveRecord::Relation#
|
|
71
|
+
- `ActiveRecord::Relation#reload`, eg:
|
|
62
72
|
|
|
63
73
|
```ruby
|
|
64
|
-
|
|
65
|
-
User.where(id:
|
|
74
|
+
# When reload is called after the associated target has been loaded, the cache will be skipped.
|
|
75
|
+
User.where(id: 1).load.reload
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- `ActiveRecord::Associations::Association#reload`, eg:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
# When reload is called after the associated target has been loaded, the cache will be skipped.
|
|
82
|
+
user.association(:account).load_target.reload
|
|
66
83
|
```
|
|
67
84
|
|
|
68
85
|
Delete cache:
|
|
@@ -82,41 +99,35 @@ For configuration information, please see [configuration](lib/generators/ar_cach
|
|
|
82
99
|
|
|
83
100
|
If all the following conditions are met, ArCache will try to read the cache:
|
|
84
101
|
|
|
85
|
-
- Use hash as `#where` parameter
|
|
102
|
+
- **Use hash as `#where` parameter**.
|
|
86
103
|
- Query condition contains unique index.
|
|
87
104
|
- Condition of unique index is only one array or no array.
|
|
88
105
|
- No call `#select` or select value is table column.
|
|
89
106
|
- No call `#order` or order value is table column and only one.
|
|
90
107
|
- 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`.
|
|
108
|
+
- No call `#joins`, `#left_joins`, `#skip_query_cache!`, `#explain`, `#from`, `#group`, `#offset`, `#lock`
|
|
99
109
|
- ...
|
|
100
110
|
|
|
101
111
|
**Cacheable example:**
|
|
102
112
|
|
|
103
113
|
```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
|
|
114
|
+
User.find(1) # support primary key cache
|
|
115
|
+
User.where(id: [1, 2]) # support multi-value unique index cache
|
|
116
|
+
User.where(email: 'foobar@gmail.com') # support sigle-column unique index cache
|
|
117
|
+
User.where(name: 'foobar', status: :active) # support multi-column unique index cache
|
|
118
|
+
User.includes(:account).where(id: [1, 2]) # support association preload cache
|
|
119
|
+
User.first.account # support association reader cach
|
|
110
120
|
```
|
|
111
121
|
|
|
122
|
+
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.
|
|
123
|
+
|
|
112
124
|
## Cache iteration
|
|
113
125
|
|
|
114
126
|
The following cases will cause cache iteration:
|
|
115
127
|
|
|
116
128
|
- Table field changes.
|
|
117
|
-
-
|
|
118
|
-
- `
|
|
119
|
-
- `ActiveRecord` update/delete join other tables.
|
|
129
|
+
- Turn on `ArCache` or turn off `ArCache`.
|
|
130
|
+
- Call `#upsert_all` method.
|
|
120
131
|
|
|
121
132
|
**Notice: After iteration, all existing caches of the table will be expired!**
|
|
122
133
|
|
|
@@ -130,6 +141,8 @@ The following cases will cause cache iteration:
|
|
|
130
141
|
- Prohibit use `ActiveRecord` other underlying methods to directly update/delete data! (You is a fake activerecord user if this code appears)
|
|
131
142
|
- Prohibit skip `ActiveRecord` directly update/delete data!
|
|
132
143
|
|
|
144
|
+
If you have to do this, please consider turning off ArCache.
|
|
145
|
+
|
|
133
146
|
## Alternatives
|
|
134
147
|
|
|
135
148
|
There are some other gems implementations for `ActiveRecord` cache such as:
|
data/lib/ar_cache.rb
CHANGED
|
@@ -18,5 +18,43 @@ 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
|
+
@cache_reflection = {}
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
delegate :configure, to: Configuration
|
|
25
|
+
|
|
26
|
+
def skip?
|
|
27
|
+
Thread.current[:ar_cache_skip]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def skip
|
|
31
|
+
return yield if skip?
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
Thread.current[:ar_cache_skip] = true
|
|
35
|
+
yield
|
|
36
|
+
ensure
|
|
37
|
+
Thread.current[:ar_cache_skip] = false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def expire?
|
|
42
|
+
Thread.current[:ar_cache_expire]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def expire
|
|
46
|
+
return yield if expire?
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
Thread.current[:ar_cache_expire] = true
|
|
50
|
+
yield
|
|
51
|
+
ensure
|
|
52
|
+
Thread.current[:ar_cache_expire] = false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def cache_reflection?(reflection)
|
|
57
|
+
@cache_reflection.fetch(reflection) { @cache_reflection[reflection] = yield }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
22
60
|
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,34 +4,22 @@ module ArCache
|
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
module Associations
|
|
6
6
|
module HasOneThroughAssociation
|
|
7
|
-
|
|
8
|
-
return super if reflection.klass.ar_cache_table.disabled?
|
|
9
|
-
return super if reflection.through_reflection.klass.ar_cache_table.disabled?
|
|
7
|
+
PRELOADER = ::ActiveRecord::Associations::Preloader.new
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
private def find_target
|
|
10
|
+
return super if ArCache.skip?
|
|
11
|
+
return super unless ArCache.cache_reflection?(reflection) do
|
|
12
|
+
ArCache::Query.new(owner.association(through_reflection.name).scope).exec_queries_cacheable? &&
|
|
13
|
+
ArCache::Query.new(source_reflection.active_record.new.association(source_reflection.name).scope)
|
|
14
|
+
.exec_queries_cacheable?
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
if reflection.strict_loading? && owner.validation_context.nil?
|
|
16
|
-
Base.strict_loading_violation!(owner: owner.class,
|
|
17
|
+
if (owner.strict_loading? || reflection.strict_loading?) && owner.validation_context.nil?
|
|
18
|
+
::ActiveRecord::Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
34
|
-
super
|
|
21
|
+
PRELOADER.preload(owner, reflection.name)
|
|
22
|
+
target
|
|
35
23
|
end
|
|
36
24
|
end
|
|
37
25
|
end
|
|
@@ -5,10 +5,8 @@ module ArCache
|
|
|
5
5
|
module Associations
|
|
6
6
|
module SingularAssociation
|
|
7
7
|
private def skip_statement_cache?(...)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return true if is_a?(::ActiveRecord::Associations::BelongsToPolymorphicAssociation)
|
|
11
|
-
return true if reflection.klass.ar_cache_table.enabled?
|
|
8
|
+
return super if ArCache.skip?
|
|
9
|
+
return true if ArCache.cache_reflection?(reflection) { ArCache::Query.new(scope).exec_queries_cacheable? }
|
|
12
10
|
|
|
13
11
|
super
|
|
14
12
|
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.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) unless klass.ar_cache_table.disabled?
|
|
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.disabled? && 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.disabled? && 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
|
|
|
@@ -4,16 +4,14 @@ module ArCache
|
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
module Core
|
|
6
6
|
module ClassMethods
|
|
7
|
-
delegate :skip_ar_cache, to: :all
|
|
8
|
-
|
|
9
7
|
# The #find use statement cache execute querying first, so need force skip.
|
|
10
8
|
def find(...)
|
|
11
|
-
ar_cache_table.
|
|
9
|
+
ArCache.skip? || ar_cache_table.disabled? ? super : all.find(...)
|
|
12
10
|
end
|
|
13
11
|
|
|
14
12
|
# The #find_by use statement cache execute querying first, so need force skip.
|
|
15
13
|
def find_by(...)
|
|
16
|
-
ar_cache_table.
|
|
14
|
+
ArCache.skip? || ar_cache_table.disabled? ? super : all.find_by(...)
|
|
17
15
|
end
|
|
18
16
|
end
|
|
19
17
|
end
|
|
@@ -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.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.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 { super }
|
|
20
30
|
end
|
|
21
31
|
end
|
|
22
32
|
end
|
|
@@ -3,45 +3,41 @@
|
|
|
3
3
|
module ArCache
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
module Relation
|
|
6
|
-
def
|
|
7
|
-
|
|
6
|
+
def reload
|
|
7
|
+
loaded? ? ArCache.skip { super } : super
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def explain
|
|
11
|
-
|
|
12
|
-
super
|
|
11
|
+
ArCache.skip { super }
|
|
13
12
|
end
|
|
14
13
|
|
|
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
|
|
14
|
+
def update_all(...)
|
|
15
|
+
ArCache.expire { delete_ar_cache_keys ? super : 0 }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def delete_all
|
|
19
|
+
ArCache.expire { delete_ar_cache_keys ? super : 0 }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private def delete_ar_cache_keys
|
|
23
|
+
return true if klass.ar_cache_table.disabled?
|
|
24
|
+
|
|
25
|
+
where_clause = ArCache::WhereClause.new(klass, arel.constraints)
|
|
26
|
+
keys = if where_clause.cacheable? && where_clause.primary_key_index?
|
|
27
|
+
where_clause.primary_cache_keys
|
|
28
|
+
else
|
|
29
|
+
pluck(primary_key).map { |item| klass.ar_cache_table.primary_cache_key(item) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return false if keys.empty?
|
|
33
|
+
|
|
34
|
+
@klass.connection.current_transaction.delete_ar_cache_keys(keys)
|
|
35
|
+
@klass.connection.current_transaction.add_changed_table(@klass.table_name)
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private def exec_queries(&block)
|
|
40
|
+
ArCache.skip? ? super : ArCache::Query.new(self).exec_queries(&block).freeze
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
end
|
|
@@ -4,7 +4,7 @@ require 'yaml'
|
|
|
4
4
|
|
|
5
5
|
module ArCache
|
|
6
6
|
class Configuration
|
|
7
|
-
singleton_class.attr_accessor :disabled, :select_disabled, :expires_in, :read_uncommitted, :
|
|
7
|
+
singleton_class.attr_accessor :disabled, :select_disabled, :expires_in, :read_uncommitted, :column_length
|
|
8
8
|
singleton_class.attr_reader :cache_store, :tables_options, :coder
|
|
9
9
|
|
|
10
10
|
def self.configure
|
|
@@ -41,7 +41,6 @@ module ArCache
|
|
|
41
41
|
options = tables_options[name.to_sym] || {}
|
|
42
42
|
options[:disabled] = disabled unless options.key?(:disabled)
|
|
43
43
|
options[:select_disabled] = select_disabled unless options.key?(:select_disabled)
|
|
44
|
-
options[:ignored_columns] = Array(options[:ignored_columns]).map(&:to_s)
|
|
45
44
|
options[:unique_indexes] = Array(options[:unique_indexes]).map { |index| Array(index).map(&:to_s).uniq }.uniq
|
|
46
45
|
options
|
|
47
46
|
end
|
|
@@ -54,6 +53,6 @@ module ArCache
|
|
|
54
53
|
@select_disabled = true
|
|
55
54
|
@expires_in = 604_800 # 1 week
|
|
56
55
|
@read_uncommitted = false
|
|
57
|
-
@
|
|
56
|
+
@column_length = 64
|
|
58
57
|
end
|
|
59
58
|
end
|
data/lib/ar_cache/marshal.rb
CHANGED
|
@@ -59,9 +59,9 @@ module ArCache
|
|
|
59
59
|
|
|
60
60
|
private def detect_wrong_key(entry, where_values_hash)
|
|
61
61
|
where_values_hash.detect do |k, v|
|
|
62
|
-
|
|
63
|
-
next if value.nil?
|
|
62
|
+
next unless entry.key?(k)
|
|
64
63
|
|
|
64
|
+
value = entry[k]
|
|
65
65
|
if v.is_a?(Array)
|
|
66
66
|
return k unless v.include?(value)
|
|
67
67
|
else
|
data/lib/ar_cache/mock_table.rb
CHANGED
data/lib/ar_cache/query.rb
CHANGED
|
@@ -10,8 +10,9 @@ 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)
|
|
14
|
-
return relation.
|
|
13
|
+
def exec_queries(&block) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
14
|
+
return [] if relation.where_clause.contradiction?
|
|
15
|
+
return ArCache.skip { relation.send(:exec_queries, &block) } unless exec_queries_cacheable?
|
|
15
16
|
|
|
16
17
|
records = table.read(where_clause, @select_values, &block)
|
|
17
18
|
|
|
@@ -22,22 +23,32 @@ module ArCache
|
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
if missed_relation
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
records += relation.find_by_sql(missed_relation.arel, &block).tap do |rs|
|
|
27
|
+
table.write(rs) if relation.select_values.empty?
|
|
27
28
|
end
|
|
28
|
-
records += relation.find_by_sql(missed_relation.arel, &block).tap { |rs| table.write(rs) }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
records_order(records)
|
|
32
|
+
|
|
33
|
+
relation.preload_associations(records) unless relation.skip_preloading_value
|
|
34
|
+
|
|
35
|
+
records.each(&:readonly!) if relation.readonly_value
|
|
36
|
+
records.each(&:strict_loading!) if relation.strict_loading_value
|
|
37
|
+
|
|
38
|
+
records
|
|
32
39
|
end
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
def exec_queries_cacheable? # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
42
|
+
return false if relation.klass.ar_cache_table.disabled?
|
|
35
43
|
return false if relation.skip_query_cache_value
|
|
36
44
|
return false if relation.lock_value
|
|
45
|
+
return false if relation.distinct_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?
|
|
@@ -55,7 +66,7 @@ module ArCache
|
|
|
55
66
|
(@select_values - table.column_names).empty?
|
|
56
67
|
end
|
|
57
68
|
|
|
58
|
-
private def order_values_cacheable?
|
|
69
|
+
private def order_values_cacheable? # rubocop:disable Metrics/CyclomaticComplexity
|
|
59
70
|
return true if where_clause.single?
|
|
60
71
|
|
|
61
72
|
size = relation.order_values.size
|
|
@@ -70,6 +81,7 @@ module ArCache
|
|
|
70
81
|
when String
|
|
71
82
|
@order_name, @order_desc = first_order_value.downcase.split
|
|
72
83
|
return false unless table.column_names.include?(@order_name)
|
|
84
|
+
return false unless ['asc', 'desc', nil].include?(@order_desc)
|
|
73
85
|
|
|
74
86
|
@order_desc = @order_desc == 'desc'
|
|
75
87
|
else
|
data/lib/ar_cache/record.rb
CHANGED
data/lib/ar_cache/table.rb
CHANGED
|
@@ -4,12 +4,11 @@ module ArCache
|
|
|
4
4
|
class Table
|
|
5
5
|
include Marshal
|
|
6
6
|
|
|
7
|
-
OPTIONS = %i[disabled select_disabled unique_indexes
|
|
7
|
+
OPTIONS = %i[disabled select_disabled unique_indexes].freeze
|
|
8
8
|
|
|
9
9
|
singleton_class.attr_reader :all
|
|
10
10
|
|
|
11
|
-
attr_reader :name, :primary_key, :unique_indexes, :column_indexes, :column_names, :md5,
|
|
12
|
-
:ignored_columns, :cache_key_prefix
|
|
11
|
+
attr_reader :name, :primary_key, :unique_indexes, :column_indexes, :column_names, :md5, :cache_key_prefix
|
|
13
12
|
|
|
14
13
|
delegate :connection, to: ActiveRecord::Base, private: true
|
|
15
14
|
|
|
@@ -32,10 +31,10 @@ module ArCache
|
|
|
32
31
|
@unique_indexes = normalize_unique_indexes(options.delete(:unique_indexes), columns).freeze
|
|
33
32
|
options.each { |k, v| instance_variable_set("@#{k}", v) }
|
|
34
33
|
@disabled = true if @primary_key.nil? # ArCache is depend on primary key implementation.
|
|
35
|
-
@column_names =
|
|
34
|
+
@column_names = columns.map(&:name).freeze
|
|
36
35
|
@column_indexes = @unique_indexes.flatten.uniq.freeze
|
|
37
36
|
coder = ArCache::Configuration.coder
|
|
38
|
-
@md5 = Digest::MD5.hexdigest("#{coder}-#{@disabled}-#{columns.to_json}
|
|
37
|
+
@md5 = Digest::MD5.hexdigest("#{coder}-#{@disabled}-#{columns.to_json}")
|
|
39
38
|
|
|
40
39
|
ArCache::Record.store(self)
|
|
41
40
|
|
|
@@ -46,18 +45,10 @@ module ArCache
|
|
|
46
45
|
@disabled
|
|
47
46
|
end
|
|
48
47
|
|
|
49
|
-
def enabled?
|
|
50
|
-
!disabled?
|
|
51
|
-
end
|
|
52
|
-
|
|
53
48
|
def select_disabled?
|
|
54
49
|
@select_disabled
|
|
55
50
|
end
|
|
56
51
|
|
|
57
|
-
def select_enabled?
|
|
58
|
-
!@select_disabled
|
|
59
|
-
end
|
|
60
|
-
|
|
61
52
|
def version
|
|
62
53
|
version = ArCache::Store.read(cache_key_prefix)
|
|
63
54
|
unless version
|
|
@@ -110,14 +101,14 @@ module ArCache
|
|
|
110
101
|
end
|
|
111
102
|
end
|
|
112
103
|
|
|
113
|
-
private def custom_unique_indexes(indexes)
|
|
104
|
+
private def custom_unique_indexes(indexes, columns)
|
|
114
105
|
indexes.each do |index|
|
|
115
|
-
index.each do |
|
|
116
|
-
column = columns.find { |c| c.name ==
|
|
117
|
-
raise ArgumentError, "The #{name} table not found #{
|
|
106
|
+
index.each do |field|
|
|
107
|
+
column = columns.find { |c| c.name == field }
|
|
108
|
+
raise ArgumentError, "The #{name} table not found #{field.inspect} column" if column.nil?
|
|
118
109
|
|
|
119
110
|
if column.type == :datetime
|
|
120
|
-
raise ArgumentError, "The #{
|
|
111
|
+
raise ArgumentError, "The #{field.inspect} is datetime type, ArCache do't support datetime type"
|
|
121
112
|
end
|
|
122
113
|
end
|
|
123
114
|
end
|
data/lib/ar_cache/version.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module ArCache
|
|
4
4
|
class WhereClause
|
|
5
|
-
attr_reader :klass, :table, :predicates
|
|
5
|
+
attr_reader :klass, :table, :predicates, :invalid_keys
|
|
6
6
|
|
|
7
7
|
def initialize(klass, predicates)
|
|
8
8
|
@klass = klass
|
|
@@ -24,8 +24,8 @@ module ArCache
|
|
|
24
24
|
count = 0
|
|
25
25
|
|
|
26
26
|
bool = index.all? do |column|
|
|
27
|
-
where_values_hash
|
|
28
|
-
if
|
|
27
|
+
where_values_hash.key?(column).tap do
|
|
28
|
+
if where_values_hash[column].is_a?(Array)
|
|
29
29
|
@multi_values_key = column
|
|
30
30
|
count += 1
|
|
31
31
|
end
|
|
@@ -52,7 +52,7 @@ module ArCache
|
|
|
52
52
|
@cache_hash = {}
|
|
53
53
|
multi_values_key = @multi_values_key || @index.first
|
|
54
54
|
|
|
55
|
-
Array(where_values_hash[multi_values_key]).each do |v|
|
|
55
|
+
Array.wrap(where_values_hash[multi_values_key]).each do |v|
|
|
56
56
|
@cache_hash[table.cache_key(where_values_hash, @index, multi_values_key, v)] = v
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -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
|
|
@@ -106,7 +105,7 @@ module ArCache
|
|
|
106
105
|
|
|
107
106
|
name = node.left.name.to_s
|
|
108
107
|
value = extract_node_value(node.right)
|
|
109
|
-
next if value.respond_to?(:size) && value.size > ArCache::Configuration.
|
|
108
|
+
next if value.respond_to?(:size) && value.size > ArCache::Configuration.column_length
|
|
110
109
|
|
|
111
110
|
hash[name] = value
|
|
112
111
|
end
|
|
@@ -14,7 +14,7 @@ ArCache.configure do |config|
|
|
|
14
14
|
# config.coder = [YAML|JSON] # default YAML
|
|
15
15
|
|
|
16
16
|
# Support the maximum length of index column value.
|
|
17
|
-
# config.
|
|
17
|
+
# config.column_length = Integer # default 64
|
|
18
18
|
|
|
19
19
|
# ArCache switch.
|
|
20
20
|
# config.disabled = Boolean # default false
|
|
@@ -27,7 +27,6 @@ ArCache.configure do |config|
|
|
|
27
27
|
# disabled: Boolean,
|
|
28
28
|
# select_disabled: Boolean,
|
|
29
29
|
# unique_indexes: Array # eg: [:id, [:name, :statue]], The default is the unique index column of the table.
|
|
30
|
-
# ignored_columns: Array # eg: [:created_at, :updated_at], defaule [].
|
|
31
30
|
# },
|
|
32
31
|
# ...
|
|
33
32
|
# }
|
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.5.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-22 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
|