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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eab4ff7873091b901a45bfa48e948679d7feda3e0e547201d3f5ab931bbf77e
4
- data.tar.gz: 642654c010e8ced742980a0657480305be9904835a23715d884df3a90d42eef8
3
+ metadata.gz: 86d921c69c8ac7d8cbc0cefdb5614120a60f5663c5a2b8e3bc07a1c9c1d8d8a0
4
+ data.tar.gz: ced6d5cf673fb6e83070ba95e4daf6fb9d0994a93f8963de63692317c9c77081
5
5
  SHA512:
6
- metadata.gz: a41629683860591506020f8ee516d6d3948ac0daf5381dff1c1b3410fc659be978a4f27d31c0ba49be3fbdf9fd608e7c424a215f5efd75842f5fbe47b31a2d75
7
- data.tar.gz: 71dc11fbccc0816af45df3a1e3e3b3460c595f67fed0376afb9202237367970593441937131e80514d7dfd6bd601d4d2bdc3e3329267c9f6370efb36708291ec
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.0.0)
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.1)
11
- actionpack (= 6.1.1)
12
- activesupport (= 6.1.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.1)
16
- actionpack (= 6.1.1)
17
- activejob (= 6.1.1)
18
- activerecord (= 6.1.1)
19
- activestorage (= 6.1.1)
20
- activesupport (= 6.1.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.1)
23
- actionpack (= 6.1.1)
24
- actionview (= 6.1.1)
25
- activejob (= 6.1.1)
26
- activesupport (= 6.1.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.1)
30
- actionview (= 6.1.1)
31
- activesupport (= 6.1.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.1)
37
- actionpack (= 6.1.1)
38
- activerecord (= 6.1.1)
39
- activestorage (= 6.1.1)
40
- activesupport (= 6.1.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.1)
43
- activesupport (= 6.1.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.1)
49
- activesupport (= 6.1.1)
48
+ activejob (6.1.3)
49
+ activesupport (= 6.1.3)
50
50
  globalid (>= 0.3.6)
51
- activemodel (6.1.1)
52
- activesupport (= 6.1.1)
53
- activerecord (6.1.1)
54
- activemodel (= 6.1.1)
55
- activesupport (= 6.1.1)
56
- activestorage (6.1.1)
57
- actionpack (= 6.1.1)
58
- activejob (= 6.1.1)
59
- activerecord (= 6.1.1)
60
- activesupport (= 6.1.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.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 (1.8.5)
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.7)
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.3)
91
- nio4r (2.5.4)
92
- nokogiri (1.11.1-x86_64-linux)
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.13.1)
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.1)
105
- actioncable (= 6.1.1)
106
- actionmailbox (= 6.1.1)
107
- actionmailer (= 6.1.1)
108
- actionpack (= 6.1.1)
109
- actiontext (= 6.1.1)
110
- actionview (= 6.1.1)
111
- activejob (= 6.1.1)
112
- activemodel (= 6.1.1)
113
- activerecord (= 6.1.1)
114
- activestorage (= 6.1.1)
115
- activesupport (= 6.1.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.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.1)
125
- actionpack (= 6.1.1)
126
- activesupport (= 6.1.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.0.3)
137
+ regexp_parser (2.1.1)
133
138
  rexml (3.2.4)
134
- rubocop (1.9.0)
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.10.3)
146
- rubocop (>= 0.87, < 2.0)
147
- rubocop-performance (1.9.2)
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
+ ![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
 
@@ -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#skip_ar_cache`, eg:
71
+ - `ActiveRecord::Relation#reload`, eg:
62
72
 
63
73
  ```ruby
64
- User.skip_ar_cache.find(1)
65
- User.where(id: [1, 2]).skip_ar_cache.load
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]) # 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
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
- - Open `ArCache` or close `ArCache`.
118
- - `ActiveRecord` update/delete condition does not hit the unique index.
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
- singleton_class.delegate :configure, to: Configuration
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
 
@@ -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 { super } : super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -4,34 +4,22 @@ 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
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
- if owner.strict_loading? && owner.validation_context.nil?
12
- Base.strict_loading_violation!(owner: owner.class, association: reflection.klass)
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, association: reflection.name)
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
- # 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
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
- # Polymorphic associations do not support computing the class, so can't judge ArCache status.
9
- # But SingularAssociation query usually can hit the unique index, so here return true directly.
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
- 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.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) unless klass.ar_cache_table.disabled?
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.disabled? && 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.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 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
 
@@ -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.enabled? ? all.find(...) : super
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.enabled? ? all.find_by(...) : super
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.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
@@ -10,7 +10,7 @@ module ArCache
10
10
 
11
11
  def ar_cache_table
12
12
  @ar_cache_table ||= begin
13
- if abstract_class? || self == ArCache::Record
13
+ if abstract_class? || table_name == 'ar_cache_records'
14
14
  ArCache::MockTable
15
15
  else
16
16
  ArCache::Table.new(table_name)
@@ -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.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.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 { 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 skip_ar_cache
7
- tap { @skip_ar_cache = true }
6
+ def reload
7
+ loaded? ? ArCache.skip { super } : super
8
8
  end
9
9
 
10
10
  def explain
11
- @skip_ar_cache = true
12
- super
11
+ ArCache.skip { super }
13
12
  end
14
13
 
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
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, :index_column_max_size
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
- @index_column_max_size = 64
56
+ @column_length = 64
58
57
  end
59
58
  end
@@ -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
- value = entry[k]
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
@@ -7,18 +7,10 @@ module ArCache
7
7
  true
8
8
  end
9
9
 
10
- def enabled?
11
- false
12
- end
13
-
14
10
  def select_disabled?
15
11
  true
16
12
  end
17
13
 
18
- def select_enabled?
19
- false
20
- end
21
-
22
14
  def version
23
15
  -1
24
16
  end
@@ -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.skip_ar_cache.send(:exec_queries, &block) unless exec_queries_cacheable?
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
- if table.ignored_columns.any? && relation.select_values.any?
26
- missed_relation = missed_relation.reselect(table.column_names)
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
- private def exec_queries_cacheable? # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
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
@@ -4,8 +4,6 @@ module ArCache
4
4
  class Record < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
5
5
  self.table_name = 'ar_cache_records'
6
6
 
7
- default_scope { skip_ar_cache }
8
-
9
7
  def self.get(table_name)
10
8
  find_by(table_name: table_name)
11
9
  end
@@ -4,12 +4,11 @@ module ArCache
4
4
  class Table
5
5
  include Marshal
6
6
 
7
- OPTIONS = %i[disabled select_disabled unique_indexes ignored_columns].freeze
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 = (columns.map(&:name) - @ignored_columns).freeze
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}-#{@ignored_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 |column|
116
- column = columns.find { |c| c.name == column }
117
- raise ArgumentError, "The #{name} table not found #{column.inspect} column" if column.nil?
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 #{column.inspect} is datetime type, ArCache do't support datetime type"
111
+ raise ArgumentError, "The #{field.inspect} is datetime type, ArCache do't support datetime type"
121
112
  end
122
113
  end
123
114
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArCache
4
- VERSION = '1.0.0'
4
+ VERSION = '1.5.0'
5
5
  end
@@ -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[column].tap do |value|
28
- if value.is_a?(Array)
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 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
@@ -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.index_column_max_size
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.index_column_max_size = Integer # default 64
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.0.0
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-02 00:00:00.000000000 Z
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