couch_potato 1.14.0 → 1.15.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/CHANGES.md +5 -0
- data/lib/couch_potato/database.rb +50 -21
- data/lib/couch_potato/version.rb +1 -1
- data/spec/unit/caching_spec.rb +76 -25
- data/spec/unit/database_spec.rb +12 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffcaae6b2815d237b48cc3e4ad553f66920fe4df2c84c59ae38177260949ba6b
|
4
|
+
data.tar.gz: bd266a1033fa83fcba822a19e3de86b2c1aac2d80ba2dd1d3aef0920d4819d8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16f3e1748e3b3314f1cf3d658fb175dd90c5e7c7cd717ab42477961c364bac527b262642a29f208c4aad200e9a31ce7470c0a538db8bf8d641e13da92f85debb
|
7
|
+
data.tar.gz: '089f1c9e5dc7238b659a4d1b2d0f3d341a084fe52f6d9c2d058ea8440f197f7d64b6f5a9d78c8cebbd19b131aede038329ab6c0f79b503d220f1f20d2e7d8a20'
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/core_ext/enumerable'
|
4
|
+
|
3
5
|
module CouchPotato
|
4
6
|
class Database
|
5
7
|
class ValidationsFailedError < ::StandardError; end
|
@@ -143,7 +145,9 @@ module CouchPotato
|
|
143
145
|
# returns nil if the single document could not be found. when passing an array and some documents
|
144
146
|
# could not be found these are omitted from the returned array
|
145
147
|
def load_document(id)
|
146
|
-
|
148
|
+
return load_documents(id) if id.is_a?(Array)
|
149
|
+
|
150
|
+
cached = cache && cache[id]
|
147
151
|
if cache
|
148
152
|
if cached
|
149
153
|
ActiveSupport::Notifications.instrument('couch_potato.load.cached') do
|
@@ -159,6 +163,23 @@ module CouchPotato
|
|
159
163
|
end
|
160
164
|
alias load load_document
|
161
165
|
|
166
|
+
def load_documents(ids)
|
167
|
+
return [] if ids.empty?
|
168
|
+
|
169
|
+
uncached_ids = ids - (cache&.keys || [])
|
170
|
+
uncached_docs_by_id = bulk_load(uncached_ids).index_by {|doc| doc.id if doc.respond_to?(:id) }
|
171
|
+
if cache
|
172
|
+
uncached_ids.each do |id|
|
173
|
+
doc = uncached_docs_by_id[id]
|
174
|
+
cache[id] = doc if doc
|
175
|
+
end
|
176
|
+
end
|
177
|
+
cached_docs_by_id = ActiveSupport::Notifications.instrument('couch_potato.load.cached') do
|
178
|
+
cache&.slice(*ids) || {}
|
179
|
+
end
|
180
|
+
ids.filter_map { |id| (cached_docs_by_id[id]) || uncached_docs_by_id[id] }
|
181
|
+
end
|
182
|
+
|
162
183
|
# loads one or more documents by its id(s)
|
163
184
|
# behaves like #load except it raises a CouchPotato::NotFound if any of the documents could not be found
|
164
185
|
def load!(id)
|
@@ -176,6 +197,8 @@ module CouchPotato
|
|
176
197
|
# returns the underlying CouchRest::Database instance
|
177
198
|
attr_reader :couchrest_database
|
178
199
|
|
200
|
+
attr_accessor :switched_databases
|
201
|
+
|
179
202
|
# returns a new database instance connected to the CouchDB database
|
180
203
|
# with the given name. the name is passed through the
|
181
204
|
# additional_databases configuration to resolve it to a database
|
@@ -183,21 +206,29 @@ module CouchPotato
|
|
183
206
|
# if the current database has a cache, the new database will receive
|
184
207
|
# a cleared copy of it.
|
185
208
|
def switch_to(database_name)
|
186
|
-
|
187
|
-
|
209
|
+
self.switched_databases ||= {}
|
210
|
+
if (db = switched_databases[database_name || :default])
|
211
|
+
return db
|
212
|
+
end
|
213
|
+
switched_databases[name || :default] ||= self
|
214
|
+
|
215
|
+
|
216
|
+
resolved_database_name = CouchPotato.resolve_database_name(database_name) unless database_name == :default
|
217
|
+
couchrest_database = resolved_database_name ? CouchPotato.couchrest_database_for_name(resolved_database_name) : CouchPotato.couchrest_database
|
218
|
+
new_db = self
|
188
219
|
.class
|
189
|
-
.new(
|
220
|
+
.new(couchrest_database, name: database_name == :default ? nil : database_name)
|
190
221
|
.tap(©_clear_cache_proc)
|
222
|
+
|
223
|
+
new_db.switched_databases = switched_databases
|
224
|
+
new_db
|
191
225
|
end
|
192
226
|
|
193
227
|
# returns a new database instance connected to the default CouchDB database.
|
194
228
|
# if the current database has a cache, the new database will receive
|
195
229
|
# a cleared copy of it.
|
196
230
|
def switch_to_default
|
197
|
-
|
198
|
-
.class
|
199
|
-
.new(CouchPotato.couchrest_database)
|
200
|
-
.tap(©_clear_cache_proc)
|
231
|
+
switch_to(:default)
|
201
232
|
end
|
202
233
|
|
203
234
|
private
|
@@ -248,14 +279,10 @@ module CouchPotato
|
|
248
279
|
raise "Can't load a document without an id (got nil)" if id.nil?
|
249
280
|
|
250
281
|
ActiveSupport::Notifications.instrument('couch_potato.load') do
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
instance.database = self if instance
|
256
|
-
instance
|
257
|
-
end
|
258
|
-
end
|
282
|
+
instance = couchrest_database.get(id)
|
283
|
+
instance.database = self if instance
|
284
|
+
instance
|
285
|
+
end
|
259
286
|
end
|
260
287
|
|
261
288
|
def view_cache_id(spec)
|
@@ -294,11 +321,13 @@ module CouchPotato
|
|
294
321
|
def bulk_load(ids)
|
295
322
|
return [] if ids.empty?
|
296
323
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
324
|
+
ActiveSupport::Notifications.instrument('couch_potato.load') do
|
325
|
+
response = couchrest_database.bulk_load ids
|
326
|
+
docs = response['rows'].map { |row| row['doc'] }.compact
|
327
|
+
docs.each do |doc|
|
328
|
+
doc.database = self if doc.respond_to?(:database=)
|
329
|
+
doc.database_collection = docs if doc.respond_to?(:database_collection=)
|
330
|
+
end
|
302
331
|
end
|
303
332
|
end
|
304
333
|
|
data/lib/couch_potato/version.rb
CHANGED
data/spec/unit/caching_spec.rb
CHANGED
@@ -18,41 +18,92 @@ RSpec.describe 'database caching' do
|
|
18
18
|
{}
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
context 'for a single document' do
|
22
|
+
it 'gets an object from the cache the 2nd time via #load_documemt' do
|
23
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
db.load_document '1'
|
26
|
+
db.load_document '1'
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
it 'gets an object from the cache the 2nd time via #load' do
|
30
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
db.load '1'
|
33
|
+
db.load '1'
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
it 'gets an object from the cache the 2nd time via #load!' do
|
37
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
db.load! '1'
|
40
|
+
db.load! '1'
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
it 'returns the correct object' do
|
44
|
+
doc = double(:doc, 'database=': nil)
|
45
|
+
allow(couchrest_db).to receive_messages(get: doc)
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
db.load_document '1'
|
48
|
+
expect(db.load_document('1')).to eql(doc)
|
49
|
+
end
|
48
50
|
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
context 'for multiple documents' do
|
53
|
+
let(:doc1) { double(:doc1, 'database=': nil, id: '1') }
|
54
|
+
let(:doc2) { double(:doc12, 'database=': nil, id: '2') }
|
55
|
+
|
56
|
+
it 'only loads uncached documents' do
|
57
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1']).and_return('rows' => [{'doc' => doc1}])
|
58
|
+
allow(couchrest_db).to receive(:bulk_load).with(['2']).and_return('rows' => [{'doc' => doc2}])
|
59
|
+
|
60
|
+
|
61
|
+
db.load_document(['1'])
|
62
|
+
db.load_document(['1', '2'])
|
63
|
+
|
64
|
+
expect(couchrest_db).to have_received(:bulk_load).with(['1']).exactly(1).times
|
65
|
+
expect(couchrest_db).to have_received(:bulk_load).with(['2']).exactly(1).times
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'loads nothing if all documents are cached' do
|
69
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1', '2'])
|
70
|
+
.and_return('rows' => [{'doc' => doc1}, {'doc' => doc2}])
|
71
|
+
|
72
|
+
db.load_document(['1', '2'])
|
73
|
+
db.load_document(['1', '2'])
|
74
|
+
|
75
|
+
expect(couchrest_db).to have_received(:bulk_load).with(['1', '2']).exactly(1).times
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns all requested documents' do
|
79
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1']).and_return('rows' => [{'doc' => doc1}])
|
80
|
+
allow(couchrest_db).to receive(:bulk_load).with(['2']).and_return('rows' => [{'doc' => doc2}])
|
81
|
+
|
82
|
+
|
83
|
+
db.load_document(['1'])
|
84
|
+
result = db.load_document(['1', '2'])
|
85
|
+
|
86
|
+
expect(result).to eql([doc1, doc2])
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'does not cache documents that do not respond to id' do
|
90
|
+
doc1 = {
|
91
|
+
'id' => '1',
|
92
|
+
}
|
93
|
+
doc2 = {
|
94
|
+
'id' => '2',
|
95
|
+
}
|
96
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1', '2'])
|
97
|
+
.and_return('rows' => [{'doc' => doc1}, {'doc' => doc1}])
|
98
|
+
|
99
|
+
db.load_document(['1', '2'])
|
100
|
+
db.load_document(['1', '2'])
|
101
|
+
|
102
|
+
expect(couchrest_db).to have_received(:bulk_load).with(['1', '2']).exactly(2).times
|
103
|
+
end
|
104
|
+
end
|
53
105
|
|
54
|
-
|
55
|
-
db.load_document ['1']
|
106
|
+
context 'when switching the database' do
|
56
107
|
end
|
57
108
|
|
58
109
|
it 'clears the cache when destroying a document via #destroy_document' do
|
data/spec/unit/database_spec.rb
CHANGED
@@ -72,8 +72,8 @@ describe CouchPotato::Database, 'load' do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
context 'when several ids given' do
|
75
|
-
let(:doc1) { DbTestUser.new }
|
76
|
-
let(:doc2) { DbTestUser.new }
|
75
|
+
let(:doc1) { DbTestUser.new(id: '1') }
|
76
|
+
let(:doc2) { DbTestUser.new(id: '2') }
|
77
77
|
let(:response) do
|
78
78
|
{ 'rows' => [{ 'doc' => nil }, { 'doc' => doc1 }, { 'doc' => doc2 }] }
|
79
79
|
end
|
@@ -98,7 +98,7 @@ describe CouchPotato::Database, 'load' do
|
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'does not write itself to a document that has no database= method' do
|
101
|
-
doc1 = double(:doc1)
|
101
|
+
doc1 = double(:doc1, id: '1')
|
102
102
|
allow(doc1).to receive(:respond_to?) { false }
|
103
103
|
allow(couchrest_db).to receive(:bulk_load) do
|
104
104
|
{ 'rows' => [{ 'doc' => doc1 }] }
|
@@ -116,7 +116,7 @@ describe CouchPotato::Database, 'load' do
|
|
116
116
|
end
|
117
117
|
|
118
118
|
it 'does not set database_collection on a document that has no database_collection= method' do
|
119
|
-
doc1 = double(:doc1)
|
119
|
+
doc1 = double(:doc1, id: '1')
|
120
120
|
allow(doc1).to receive(:respond_to?) { false }
|
121
121
|
allow(couchrest_db).to receive(:bulk_load) do
|
122
122
|
{ 'rows' => [{ 'doc' => doc1 }] }
|
@@ -571,6 +571,14 @@ describe CouchPotato::Database, '#switch_to' do
|
|
571
571
|
|
572
572
|
expect(new_db.cache).to be_nil
|
573
573
|
end
|
574
|
+
|
575
|
+
it 're-uses the original cache when switching back to the original database' do
|
576
|
+
db.cache = { key: 'value' }
|
577
|
+
new_db = db.switch_to('db2')
|
578
|
+
original_db = new_db.switch_to_default
|
579
|
+
|
580
|
+
expect(original_db.cache).to have_key(:key)
|
581
|
+
end
|
574
582
|
end
|
575
583
|
|
576
584
|
describe CouchPotato::Database, '#switch_to_default' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_potato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Lang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|