cached_resource 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +41 -20
- data/lib/cached_resource/version.rb +1 -1
- data/spec/cached_resource/caching_spec.rb +33 -46
- 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: '0895f45566dd7c4ee2f394be6dda1c7a86aed9ad4e7c6a470d9a59d584c529c1'
|
4
|
+
data.tar.gz: 16106c7680c3cd6708b8171aa5db5f3993f3a77368685876e3e125b03e2d8e85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dbb4bc9fc1019dbf38dce7553b1ad15a964ca3699a461d551b892a26608b53ab0dbe4d8dbcce3878977f4b00debd88affa6494ad52d4fb2fb739a3ca6d239c3
|
7
|
+
data.tar.gz: 689a7edad73b7de5cff68c17d34135422d7166b1ae2745ae3be398cc77399e1ccd2d09a8423a3c7fda00f647216834e4b93c0a82287c39dd5ea5177d3fc7072f
|
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 cached_resource.enabled
|
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,29 +53,29 @@ 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
|
|
@@ -101,7 +102,10 @@ module CachedResource
|
|
101
102
|
if cache.is_a? Enumerable
|
102
103
|
restored = cache.map { |record| full_dup(record) }
|
103
104
|
next restored unless respond_to?(:collection_parser)
|
104
|
-
collection_parser.new(restored)
|
105
|
+
collection_parser.new(restored).tap do |parser|
|
106
|
+
parser.resource_class = self
|
107
|
+
parser.original_params = json['original_params']
|
108
|
+
end
|
105
109
|
else
|
106
110
|
full_dup(cache)
|
107
111
|
end
|
@@ -112,8 +116,12 @@ module CachedResource
|
|
112
116
|
end
|
113
117
|
|
114
118
|
# Write an entry to the cache for the given key and value.
|
115
|
-
def cache_write(key, object)
|
116
|
-
|
119
|
+
def cache_write(key, object, *arguments)
|
120
|
+
options = arguments[1] || {}
|
121
|
+
params = options[:params]
|
122
|
+
prefix_options, query_options = split_options(params)
|
123
|
+
|
124
|
+
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
125
|
result && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} WRITE #{key}")
|
118
126
|
result
|
119
127
|
end
|
@@ -150,21 +158,34 @@ module CachedResource
|
|
150
158
|
end
|
151
159
|
|
152
160
|
def json_to_object(json)
|
153
|
-
|
154
|
-
|
155
|
-
|
161
|
+
resource = json['resource']
|
162
|
+
if resource.is_a? Array
|
163
|
+
resource.map do |attrs|
|
164
|
+
self.new(attrs["object"], attrs["persistence"]).tap do |resource|
|
165
|
+
resource.prefix_options = json['prefix_options']
|
166
|
+
end
|
167
|
+
end
|
156
168
|
else
|
157
|
-
self.new(
|
169
|
+
self.new(resource["object"], resource["persistence"]).tap do |resource|
|
170
|
+
resource.prefix_options = json['prefix_options']
|
171
|
+
end
|
158
172
|
end
|
159
173
|
end
|
160
174
|
|
161
|
-
def object_to_json(object)
|
175
|
+
def object_to_json(object, prefix_options, query_options)
|
162
176
|
if object.is_a? Enumerable
|
163
|
-
|
177
|
+
{
|
178
|
+
:resource => object.map { |o| { :object => o, :persistence => o.persisted? } },
|
179
|
+
:prefix_options => prefix_options,
|
180
|
+
:original_params => query_options
|
181
|
+
}.to_json
|
164
182
|
elsif object.nil?
|
165
183
|
nil.to_json
|
166
184
|
else
|
167
|
-
{
|
185
|
+
{
|
186
|
+
:resource => { :object => object, :persistence => object.persisted? },
|
187
|
+
:prefix_options => prefix_options
|
188
|
+
}.to_json
|
168
189
|
end
|
169
190
|
end
|
170
191
|
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"}}
|
@@ -215,13 +217,39 @@ describe CachedResource do
|
|
215
217
|
cached.should be_instance_of(ActiveResource::Collection)
|
216
218
|
end
|
217
219
|
|
218
|
-
it "should return
|
220
|
+
it "should return a chainable instance of the collection_parser" do
|
219
221
|
Thing.cached_resource.cache.clear
|
220
222
|
class CustomCollection < ActiveResource::Collection; end
|
221
223
|
Thing.collection_parser = CustomCollection
|
222
|
-
|
223
|
-
|
224
|
+
|
225
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
226
|
+
mock.get "/things.json?name=ada", {}, @thing_collection.to_json
|
227
|
+
mock.get "/things.json?major=CS&name=ada", {}, @thing_collection2.to_json
|
228
|
+
end
|
229
|
+
|
230
|
+
non_cached = Thing.where(name: 'ada')
|
231
|
+
non_cached.original_params.should == { 'name' => 'ada' }
|
232
|
+
non_cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
233
|
+
|
234
|
+
cached = read_from_cache('thing/all/{:params=>{:name=>"ada"}}')
|
224
235
|
cached.should be_instance_of(CustomCollection)
|
236
|
+
cached.original_params.should == { 'name' => 'ada' }
|
237
|
+
cached.resource_class.should == Thing
|
238
|
+
cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
239
|
+
|
240
|
+
if ActiveResource::VERSION::MAJOR < 5
|
241
|
+
non_cached = cached.resource_class.where(cached.original_params.merge(major: 'CS'))
|
242
|
+
else
|
243
|
+
non_cached = cached.where(major: 'CS')
|
244
|
+
end
|
245
|
+
|
246
|
+
non_cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
|
247
|
+
non_cached.resource_class.should == Thing
|
248
|
+
non_cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
249
|
+
cached = read_from_cache('thing/all/{:params=>{"name"=>"ada",:major=>"cs"}}')
|
250
|
+
cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
|
251
|
+
cached.resource_class.should == Thing
|
252
|
+
cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
225
253
|
end
|
226
254
|
else
|
227
255
|
it "should return an Array" do
|
@@ -505,14 +533,9 @@ describe CachedResource do
|
|
505
533
|
end
|
506
534
|
end
|
507
535
|
|
508
|
-
it "should cache a response" do
|
536
|
+
it "should not cache a response" do
|
509
537
|
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
|
538
|
+
read_from_cache("thing/1").should be_nil
|
516
539
|
end
|
517
540
|
|
518
541
|
it "should always remake the request" do
|
@@ -528,42 +551,6 @@ describe CachedResource do
|
|
528
551
|
Thing.find("fded")
|
529
552
|
ActiveResource::HttpMock.requests.length.should == 2
|
530
553
|
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
554
|
end
|
568
555
|
|
569
556
|
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.1.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-01-18 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
|