cached_resource 7.0.0 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +2 -2
- data/FUNDING.json +7 -0
- data/README.md +7 -0
- data/lib/cached_resource/caching.rb +47 -20
- data/lib/cached_resource/version.rb +1 -1
- data/spec/cached_resource/caching_spec.rb +42 -49
- data/spec/spec_helper.rb +1 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1c2150c2dc21cf091c9b26674b3e52a7bd43938318704f7c2f0739a0b9756aa
|
4
|
+
data.tar.gz: 2f7b9665c688f2a60b7def43cfafbe2701accded9fcf9aabc371fe91bf78362d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c94c6b77f623a49a3259a69a4bb1b1d2d7fc219d590b740d5a86c71f3cfbf7eb783a2e8a2c06631c926bd2679b220341d8fbf03b77a3651d5219a70bb8d779
|
7
|
+
data.tar.gz: 207c37429a14511fb788d21bc69e86b01f8f59a303b20aebafb2f07e54aba48546c03a5ac7fa4b99da0bd9b7cd53d385ddb73306c643d9044d113ea638949e61
|
data/.github/workflows/ruby.yml
CHANGED
@@ -15,7 +15,7 @@ permissions:
|
|
15
15
|
jobs:
|
16
16
|
test:
|
17
17
|
|
18
|
-
runs-on: ubuntu-
|
18
|
+
runs-on: ubuntu-20.04
|
19
19
|
|
20
20
|
strategy:
|
21
21
|
matrix:
|
@@ -106,4 +106,4 @@ jobs:
|
|
106
106
|
TEST_RAILS_VERSION: ${{ matrix.rails-version }}
|
107
107
|
DEBUG: true
|
108
108
|
- name: Run tests
|
109
|
-
run: bundle exec rake
|
109
|
+
run: bundle exec rake
|
data/FUNDING.json
ADDED
data/README.md
CHANGED
@@ -25,6 +25,13 @@ CachedResource is designed to be framework agnostic, but will hook into Rails fo
|
|
25
25
|
| 💎 3.1 | | | | ✅ | ✅ | ✅ |
|
26
26
|
| 💎 3.2 | | | | ✅ | ✅ | ✅ |
|
27
27
|
|
28
|
+
## Limitations
|
29
|
+
|
30
|
+
The following are limitations for ActiveResource/Rails versions
|
31
|
+
|
32
|
+
| ActiveSupport Version | Limitation |
|
33
|
+
|---------------------- | ----------------------------------------------------------------------- |
|
34
|
+
| 🛤️ 4.X | You cannot chain calls. Ie `Thing.where(fn: 'foo').where(ln: 'bar')`. <br> However, you can still access `original_params` and the `resource_class` and replicate it with <br>`call1 = Thing.where(fn: 'foo')`<br>`call1.resource_class.where(call1.original_params.merge(ln: 'bar'))` |
|
28
35
|
|
29
36
|
## Configuration
|
30
37
|
|
@@ -37,13 +37,14 @@ module CachedResource
|
|
37
37
|
cache_read(key) || find_via_reload(key, *arguments)
|
38
38
|
end
|
39
39
|
|
40
|
-
# Re/send the request to fetch the resource
|
41
|
-
# for the request.
|
40
|
+
# Re/send the request to fetch the resource
|
42
41
|
def find_via_reload(key, *arguments)
|
43
42
|
object = find_without_cache(*arguments)
|
43
|
+
return object unless should_cache?(object)
|
44
|
+
|
44
45
|
cache_collection_synchronize(object, *arguments) if cached_resource.collection_synchronize
|
45
46
|
return object if !cached_resource.cache_collections && is_any_collection?(*arguments)
|
46
|
-
cache_write(key, object)
|
47
|
+
cache_write(key, object, *arguments)
|
47
48
|
cache_read(key)
|
48
49
|
end
|
49
50
|
|
@@ -52,32 +53,38 @@ module CachedResource
|
|
52
53
|
# otherwise update an existing collection if possible.
|
53
54
|
def cache_collection_synchronize(object, *arguments)
|
54
55
|
if object.is_a? Enumerable
|
55
|
-
update_singles_cache(object)
|
56
|
+
update_singles_cache(object, *arguments)
|
56
57
|
# update the collection only if this is a subset of it
|
57
|
-
update_collection_cache(object) unless is_collection?(*arguments)
|
58
|
+
update_collection_cache(object, *arguments) unless is_collection?(*arguments)
|
58
59
|
else
|
59
|
-
update_collection_cache(object)
|
60
|
+
update_collection_cache(object, *arguments)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
63
64
|
# Update the cache of singles with an array of updates.
|
64
|
-
def update_singles_cache(updates)
|
65
|
+
def update_singles_cache(updates, *arguments)
|
65
66
|
updates = Array(updates)
|
66
|
-
updates.each { |object| cache_write(cache_key(object.send(primary_key)), object) }
|
67
|
+
updates.each { |object| cache_write(cache_key(object.send(primary_key)), object, *arguments) }
|
67
68
|
end
|
68
69
|
|
69
70
|
# Update the "mother" collection with an array of updates.
|
70
|
-
def update_collection_cache(updates)
|
71
|
+
def update_collection_cache(updates, *arguments)
|
71
72
|
updates = Array(updates)
|
72
73
|
collection = cache_read(cache_key(cached_resource.collection_arguments))
|
73
74
|
|
74
75
|
if collection && !updates.empty?
|
75
76
|
index = collection.inject({}) { |hash, object| hash[object.send(primary_key)] = object; hash }
|
76
77
|
updates.each { |object| index[object.send(primary_key)] = object }
|
77
|
-
cache_write(cache_key(cached_resource.collection_arguments), index.values)
|
78
|
+
cache_write(cache_key(cached_resource.collection_arguments), index.values, *arguments)
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
82
|
+
# Avoid cache nil or [] objects
|
83
|
+
def should_cache?(object)
|
84
|
+
return false unless cached_resource.enabled
|
85
|
+
object.respond_to?(:empty?) ? !object.empty? : !!object
|
86
|
+
end
|
87
|
+
|
81
88
|
# Determine if the given arguments represent
|
82
89
|
# the entire collection of objects.
|
83
90
|
def is_collection?(*arguments)
|
@@ -101,7 +108,10 @@ module CachedResource
|
|
101
108
|
if cache.is_a? Enumerable
|
102
109
|
restored = cache.map { |record| full_dup(record) }
|
103
110
|
next restored unless respond_to?(:collection_parser)
|
104
|
-
collection_parser.new(restored)
|
111
|
+
collection_parser.new(restored).tap do |parser|
|
112
|
+
parser.resource_class = self
|
113
|
+
parser.original_params = json['original_params']
|
114
|
+
end
|
105
115
|
else
|
106
116
|
full_dup(cache)
|
107
117
|
end
|
@@ -112,8 +122,12 @@ module CachedResource
|
|
112
122
|
end
|
113
123
|
|
114
124
|
# Write an entry to the cache for the given key and value.
|
115
|
-
def cache_write(key, object)
|
116
|
-
|
125
|
+
def cache_write(key, object, *arguments)
|
126
|
+
options = arguments[1] || {}
|
127
|
+
params = options[:params]
|
128
|
+
prefix_options, query_options = split_options(params)
|
129
|
+
|
130
|
+
result = cached_resource.cache.write(key, object_to_json(object, prefix_options, query_options), :race_condition_ttl => cached_resource.race_condition_ttl, :expires_in => cached_resource.generate_ttl)
|
117
131
|
result && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} WRITE #{key}")
|
118
132
|
result
|
119
133
|
end
|
@@ -150,21 +164,34 @@ module CachedResource
|
|
150
164
|
end
|
151
165
|
|
152
166
|
def json_to_object(json)
|
153
|
-
|
154
|
-
|
155
|
-
|
167
|
+
resource = json['resource']
|
168
|
+
if resource.is_a? Array
|
169
|
+
resource.map do |attrs|
|
170
|
+
self.new(attrs["object"], attrs["persistence"]).tap do |resource|
|
171
|
+
resource.prefix_options = json['prefix_options']
|
172
|
+
end
|
173
|
+
end
|
156
174
|
else
|
157
|
-
self.new(
|
175
|
+
self.new(resource["object"], resource["persistence"]).tap do |resource|
|
176
|
+
resource.prefix_options = json['prefix_options']
|
177
|
+
end
|
158
178
|
end
|
159
179
|
end
|
160
180
|
|
161
|
-
def object_to_json(object)
|
181
|
+
def object_to_json(object, prefix_options, query_options)
|
162
182
|
if object.is_a? Enumerable
|
163
|
-
|
183
|
+
{
|
184
|
+
:resource => object.map { |o| { :object => o, :persistence => o.persisted? } },
|
185
|
+
:prefix_options => prefix_options,
|
186
|
+
:original_params => query_options
|
187
|
+
}.to_json
|
164
188
|
elsif object.nil?
|
165
189
|
nil.to_json
|
166
190
|
else
|
167
|
-
{
|
191
|
+
{
|
192
|
+
:resource => { :object => object, :persistence => object.persisted? },
|
193
|
+
:prefix_options => prefix_options
|
194
|
+
}.to_json
|
168
195
|
end
|
169
196
|
end
|
170
197
|
end
|
@@ -18,6 +18,8 @@ describe CachedResource do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
@thing = {:thing => {:id => 1, :name => "Ada"}}
|
21
|
+
@thing_collection = [{:id => 1, :name => "Ada"}, {:id => 2, :name => "Ada", :major => 'CS'}]
|
22
|
+
@thing_collection2 = [{:id => 2, :name => "Ada", :major => 'CS'}]
|
21
23
|
@other_thing = {:thing => {:id => 1, :name => "Ari"}}
|
22
24
|
@thing2 = {:thing => {:id => 2, :name => "Joe"}}
|
23
25
|
@other_thing2 = {:thing => {:id => 2, :name => "Jeb"}}
|
@@ -31,6 +33,7 @@ describe CachedResource do
|
|
31
33
|
@other_string_thing_json = @other_string_thing.to_json
|
32
34
|
@date_thing_json = @date_thing.to_json
|
33
35
|
@nil_thing = nil.to_json
|
36
|
+
@empty_array_thing = [].to_json
|
34
37
|
@not_the_thing = {:not_the_thing => {:id => 1, :name => "Not"}}
|
35
38
|
@not_the_thing_json = @not_the_thing.to_json
|
36
39
|
end
|
@@ -57,6 +60,7 @@ describe CachedResource do
|
|
57
60
|
mock.get "/things/1.json?foo=bar", {}, @thing_json
|
58
61
|
mock.get "/things/fded.json", {}, @string_thing_json
|
59
62
|
mock.get "/things.json?name=42", {}, @nil_thing, 404
|
63
|
+
mock.get "/things.json?name=43", {}, @empty_array_thing
|
60
64
|
mock.get "/things/4.json", {}, @date_thing_json
|
61
65
|
mock.get "/not_the_things/1.json", {}, @not_the_thing_json
|
62
66
|
end
|
@@ -64,15 +68,19 @@ describe CachedResource do
|
|
64
68
|
|
65
69
|
it "should cache a response" do
|
66
70
|
result = Thing.find(1)
|
67
|
-
|
68
71
|
read_from_cache("thing/1").should == result
|
69
72
|
end
|
70
73
|
|
71
|
-
it "
|
72
|
-
|
74
|
+
it "shouldn't cache nil response" do
|
75
|
+
Thing.find(:all, :params => { :name => '42' })
|
73
76
|
read_from_cache("thing/all/name/42").should == nil
|
74
77
|
end
|
75
78
|
|
79
|
+
it "shouldn't cache [] response" do
|
80
|
+
Thing.find(:all, :params => { :name => '43' })
|
81
|
+
read_from_cache("thing/all/name/43").should == nil
|
82
|
+
end
|
83
|
+
|
76
84
|
it "should cache a response for a string primary key" do
|
77
85
|
result = Thing.find("fded")
|
78
86
|
read_from_cache("thing/fded").should == result
|
@@ -215,13 +223,39 @@ describe CachedResource do
|
|
215
223
|
cached.should be_instance_of(ActiveResource::Collection)
|
216
224
|
end
|
217
225
|
|
218
|
-
it "should return
|
226
|
+
it "should return a chainable instance of the collection_parser" do
|
219
227
|
Thing.cached_resource.cache.clear
|
220
228
|
class CustomCollection < ActiveResource::Collection; end
|
221
229
|
Thing.collection_parser = CustomCollection
|
222
|
-
|
223
|
-
|
230
|
+
|
231
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
232
|
+
mock.get "/things.json?name=ada", {}, @thing_collection.to_json
|
233
|
+
mock.get "/things.json?major=CS&name=ada", {}, @thing_collection2.to_json
|
234
|
+
end
|
235
|
+
|
236
|
+
non_cached = Thing.where(name: 'ada')
|
237
|
+
non_cached.original_params.should == { 'name' => 'ada' }
|
238
|
+
non_cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
239
|
+
|
240
|
+
cached = read_from_cache('thing/all/{:params=>{:name=>"ada"}}')
|
224
241
|
cached.should be_instance_of(CustomCollection)
|
242
|
+
cached.original_params.should == { 'name' => 'ada' }
|
243
|
+
cached.resource_class.should == Thing
|
244
|
+
cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
245
|
+
|
246
|
+
if ActiveResource::VERSION::MAJOR < 5
|
247
|
+
non_cached = cached.resource_class.where(cached.original_params.merge(major: 'CS'))
|
248
|
+
else
|
249
|
+
non_cached = cached.where(major: 'CS')
|
250
|
+
end
|
251
|
+
|
252
|
+
non_cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
|
253
|
+
non_cached.resource_class.should == Thing
|
254
|
+
non_cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
255
|
+
cached = read_from_cache('thing/all/{:params=>{"name"=>"ada",:major=>"cs"}}')
|
256
|
+
cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
|
257
|
+
cached.resource_class.should == Thing
|
258
|
+
cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
225
259
|
end
|
226
260
|
else
|
227
261
|
it "should return an Array" do
|
@@ -505,14 +539,9 @@ describe CachedResource do
|
|
505
539
|
end
|
506
540
|
end
|
507
541
|
|
508
|
-
it "should cache a response" do
|
542
|
+
it "should not cache a response" do
|
509
543
|
result = Thing.find(1)
|
510
|
-
read_from_cache("thing/1").should
|
511
|
-
end
|
512
|
-
|
513
|
-
it "should cache a response for a string primary key" do
|
514
|
-
result = Thing.find("fded")
|
515
|
-
read_from_cache("thing/fded").should == result
|
544
|
+
read_from_cache("thing/1").should be_nil
|
516
545
|
end
|
517
546
|
|
518
547
|
it "should always remake the request" do
|
@@ -528,42 +557,6 @@ describe CachedResource do
|
|
528
557
|
Thing.find("fded")
|
529
558
|
ActiveResource::HttpMock.requests.length.should == 2
|
530
559
|
end
|
531
|
-
|
532
|
-
it "should rewrite the cache for each request" do
|
533
|
-
Thing.find(1)
|
534
|
-
old_result = read_from_cache("thing/1")
|
535
|
-
|
536
|
-
# change the response
|
537
|
-
ActiveResource::HttpMock.reset!
|
538
|
-
ActiveResource::HttpMock.respond_to do |mock|
|
539
|
-
mock.get "/things/1.json", {}, @other_thing_json
|
540
|
-
end
|
541
|
-
|
542
|
-
Thing.find(1)
|
543
|
-
new_result = read_from_cache("thing/1")
|
544
|
-
# since active resources are equal if and only if they
|
545
|
-
# are the same object or an instance of the same class,
|
546
|
-
# not new?, and have the same id.
|
547
|
-
new_result.name.should_not == old_result.name
|
548
|
-
end
|
549
|
-
|
550
|
-
it "should rewrite the cache for each request for a string primary key" do
|
551
|
-
Thing.find("fded")
|
552
|
-
old_result = read_from_cache("thing/fded")
|
553
|
-
|
554
|
-
# change the response
|
555
|
-
ActiveResource::HttpMock.reset!
|
556
|
-
ActiveResource::HttpMock.respond_to do |mock|
|
557
|
-
mock.get "/things/fded.json", {}, @other_string_thing_json
|
558
|
-
end
|
559
|
-
|
560
|
-
Thing.find("fded")
|
561
|
-
new_result = read_from_cache("thing/fded")
|
562
|
-
# since active resources are equal if and only if they
|
563
|
-
# are the same object or an instance of the same class,
|
564
|
-
# not new?, and have the same id.
|
565
|
-
new_result.name.should_not == old_result.name
|
566
|
-
end
|
567
560
|
end
|
568
561
|
|
569
562
|
describe "when cache_collections is disabled" do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cached_resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Morgan Brown
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeresource
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- ".github/workflows/ruby.yml"
|
90
90
|
- ".gitignore"
|
91
91
|
- ".rspec"
|
92
|
+
- FUNDING.json
|
92
93
|
- Gemfile
|
93
94
|
- LICENSE
|
94
95
|
- README.md
|
@@ -132,4 +133,8 @@ rubygems_version: 3.1.6
|
|
132
133
|
signing_key:
|
133
134
|
specification_version: 4
|
134
135
|
summary: Caching for ActiveResource
|
135
|
-
test_files:
|
136
|
+
test_files:
|
137
|
+
- spec/cached_resource/cached_resource_spec.rb
|
138
|
+
- spec/cached_resource/caching_spec.rb
|
139
|
+
- spec/cached_resource/configuration_spec.rb
|
140
|
+
- spec/spec_helper.rb
|