ar_cache 1.0.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eab4ff7873091b901a45bfa48e948679d7feda3e0e547201d3f5ab931bbf77e
4
- data.tar.gz: 642654c010e8ced742980a0657480305be9904835a23715d884df3a90d42eef8
3
+ metadata.gz: 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