identity_cache 1.2.0 → 1.6.3
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/.github/workflows/ci.yml +8 -7
- data/.gitignore +1 -1
- data/.rubocop.yml +0 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +84 -2
- data/Gemfile +4 -4
- data/Gemfile.lock +118 -0
- data/README.md +28 -5
- data/Rakefile +98 -6
- data/dev.yml +17 -17
- data/gemfiles/Gemfile.latest-release +1 -0
- data/gemfiles/Gemfile.min-supported +5 -5
- data/gemfiles/Gemfile.rails-edge +1 -0
- data/identity_cache.gemspec +3 -3
- data/lib/identity_cache/belongs_to_caching.rb +1 -1
- data/lib/identity_cache/cache_fetcher.rb +12 -3
- data/lib/identity_cache/cache_key_loader.rb +1 -1
- data/lib/identity_cache/cached/attribute.rb +66 -3
- data/lib/identity_cache/cached/attribute_by_multi.rb +94 -9
- data/lib/identity_cache/cached/attribute_by_one.rb +4 -40
- data/lib/identity_cache/cached/belongs_to.rb +14 -10
- data/lib/identity_cache/cached/primary_index.rb +10 -2
- data/lib/identity_cache/cached/recursive/association.rb +1 -1
- data/lib/identity_cache/cached/reference/has_many.rb +1 -1
- data/lib/identity_cache/configuration_dsl.rb +1 -1
- data/lib/identity_cache/encoder.rb +1 -0
- data/lib/identity_cache/fallback_fetcher.rb +5 -1
- data/lib/identity_cache/memoized_cache_proxy.rb +10 -0
- data/lib/identity_cache/parent_model_expiration.rb +8 -3
- data/lib/identity_cache/query_api.rb +12 -6
- data/lib/identity_cache/should_use_cache.rb +10 -0
- data/lib/identity_cache/version.rb +1 -1
- data/lib/identity_cache/with_primary_index.rb +27 -14
- data/lib/identity_cache.rb +131 -21
- data/shipit.rubygems.yml +4 -1
- metadata +13 -12
- data/isogun.yml +0 -11
data/lib/identity_cache.rb
CHANGED
@@ -60,6 +60,10 @@ module IdentityCache
|
|
60
60
|
|
61
61
|
class InverseAssociationError < StandardError; end
|
62
62
|
|
63
|
+
class NestedDeferredParentBlockError < StandardError; end
|
64
|
+
|
65
|
+
class NestedDeferredCacheExpirationBlockError < StandardError; end
|
66
|
+
|
63
67
|
class UnsupportedScopeError < StandardError; end
|
64
68
|
|
65
69
|
class UnsupportedAssociationError < StandardError; end
|
@@ -115,27 +119,36 @@ module IdentityCache
|
|
115
119
|
!readonly
|
116
120
|
end
|
117
121
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
pool.
|
122
|
+
# Rails wraps each of your tests in a transaction, so that any changes
|
123
|
+
# made to the database during the test can be rolled back afterwards.
|
124
|
+
# These transactions are flagged as "unjoinable", which tries to make
|
125
|
+
# your application behave as if they weren't there. In particular:
|
126
|
+
#
|
127
|
+
# - Opening another transaction during the test creates a savepoint,
|
128
|
+
# which can be rolled back independently of the main transaction.
|
129
|
+
# - When those nested transactions complete, any `after_commit`
|
130
|
+
# callbacks for records modified during the transaction will run,
|
131
|
+
# even though the changes haven't actually been committed yet.
|
132
|
+
#
|
133
|
+
# By ignoring unjoinable transactions, IdentityCache's behaviour
|
134
|
+
# during your test suite will more closely match production.
|
135
|
+
#
|
136
|
+
# When there are no open transactions, `current_transaction` returns a
|
137
|
+
# special `NullTransaction` object that is unjoinable, meaning we will
|
138
|
+
# use the cache.
|
139
|
+
if ActiveRecord::ConnectionAdapters::ConnectionPool.method_defined?(:active_connection)
|
140
|
+
def should_use_cache? # :nodoc:
|
141
|
+
ActiveRecord::Base.connection_handler.connection_pool_list(ActiveRecord::Base.current_role).none? do |pool|
|
142
|
+
pool.active_connection? &&
|
143
|
+
pool.active_connection.current_transaction.joinable?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
else
|
147
|
+
def should_use_cache? # :nodoc:
|
148
|
+
ActiveRecord::Base.connection_handler.connection_pool_list(ActiveRecord::Base.current_role).none? do |pool|
|
149
|
+
pool.active_connection? &&
|
150
|
+
pool.connection.current_transaction.joinable?
|
151
|
+
end
|
139
152
|
end
|
140
153
|
end
|
141
154
|
|
@@ -191,6 +204,99 @@ module IdentityCache
|
|
191
204
|
result
|
192
205
|
end
|
193
206
|
|
207
|
+
# Executes a block with deferred parent expiration, ensuring that the parent
|
208
|
+
# records' cache expiration is deferred until the block completes. When the block
|
209
|
+
# completes, it triggers expiration of the primary index for the parent records.
|
210
|
+
# Raises a NestedDeferredParentBlockError if a deferred parent expiration block
|
211
|
+
# is already active on the current thread.
|
212
|
+
#
|
213
|
+
# == Parameters:
|
214
|
+
# No parameters.
|
215
|
+
#
|
216
|
+
# == Raises:
|
217
|
+
# NestedDeferredParentBlockError if a deferred parent expiration block is already active.
|
218
|
+
#
|
219
|
+
# == Yield:
|
220
|
+
# Runs the provided block with deferred parent expiration.
|
221
|
+
#
|
222
|
+
# == Returns:
|
223
|
+
# The result of executing the provided block.
|
224
|
+
#
|
225
|
+
# == Ensures:
|
226
|
+
# Cleans up thread-local variables related to deferred parent expiration regardless
|
227
|
+
# of whether the block raises an exception.
|
228
|
+
def with_deferred_parent_expiration
|
229
|
+
raise NestedDeferredParentBlockError if Thread.current[:idc_deferred_parent_expiration]
|
230
|
+
|
231
|
+
if Thread.current[:idc_deferred_expiration]
|
232
|
+
deprecator.deprecation_warning("`with_deferred_parent_expiration`")
|
233
|
+
end
|
234
|
+
|
235
|
+
Thread.current[:idc_deferred_parent_expiration] = true
|
236
|
+
Thread.current[:idc_parent_records_for_cache_expiry] = Set.new
|
237
|
+
|
238
|
+
result = yield
|
239
|
+
|
240
|
+
Thread.current[:idc_deferred_parent_expiration] = nil
|
241
|
+
Thread.current[:idc_parent_records_for_cache_expiry].each(&:expire_primary_index)
|
242
|
+
|
243
|
+
result
|
244
|
+
ensure
|
245
|
+
Thread.current[:idc_deferred_parent_expiration] = nil
|
246
|
+
Thread.current[:idc_parent_records_for_cache_expiry]&.clear
|
247
|
+
end
|
248
|
+
|
249
|
+
# Executes a block with deferred cache expiration, ensuring that the records' (parent,
|
250
|
+
# children and attributes) cache expiration is deferred until the block completes. When
|
251
|
+
# the block completes, it issues delete_multi calls for all the records and attributes
|
252
|
+
# that were marked for expiration.
|
253
|
+
#
|
254
|
+
# == Parameters:
|
255
|
+
# No parameters.
|
256
|
+
#
|
257
|
+
# == Raises:
|
258
|
+
# NestedDeferredCacheExpirationBlockError if a deferred cache expiration block is already active.
|
259
|
+
#
|
260
|
+
# == Yield:
|
261
|
+
# Runs the provided block with deferred cache expiration.
|
262
|
+
#
|
263
|
+
# == Returns:
|
264
|
+
# The result of executing the provided block.
|
265
|
+
#
|
266
|
+
# == Ensures:
|
267
|
+
# Cleans up thread-local variables related to deferred cache expiration regardless
|
268
|
+
# of whether the block raises an exception.
|
269
|
+
def with_deferred_expiration
|
270
|
+
raise NestedDeferredCacheExpirationBlockError if Thread.current[:idc_deferred_expiration]
|
271
|
+
|
272
|
+
if Thread.current[:idc_deferred_parent_expiration]
|
273
|
+
deprecator.deprecation_warning("`with_deferred_parent_expiration`")
|
274
|
+
end
|
275
|
+
|
276
|
+
Thread.current[:idc_deferred_expiration] = true
|
277
|
+
Thread.current[:idc_records_to_expire] = Set.new
|
278
|
+
Thread.current[:idc_attributes_to_expire] = Set.new
|
279
|
+
|
280
|
+
result = yield
|
281
|
+
|
282
|
+
Thread.current[:idc_deferred_expiration] = nil
|
283
|
+
if Thread.current[:idc_records_to_expire].any?
|
284
|
+
IdentityCache.cache.delete_multi(
|
285
|
+
Thread.current[:idc_records_to_expire]
|
286
|
+
)
|
287
|
+
end
|
288
|
+
if Thread.current[:idc_attributes_to_expire].any?
|
289
|
+
IdentityCache.cache.delete_multi(
|
290
|
+
Thread.current[:idc_attributes_to_expire]
|
291
|
+
)
|
292
|
+
end
|
293
|
+
result
|
294
|
+
ensure
|
295
|
+
Thread.current[:idc_deferred_expiration] = nil
|
296
|
+
Thread.current[:idc_records_to_expire].clear
|
297
|
+
Thread.current[:idc_attributes_to_expire].clear
|
298
|
+
end
|
299
|
+
|
194
300
|
def with_fetch_read_only_records(value = true)
|
195
301
|
old_value = Thread.current[:identity_cache_fetch_read_only_records]
|
196
302
|
Thread.current[:identity_cache_fetch_read_only_records] = value
|
@@ -210,6 +316,10 @@ module IdentityCache
|
|
210
316
|
ParentModelExpiration.install_all_pending_parent_expiry_hooks
|
211
317
|
end
|
212
318
|
|
319
|
+
def deprecator
|
320
|
+
@deprecator ||= ActiveSupport::Deprecation.new("1.7.0", "IdentityCache")
|
321
|
+
end
|
322
|
+
|
213
323
|
private
|
214
324
|
|
215
325
|
def fetch_in_batches(keys, &block)
|
data/shipit.rubygems.yml
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: identity_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Camilo Lopez
|
@@ -11,10 +11,10 @@ authors:
|
|
11
11
|
- Tobias Lutke
|
12
12
|
- Arthur Neves
|
13
13
|
- Francis Bogsanyi
|
14
|
-
autorequire:
|
14
|
+
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date:
|
17
|
+
date: 2024-10-22 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: activerecord
|
@@ -22,14 +22,14 @@ dependencies:
|
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
25
|
+
version: '7.0'
|
26
26
|
type: :runtime
|
27
27
|
prerelease: false
|
28
28
|
version_requirements: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.0'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: ar_transaction_changes
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
67
|
+
version: '2.0'
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
74
|
+
version: '2.0'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: rake
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,12 +111,14 @@ files:
|
|
111
111
|
- ".github/workflows/cla.yml"
|
112
112
|
- ".gitignore"
|
113
113
|
- ".rubocop.yml"
|
114
|
+
- ".ruby-version"
|
114
115
|
- ".spin/bootstrap"
|
115
116
|
- ".spin/svc.yml"
|
116
117
|
- CAVEATS.md
|
117
118
|
- CHANGELOG.md
|
118
119
|
- CONTRIBUTING.md
|
119
120
|
- Gemfile
|
121
|
+
- Gemfile.lock
|
120
122
|
- LICENSE
|
121
123
|
- README.md
|
122
124
|
- Rakefile
|
@@ -125,7 +127,6 @@ files:
|
|
125
127
|
- gemfiles/Gemfile.min-supported
|
126
128
|
- gemfiles/Gemfile.rails-edge
|
127
129
|
- identity_cache.gemspec
|
128
|
-
- isogun.yml
|
129
130
|
- lib/identity_cache.rb
|
130
131
|
- lib/identity_cache/belongs_to_caching.rb
|
131
132
|
- lib/identity_cache/cache_fetcher.rb
|
@@ -175,7 +176,7 @@ homepage: https://github.com/Shopify/identity_cache
|
|
175
176
|
licenses: []
|
176
177
|
metadata:
|
177
178
|
allowed_push_host: https://rubygems.org
|
178
|
-
post_install_message:
|
179
|
+
post_install_message:
|
179
180
|
rdoc_options: []
|
180
181
|
require_paths:
|
181
182
|
- lib
|
@@ -183,15 +184,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
184
|
requirements:
|
184
185
|
- - ">="
|
185
186
|
- !ruby/object:Gem::Version
|
186
|
-
version:
|
187
|
+
version: 3.0.0
|
187
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
189
|
requirements:
|
189
190
|
- - ">="
|
190
191
|
- !ruby/object:Gem::Version
|
191
192
|
version: '0'
|
192
193
|
requirements: []
|
193
|
-
rubygems_version: 3.
|
194
|
-
signing_key:
|
194
|
+
rubygems_version: 3.5.22
|
195
|
+
signing_key:
|
195
196
|
specification_version: 4
|
196
197
|
summary: IdentityCache lets you specify how you want to cache your model objects,
|
197
198
|
at the model level, and adds a number of convenience methods for accessing those
|