couch_potato 1.15.0 → 1.17.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 +10 -0
- data/lib/couch_potato/database.rb +17 -9
- data/lib/couch_potato/persistence/ghost_attributes.rb +7 -3
- data/lib/couch_potato/version.rb +1 -1
- data/spec/unit/caching_spec.rb +72 -16
- data/spec/unit/database_spec.rb +51 -0
- 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: a78d19f65a75932bb6f60639fc9ad3dff0151e9c7de7f8cbc31e1b61038f7fa8
|
4
|
+
data.tar.gz: c5383ffd3db50bd45d727a84b62588dcd70d6ea3d07ac96559e1318c145fb057
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38aa7ce10b0f12429789ecc0f25e34b276f98eadedac900f2ea18b7c1845549be28becb624d4da1c89506d814fa403b7f9647f960f3be534ac47b02c839f6866
|
7
|
+
data.tar.gz: e0b48a96f9a485d0765b066b5e5bca043058b85af246775abdf2bf3afb598bf691b09ae156182b9ecf1ff9dcc0acdee3bb5cc899a8722d0a75bdff9ded965b7b
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## Changes
|
2
2
|
|
3
|
+
# 1.17.0
|
4
|
+
|
5
|
+
- filter out nil ids for loading multiple documents
|
6
|
+
- cache nil documents
|
7
|
+
|
8
|
+
# 1.16.0
|
9
|
+
|
10
|
+
- add payload to ActiveSupport instrumentation calls
|
11
|
+
- only notify load.cached when there are cached documents
|
12
|
+
|
3
13
|
# 1.15.0
|
4
14
|
|
5
15
|
- cache loading multiple documents
|
@@ -149,8 +149,8 @@ module CouchPotato
|
|
149
149
|
|
150
150
|
cached = cache && cache[id]
|
151
151
|
if cache
|
152
|
-
if
|
153
|
-
ActiveSupport::Notifications.instrument('couch_potato.load.cached') do
|
152
|
+
if cache.key?(id)
|
153
|
+
ActiveSupport::Notifications.instrument('couch_potato.load.cached', id: id, doc: cached) do
|
154
154
|
cached
|
155
155
|
end
|
156
156
|
else
|
@@ -164,19 +164,23 @@ module CouchPotato
|
|
164
164
|
alias load load_document
|
165
165
|
|
166
166
|
def load_documents(ids)
|
167
|
+
ids = ids.compact
|
167
168
|
return [] if ids.empty?
|
168
169
|
|
169
170
|
uncached_ids = ids - (cache&.keys || [])
|
170
171
|
uncached_docs_by_id = bulk_load(uncached_ids).index_by {|doc| doc.id if doc.respond_to?(:id) }
|
172
|
+
cached_docs_by_id = cache&.slice(*ids) || {}
|
173
|
+
if cached_docs_by_id.any?
|
174
|
+
ActiveSupport::Notifications.instrument('couch_potato.load.cached', ids: cached_docs_by_id.keys, docs: cached_docs_by_id.values) do
|
175
|
+
cached_docs_by_id
|
176
|
+
end
|
177
|
+
end
|
171
178
|
if cache
|
172
179
|
uncached_ids.each do |id|
|
173
180
|
doc = uncached_docs_by_id[id]
|
174
|
-
cache[id] = doc
|
181
|
+
cache[id] = doc
|
175
182
|
end
|
176
183
|
end
|
177
|
-
cached_docs_by_id = ActiveSupport::Notifications.instrument('couch_potato.load.cached') do
|
178
|
-
cache&.slice(*ids) || {}
|
179
|
-
end
|
180
184
|
ids.filter_map { |id| (cached_docs_by_id[id]) || uncached_docs_by_id[id] }
|
181
185
|
end
|
182
186
|
|
@@ -278,9 +282,11 @@ module CouchPotato
|
|
278
282
|
def load_document_without_caching(id)
|
279
283
|
raise "Can't load a document without an id (got nil)" if id.nil?
|
280
284
|
|
281
|
-
|
285
|
+
payload = {id: id}
|
286
|
+
ActiveSupport::Notifications.instrument('couch_potato.load', payload) do
|
282
287
|
instance = couchrest_database.get(id)
|
283
288
|
instance.database = self if instance
|
289
|
+
payload[:doc] = instance
|
284
290
|
instance
|
285
291
|
end
|
286
292
|
end
|
@@ -321,9 +327,11 @@ module CouchPotato
|
|
321
327
|
def bulk_load(ids)
|
322
328
|
return [] if ids.empty?
|
323
329
|
|
324
|
-
|
330
|
+
payload = {ids: ids}
|
331
|
+
ActiveSupport::Notifications.instrument('couch_potato.load', payload) do
|
325
332
|
response = couchrest_database.bulk_load ids
|
326
|
-
docs = response[
|
333
|
+
docs = response["rows"].map { |row| row["doc"] }.compact
|
334
|
+
payload[:docs] = docs
|
327
335
|
docs.each do |doc|
|
328
336
|
doc.database = self if doc.respond_to?(:database=)
|
329
337
|
doc.database_collection = docs if doc.respond_to?(:database_collection=)
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module CouchPotato
|
2
|
-
module GhostAttributes
|
3
|
-
def method_missing(name, *
|
4
|
-
if(value = _document && _document[name.to_s])
|
2
|
+
module GhostAttributes # :nodoc:
|
3
|
+
def method_missing(name, *)
|
4
|
+
if (value = _document && _document[name.to_s])
|
5
5
|
value
|
6
6
|
else
|
7
7
|
super
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
def respond_to_missing?(name, *)
|
12
|
+
_document && _document[name.to_s]
|
13
|
+
end
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
data/lib/couch_potato/version.rb
CHANGED
data/spec/unit/caching_spec.rb
CHANGED
@@ -18,6 +18,10 @@ RSpec.describe 'database caching' do
|
|
18
18
|
{}
|
19
19
|
end
|
20
20
|
|
21
|
+
after(:each) do
|
22
|
+
ActiveSupport::Notifications.unsubscribe(@subscriber) if @subscriber
|
23
|
+
end
|
24
|
+
|
21
25
|
context 'for a single document' do
|
22
26
|
it 'gets an object from the cache the 2nd time via #load_documemt' do
|
23
27
|
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
@@ -33,6 +37,15 @@ RSpec.describe 'database caching' do
|
|
33
37
|
db.load '1'
|
34
38
|
end
|
35
39
|
|
40
|
+
it 'caches nil' do
|
41
|
+
allow(couchrest_db).to receive(:get).with('1').and_return(nil)
|
42
|
+
|
43
|
+
db.load '1'
|
44
|
+
db.load '1'
|
45
|
+
|
46
|
+
expect(couchrest_db).to have_received(:get).with('1').exactly(1).times
|
47
|
+
end
|
48
|
+
|
36
49
|
it 'gets an object from the cache the 2nd time via #load!' do
|
37
50
|
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
38
51
|
|
@@ -47,6 +60,29 @@ RSpec.describe 'database caching' do
|
|
47
60
|
db.load_document '1'
|
48
61
|
expect(db.load_document('1')).to eql(doc)
|
49
62
|
end
|
63
|
+
|
64
|
+
it 'instruments the load call' do
|
65
|
+
doc = double("doc").as_null_object
|
66
|
+
allow(couchrest_db).to receive(:get).and_return(doc)
|
67
|
+
events = []
|
68
|
+
@subscriber = ActiveSupport::Notifications.subscribe(
|
69
|
+
'couch_potato.load.cached'
|
70
|
+
) do |event|
|
71
|
+
events << event
|
72
|
+
end
|
73
|
+
|
74
|
+
db.load("1")
|
75
|
+
db.load("1")
|
76
|
+
|
77
|
+
expect(events.size).to eq(1)
|
78
|
+
expect(events.first.payload).to eq(
|
79
|
+
{
|
80
|
+
id: "1",
|
81
|
+
doc: doc
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
end
|
50
86
|
end
|
51
87
|
|
52
88
|
context 'for multiple documents' do
|
@@ -65,6 +101,42 @@ RSpec.describe 'database caching' do
|
|
65
101
|
expect(couchrest_db).to have_received(:bulk_load).with(['2']).exactly(1).times
|
66
102
|
end
|
67
103
|
|
104
|
+
it 'caches nil' do
|
105
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1']).and_return('rows' => [{'doc' => nil}])
|
106
|
+
allow(couchrest_db).to receive(:bulk_load).with(['2']).and_return('rows' => [{'doc' => doc2}])
|
107
|
+
|
108
|
+
|
109
|
+
db.load_document(['1'])
|
110
|
+
db.load_document(['1', '2'])
|
111
|
+
|
112
|
+
expect(couchrest_db).to have_received(:bulk_load).with(['1']).exactly(1).times
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'instruments the load call' do
|
116
|
+
allow(couchrest_db).to receive(:bulk_load).with(['1'])
|
117
|
+
.and_return('rows' => [{'doc' => doc1}])
|
118
|
+
allow(couchrest_db).to receive(:bulk_load).with(['2'])
|
119
|
+
.and_return('rows' => [{'doc' => doc2}])
|
120
|
+
events = []
|
121
|
+
@subscriber = ActiveSupport::Notifications.subscribe(
|
122
|
+
'couch_potato.load.cached'
|
123
|
+
) do |event|
|
124
|
+
events << event
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
db.load_document(['1'])
|
129
|
+
db.load_document(['1', '2'])
|
130
|
+
|
131
|
+
expect(events.size).to eq(1)
|
132
|
+
expect(events.first.payload).to eq(
|
133
|
+
{
|
134
|
+
ids: ["1"],
|
135
|
+
docs: [doc1]
|
136
|
+
}
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
68
140
|
it 'loads nothing if all documents are cached' do
|
69
141
|
allow(couchrest_db).to receive(:bulk_load).with(['1', '2'])
|
70
142
|
.and_return('rows' => [{'doc' => doc1}, {'doc' => doc2}])
|
@@ -85,22 +157,6 @@ RSpec.describe 'database caching' do
|
|
85
157
|
|
86
158
|
expect(result).to eql([doc1, doc2])
|
87
159
|
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
160
|
end
|
105
161
|
|
106
162
|
context 'when switching the database' do
|
data/spec/unit/database_spec.rb
CHANGED
@@ -42,6 +42,11 @@ describe CouchPotato::Database, 'load' do
|
|
42
42
|
let(:couchrest_db) { double('couchrest db', info: nil).as_null_object }
|
43
43
|
let(:db) { CouchPotato::Database.new couchrest_db }
|
44
44
|
|
45
|
+
|
46
|
+
after(:each) do
|
47
|
+
ActiveSupport::Notifications.unsubscribe(@subscriber) if @subscriber
|
48
|
+
end
|
49
|
+
|
45
50
|
it 'should raise an exception if nil given' do
|
46
51
|
expect do
|
47
52
|
db.load nil
|
@@ -87,6 +92,12 @@ describe CouchPotato::Database, 'load' do
|
|
87
92
|
db.load %w[1 2 3]
|
88
93
|
end
|
89
94
|
|
95
|
+
it 'does not request anything when nil is given' do
|
96
|
+
expect(db.load([nil])).to eq([])
|
97
|
+
|
98
|
+
expect(couchrest_db).not_to have_received(:bulk_load)
|
99
|
+
end
|
100
|
+
|
90
101
|
it 'returns only found documents' do
|
91
102
|
expect(db.load(%w[1 2 3]).size).to eq(2)
|
92
103
|
end
|
@@ -130,6 +141,46 @@ describe CouchPotato::Database, 'load' do
|
|
130
141
|
it 'returns an empty array when passing an empty array' do
|
131
142
|
expect(db.load([])).to eq([])
|
132
143
|
end
|
144
|
+
|
145
|
+
it 'instruments the load call' do
|
146
|
+
events = []
|
147
|
+
@subscriber = ActiveSupport::Notifications.subscribe(
|
148
|
+
'couch_potato.load'
|
149
|
+
) do |event|
|
150
|
+
events << event
|
151
|
+
end
|
152
|
+
|
153
|
+
db.load(["1", "2"])
|
154
|
+
|
155
|
+
expect(events.size).to eq(1)
|
156
|
+
expect(events.first.payload).to eq(
|
157
|
+
{
|
158
|
+
ids: ["1", "2"],
|
159
|
+
docs: [doc1, doc2]
|
160
|
+
}
|
161
|
+
)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'instruments the load call' do
|
166
|
+
doc = double("doc").as_null_object
|
167
|
+
allow(couchrest_db).to receive(:get).and_return(doc)
|
168
|
+
events = []
|
169
|
+
@subscriber = ActiveSupport::Notifications.subscribe(
|
170
|
+
'couch_potato.load'
|
171
|
+
) do |event|
|
172
|
+
events << event
|
173
|
+
end
|
174
|
+
|
175
|
+
db.load("1")
|
176
|
+
|
177
|
+
expect(events.size).to eq(1)
|
178
|
+
expect(events.first.payload).to eq(
|
179
|
+
{
|
180
|
+
id: "1",
|
181
|
+
doc: doc
|
182
|
+
}
|
183
|
+
)
|
133
184
|
end
|
134
185
|
end
|
135
186
|
|
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.17.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-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|