active_remote-cached 1.0.0 → 1.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/ci.yml +85 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +58 -0
- data/Appraisals +27 -0
- data/Gemfile +2 -0
- data/README.md +121 -0
- data/Rakefile +6 -9
- data/active_remote-cached.gemspec +52 -21
- data/lib/active_remote/cached/argument_keys.rb +83 -46
- data/lib/active_remote/cached/cache.rb +78 -51
- data/lib/active_remote/cached/railtie.rb +5 -5
- data/lib/active_remote/cached/version.rb +3 -1
- data/lib/active_remote/cached.rb +159 -112
- data/lib/active_remote-cached.rb +3 -1
- data/spec/active_remote/cached/argument_keys_spec.rb +136 -10
- data/spec/active_remote/cached/cache_spec.rb +179 -16
- data/spec/active_remote/cached_delete_methods_spec.rb +66 -12
- data/spec/active_remote/cached_exist_methods_spec.rb +111 -33
- data/spec/active_remote/cached_find_methods_spec.rb +62 -51
- data/spec/active_remote/cached_search_methods_spec.rb +202 -102
- data/spec/active_remote/cached_spec.rb +331 -0
- data/spec/spec_helper.rb +6 -10
- metadata +76 -22
|
@@ -1,63 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
class SearchMethodClass
|
|
4
6
|
include ::ActiveRemote::Cached
|
|
5
7
|
|
|
6
|
-
def self.derp
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
def self.derp
|
|
9
|
+
nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.find
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.search
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
9
19
|
|
|
10
20
|
cached_finders_for :foo, :expires_in => 500
|
|
11
21
|
cached_finders_for :guid
|
|
12
22
|
cached_finders_for :guid, :user_guid
|
|
13
|
-
cached_finders_for [
|
|
14
|
-
cached_finders_for [
|
|
23
|
+
cached_finders_for %i[user_guid client_guid]
|
|
24
|
+
cached_finders_for %i[derp user_guid client_guid]
|
|
25
|
+
cached_finders_for %i[zippy123 alpha]
|
|
15
26
|
end
|
|
16
27
|
|
|
17
28
|
describe SearchMethodClass do
|
|
18
|
-
|
|
29
|
+
let(:versioned_prefix) { ::ActiveRemote::Cached::RUBY_AND_ACTIVE_SUPPORT_VERSION }
|
|
30
|
+
|
|
31
|
+
describe 'API' do
|
|
19
32
|
it "creates 'cached_search_by_foo'" do
|
|
20
|
-
SearchMethodClass.
|
|
33
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_foo)
|
|
21
34
|
end
|
|
22
35
|
|
|
23
36
|
it "creates 'cached_search_by_foo!'" do
|
|
24
|
-
SearchMethodClass.
|
|
37
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_foo!)
|
|
25
38
|
end
|
|
26
39
|
|
|
27
40
|
it "creates 'cached_search_by_guid'" do
|
|
28
|
-
SearchMethodClass.
|
|
41
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_guid)
|
|
29
42
|
end
|
|
30
43
|
|
|
31
44
|
it "creates 'cached_search_by_user_guid'" do
|
|
32
|
-
SearchMethodClass.
|
|
45
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_user_guid)
|
|
33
46
|
end
|
|
34
47
|
|
|
35
48
|
it "creates 'cached_search_by_user_guid_and_client_guid'" do
|
|
36
|
-
SearchMethodClass.
|
|
49
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_user_guid_and_client_guid)
|
|
37
50
|
end
|
|
38
51
|
|
|
39
52
|
it "creates 'cached_search_by_client_guid_and_user_guid'" do
|
|
40
|
-
SearchMethodClass.
|
|
53
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_client_guid_and_user_guid)
|
|
41
54
|
end
|
|
42
55
|
|
|
43
56
|
it "creates 'cached_search_by_derp_and_user_guid_and_client_guid'" do
|
|
44
|
-
SearchMethodClass.
|
|
57
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_derp_and_user_guid_and_client_guid)
|
|
45
58
|
end
|
|
46
59
|
|
|
47
60
|
it "creates 'cached_search_by_client_guid_and_derp_and_user_guid'" do
|
|
48
|
-
SearchMethodClass.
|
|
61
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_client_guid_and_derp_and_user_guid)
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
it "creates 'cached_search_by_client_guid_and_user_guid_and_derp'" do
|
|
52
|
-
SearchMethodClass.
|
|
65
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_client_guid_and_user_guid_and_derp)
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
it "creates 'cached_search_by_client_guid_and_user_guid_and_derp!'" do
|
|
56
|
-
SearchMethodClass.
|
|
69
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_client_guid_and_user_guid_and_derp!)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Ensure it works with numbers in method name
|
|
73
|
+
it "creates 'cached_search_by_alpha_and_zippy123'" do
|
|
74
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_alpha_and_zippy123)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Ensure it responds to methods where params are not sorted
|
|
78
|
+
# i.e. the method missing override is used.
|
|
79
|
+
it "responds to 'cached_search_by_zippy123_and_alpha'" do
|
|
80
|
+
expect(SearchMethodClass).to respond_to(:cached_search_by_zippy123_and_alpha)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Ensure the right method actually gets called when
|
|
84
|
+
# method_missing override is used.
|
|
85
|
+
it "can call 'cached_search_by_zippy123_and_alpha' when not defined" do
|
|
86
|
+
expect(SearchMethodClass).to receive(:search)
|
|
87
|
+
SearchMethodClass.cached_search_by_zippy123_and_alpha('abc', '123')
|
|
57
88
|
end
|
|
58
89
|
end
|
|
59
90
|
|
|
60
|
-
describe
|
|
91
|
+
describe '#cached_search_by_guid' do
|
|
61
92
|
before do
|
|
62
93
|
::ActiveRemote::Cached.cache(HashCache.new)
|
|
63
94
|
::ActiveRemote::Cached.default_options(:expires_in => 100)
|
|
@@ -67,108 +98,105 @@ describe SearchMethodClass do
|
|
|
67
98
|
::ActiveRemote::Cached.default_options({})
|
|
68
99
|
end
|
|
69
100
|
|
|
70
|
-
it
|
|
71
|
-
SearchMethodClass.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
end
|
|
101
|
+
it 'executes the search block when a block is passed' do
|
|
102
|
+
expect(SearchMethodClass).to receive(:derp).and_return(:derp)
|
|
103
|
+
expect(SearchMethodClass.cached_search(:guid => :guid) do
|
|
104
|
+
SearchMethodClass.derp
|
|
105
|
+
end).to eq(:derp)
|
|
76
106
|
end
|
|
77
107
|
|
|
78
|
-
it
|
|
79
|
-
SearchMethodClass.
|
|
80
|
-
SearchMethodClass.cached_search(:guid => :guid) do
|
|
81
|
-
SearchMethodClass.derp
|
|
82
|
-
end
|
|
108
|
+
it 'does not persist empty values by default' do
|
|
109
|
+
expect(SearchMethodClass).to receive(:derp).and_return([])
|
|
83
110
|
|
|
84
|
-
|
|
111
|
+
SearchMethodClass.cached_search(:guid => :guid) do
|
|
112
|
+
SearchMethodClass.derp
|
|
85
113
|
end
|
|
86
|
-
end
|
|
87
114
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
SearchMethodClass.cached_search({:guid => :guid}, :allow_empty => true) do
|
|
91
|
-
SearchMethodClass.derp
|
|
92
|
-
end
|
|
115
|
+
expect(SearchMethodClass.cached_exist_search_by_guid?(:guid)).to eq(false)
|
|
116
|
+
end
|
|
93
117
|
|
|
94
|
-
|
|
118
|
+
it 'persists empty values when allow_empty sent' do
|
|
119
|
+
expect(SearchMethodClass).to receive(:derp).and_return([])
|
|
120
|
+
SearchMethodClass.cached_search({ :guid => :guid }, :allow_empty => true) do
|
|
121
|
+
SearchMethodClass.derp
|
|
95
122
|
end
|
|
96
|
-
end
|
|
97
123
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
SearchMethodClass.cached_search(:guid => :guid) do
|
|
101
|
-
SearchMethodClass.derp
|
|
102
|
-
end
|
|
124
|
+
expect(SearchMethodClass.cached_exist_search_by_guid?(:guid)).to eq(true)
|
|
125
|
+
end
|
|
103
126
|
|
|
104
|
-
|
|
127
|
+
it 'does not persist nil values by default' do
|
|
128
|
+
expect(SearchMethodClass).to receive(:derp).and_return(nil)
|
|
129
|
+
SearchMethodClass.cached_search(:guid => :guid) do
|
|
130
|
+
SearchMethodClass.derp
|
|
105
131
|
end
|
|
106
|
-
end
|
|
107
132
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
SearchMethodClass.cached_search({:guid => :guid}, :allow_nil => true) do
|
|
111
|
-
SearchMethodClass.derp
|
|
112
|
-
end
|
|
133
|
+
expect(SearchMethodClass.cached_exist_search_by_guid?(:guid)).to eq(false)
|
|
134
|
+
end
|
|
113
135
|
|
|
114
|
-
|
|
136
|
+
it 'persists nil values when allow_nil sent' do
|
|
137
|
+
expect(SearchMethodClass).to receive(:derp).and_return(nil)
|
|
138
|
+
SearchMethodClass.cached_search({ :guid => :guid }, :allow_nil => true) do
|
|
139
|
+
SearchMethodClass.derp
|
|
115
140
|
end
|
|
116
|
-
end
|
|
117
141
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
SearchMethodClass.cached_search(:guid => :guid) do
|
|
121
|
-
SearchMethodClass.derp
|
|
122
|
-
end
|
|
142
|
+
expect(SearchMethodClass.cached_exist_search_by_guid?(:guid)).to eq(true)
|
|
143
|
+
end
|
|
123
144
|
|
|
124
|
-
|
|
145
|
+
it 'does persist non nil values' do
|
|
146
|
+
expect(SearchMethodClass).to receive(:derp).and_return(:derp)
|
|
147
|
+
SearchMethodClass.cached_search(:guid => :guid) do
|
|
148
|
+
SearchMethodClass.derp
|
|
125
149
|
end
|
|
150
|
+
|
|
151
|
+
expect(SearchMethodClass.cached_exist_search_by_guid?(:guid)).to eq(true)
|
|
126
152
|
end
|
|
127
153
|
|
|
128
|
-
it
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
154
|
+
it 'executes search_by_guid when cached_search with guid called' do
|
|
155
|
+
expect(SearchMethodClass).to receive(:search).and_return(:hello)
|
|
156
|
+
|
|
157
|
+
expect(SearchMethodClass.cached_search(:guid => :guid)).to eq(:hello)
|
|
132
158
|
end
|
|
133
159
|
|
|
134
|
-
it
|
|
135
|
-
SearchMethodClass.
|
|
136
|
-
|
|
137
|
-
end
|
|
160
|
+
it 'executes the fetch block if not present in cache' do
|
|
161
|
+
expect(SearchMethodClass).to receive(:search).and_return(:hello)
|
|
162
|
+
expect(SearchMethodClass.cached_search_by_guid(:guid)).to eq(:hello)
|
|
138
163
|
end
|
|
139
164
|
|
|
140
|
-
it
|
|
141
|
-
::ActiveRemote::Cached.cache.
|
|
165
|
+
it 'merges the default options in for the fetch call' do
|
|
166
|
+
expect(::ActiveRemote::Cached.cache).to receive(:fetch).with(
|
|
167
|
+
[versioned_prefix, SearchMethodClass.name, '#search', 'guid.guid'], { :expires_in => 100 }
|
|
168
|
+
).and_return(:hello)
|
|
142
169
|
|
|
143
|
-
SearchMethodClass.
|
|
144
|
-
|
|
145
|
-
end
|
|
170
|
+
expect(SearchMethodClass).not_to receive(:search)
|
|
171
|
+
expect(SearchMethodClass.cached_search_by_guid(:guid)).to eq(:hello)
|
|
146
172
|
end
|
|
147
173
|
|
|
148
|
-
it
|
|
149
|
-
::ActiveRemote::Cached.cache.
|
|
174
|
+
it 'overrides the default options with local options for the fetch call' do
|
|
175
|
+
expect(::ActiveRemote::Cached.cache).to receive(:fetch).with(
|
|
176
|
+
[versioned_prefix, SearchMethodClass.name, '#search', 'guid.guid'], { :expires_in => 200 }
|
|
177
|
+
).and_return(:hello)
|
|
150
178
|
|
|
151
|
-
SearchMethodClass.
|
|
152
|
-
|
|
153
|
-
end
|
|
179
|
+
expect(SearchMethodClass).not_to receive(:search)
|
|
180
|
+
expect(SearchMethodClass.cached_search_by_guid(:guid, { :expires_in => 200 })).to eq(:hello)
|
|
154
181
|
end
|
|
155
182
|
|
|
156
|
-
describe
|
|
183
|
+
describe 'namespaced cache' do
|
|
157
184
|
before do
|
|
158
|
-
::ActiveRemote::Cached.default_options(:expires_in => 100, :namespace =>
|
|
185
|
+
::ActiveRemote::Cached.default_options(:expires_in => 100, :namespace => 'MyApp')
|
|
159
186
|
end
|
|
160
187
|
|
|
161
|
-
it
|
|
162
|
-
::ActiveRemote::Cached.cache.
|
|
188
|
+
it 'uses the namespace as a prefix to the cache key' do
|
|
189
|
+
expect(::ActiveRemote::Cached.cache).to receive(:fetch).with(
|
|
190
|
+
[versioned_prefix, 'MyApp', SearchMethodClass.name, '#search', 'guid.guid'], { :expires_in => 100 }
|
|
191
|
+
).and_return(:hello)
|
|
163
192
|
|
|
164
|
-
SearchMethodClass.
|
|
165
|
-
|
|
166
|
-
end
|
|
193
|
+
expect(SearchMethodClass).not_to receive(:search)
|
|
194
|
+
SearchMethodClass.cached_search_by_guid(:guid)
|
|
167
195
|
end
|
|
168
196
|
end
|
|
169
197
|
end
|
|
170
198
|
|
|
171
|
-
describe
|
|
199
|
+
describe '#cached_search_by_foo' do
|
|
172
200
|
before do
|
|
173
201
|
::ActiveRemote::Cached.cache(HashCache.new)
|
|
174
202
|
::ActiveRemote::Cached.default_options(:expires_in => 100)
|
|
@@ -178,24 +206,26 @@ describe SearchMethodClass do
|
|
|
178
206
|
::ActiveRemote::Cached.default_options({})
|
|
179
207
|
end
|
|
180
208
|
|
|
181
|
-
it
|
|
182
|
-
::ActiveRemote::Cached.cache.
|
|
209
|
+
it 'overrides the default options with cached_finder options for the fetch call' do
|
|
210
|
+
expect(::ActiveRemote::Cached.cache).to receive(:fetch).with(
|
|
211
|
+
[versioned_prefix, SearchMethodClass.name, '#search', 'foo.foo'], { :expires_in => 500 }
|
|
212
|
+
).and_return(:hello)
|
|
183
213
|
|
|
184
|
-
SearchMethodClass.
|
|
185
|
-
|
|
186
|
-
end
|
|
214
|
+
expect(SearchMethodClass).not_to receive(:find)
|
|
215
|
+
expect(SearchMethodClass.cached_search_by_foo(:foo)).to eq(:hello)
|
|
187
216
|
end
|
|
188
217
|
|
|
189
|
-
it
|
|
190
|
-
::ActiveRemote::Cached.cache.
|
|
218
|
+
it 'overrides the cached_finder options with local options for the fetch call' do
|
|
219
|
+
expect(::ActiveRemote::Cached.cache).to receive(:fetch).with(
|
|
220
|
+
[versioned_prefix, SearchMethodClass.name, '#search', 'foo.foo'], { :expires_in => 200 }
|
|
221
|
+
).and_return(:hello)
|
|
191
222
|
|
|
192
|
-
SearchMethodClass.
|
|
193
|
-
|
|
194
|
-
end
|
|
223
|
+
expect(SearchMethodClass).not_to receive(:find)
|
|
224
|
+
expect(SearchMethodClass.cached_search_by_foo(:foo, :expires_in => 200)).to eq(:hello)
|
|
195
225
|
end
|
|
196
226
|
end
|
|
197
227
|
|
|
198
|
-
describe
|
|
228
|
+
describe '#cached_search_by_foo!' do
|
|
199
229
|
before do
|
|
200
230
|
::ActiveRemote::Cached.cache(HashCache.new)
|
|
201
231
|
::ActiveRemote::Cached.default_options(:expires_in => 100)
|
|
@@ -205,16 +235,86 @@ describe SearchMethodClass do
|
|
|
205
235
|
::ActiveRemote::Cached.default_options({})
|
|
206
236
|
end
|
|
207
237
|
|
|
208
|
-
it
|
|
209
|
-
SearchMethodClass.
|
|
210
|
-
|
|
211
|
-
end
|
|
238
|
+
it 'and_return results when present' do
|
|
239
|
+
expect(SearchMethodClass).to receive(:search).and_return([:hello])
|
|
240
|
+
expect(SearchMethodClass.cached_search_by_foo!(:foo, :expires_in => 200)).to eq([:hello])
|
|
212
241
|
end
|
|
213
242
|
|
|
214
|
-
it
|
|
215
|
-
SearchMethodClass.
|
|
216
|
-
|
|
217
|
-
|
|
243
|
+
it 'raises ActiveRemote::RemoteRecordNotFound when not found' do
|
|
244
|
+
expect(SearchMethodClass).to receive(:search).and_return([])
|
|
245
|
+
expect do
|
|
246
|
+
SearchMethodClass.cached_search_by_foo!(:foo, :expires_in => 200)
|
|
247
|
+
end.to raise_error ::ActiveRemote::RemoteRecordNotFound
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it 'raises ActiveRemote::RemoteRecordNotFound when the block returns no results' do
|
|
251
|
+
expect(SearchMethodClass).not_to receive(:search)
|
|
252
|
+
expect do
|
|
253
|
+
SearchMethodClass.cached_search_by_foo!(:foo) { [] }
|
|
254
|
+
end.to raise_error ::ActiveRemote::RemoteRecordNotFound
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it 'raises ActiveRemote::RemoteRecordNotFound when the first result is nil' do
|
|
258
|
+
expect(SearchMethodClass).not_to receive(:search)
|
|
259
|
+
expect do
|
|
260
|
+
SearchMethodClass.cached_search_by_foo!(:foo) { [nil] }
|
|
261
|
+
end.to raise_error ::ActiveRemote::RemoteRecordNotFound
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it 'raises ActiveRemote::RemoteRecordNotFound when the results are nil' do
|
|
265
|
+
expect(SearchMethodClass).to receive(:search).and_return(nil)
|
|
266
|
+
expect do
|
|
267
|
+
SearchMethodClass.cached_search_by_foo!(:foo)
|
|
268
|
+
end.to raise_error ::ActiveRemote::RemoteRecordNotFound
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it 'names the model class in the error' do
|
|
272
|
+
expect(SearchMethodClass).to receive(:search).and_return([])
|
|
273
|
+
expect do
|
|
274
|
+
SearchMethodClass.cached_search_by_foo!(:foo)
|
|
275
|
+
end.to raise_error(::ActiveRemote::RemoteRecordNotFound, /SearchMethodClass/)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'reports the model class on the error' do
|
|
279
|
+
expect(SearchMethodClass).to receive(:search).and_return([])
|
|
280
|
+
|
|
281
|
+
SearchMethodClass.cached_search_by_foo!(:foo)
|
|
282
|
+
rescue ::ActiveRemote::RemoteRecordNotFound => e
|
|
283
|
+
expect(e.remote_record_class).to eq(SearchMethodClass)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it 'does not cache the results when it raises' do
|
|
287
|
+
expect do
|
|
288
|
+
SearchMethodClass.cached_search_by_foo!(:foo) { [] }
|
|
289
|
+
end.to raise_error ::ActiveRemote::RemoteRecordNotFound
|
|
290
|
+
|
|
291
|
+
expect(SearchMethodClass.cached_exist_search_by_foo?(:foo)).to eq(false)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'caches the results when they are present' do
|
|
295
|
+
expect(SearchMethodClass).to receive(:search).once.and_return([:hello])
|
|
296
|
+
|
|
297
|
+
expect(SearchMethodClass.cached_search_by_foo!(:foo)).to eq([:hello])
|
|
298
|
+
expect(SearchMethodClass.cached_search_by_foo!(:foo)).to eq([:hello])
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# This tests the method_missing override
|
|
303
|
+
describe '#cached_search_by_zippy123_and_alpha' do
|
|
304
|
+
before do
|
|
305
|
+
::ActiveRemote::Cached.cache(HashCache.new)
|
|
306
|
+
::ActiveRemote::Cached.default_options(:expires_in => 100)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
after do
|
|
310
|
+
::ActiveRemote::Cached.default_options({})
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it 'calls the underlying method with params in correct order' do
|
|
314
|
+
expect(SearchMethodClass).to receive(:cached_search_by_alpha_and_zippy123).with('123', 'abc').and_return(:hello)
|
|
315
|
+
|
|
316
|
+
# Calls method that does not exist (different param order)
|
|
317
|
+
expect(SearchMethodClass.cached_search_by_zippy123_and_alpha('abc', '123')).to eq(:hello)
|
|
218
318
|
end
|
|
219
319
|
end
|
|
220
320
|
end
|