couch_potato 1.10.1 → 1.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e0a3143ad59fbb9f3391e381841412de37afda869b90c3b105b3efe41859fa2
4
- data.tar.gz: 452e6d3cc546b0d45feb5ea94ea81779400adf6474e22580e6637d15f58858bb
3
+ metadata.gz: fc65386f8f391b222c93733fbf83cb00050bc37b2fa1787be8d73e4847b2fa43
4
+ data.tar.gz: a2c6fe4017c646b3bceaa9baaa236044ffe286fd3380095296a602034511d817
5
5
  SHA512:
6
- metadata.gz: f517b4ecfaf2c57eceade400298c68ef2d189f1274709c95f7bd54d97721b9131b79430956e5c517cd2fbd3781149ff9fe54c4640eaea8e82b940e97c696fd04
7
- data.tar.gz: a668623b7cd70ab1acb86aff299f8729f8645625b560f3b45247447117c9ac69d5aa335d57ff9dacaa980cd021d2f01f5e21c0a88f5faa45d5add8045e016e21
6
+ metadata.gz: 5f7c933270982e090183aacdb7fdd52e76e2739476e7e4d87cbcad1239c62b4973f31ce62278f181c33612bc6c2dc8ee7abbc2ffca0bef4560b919b8a37359c8
7
+ data.tar.gz: 7f79c9a6b3c31f5f1fc0eea3f4a16da6e7cb6ace5a68232a9a127d7d056b5144d88714e12e128a64eba34a9377e073311408077958c14b818c0f4037853a59a5
data/CHANGES.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## Changes
2
2
 
3
+ # 1.11.0
4
+
5
+ - improve view_in_batches performance by switching to using startkey_docid over skip
6
+
3
7
  ### 1.10.1
4
8
 
5
9
  - support passing an empty array to CouchPotato::Database#load
@@ -65,12 +65,27 @@ module CouchPotato
65
65
  # to a given block in batches of the given size, making multiple
66
66
  # requests with according skip/limit params sent to CouchDB.
67
67
  def view_in_batches(spec, batch_size: default_batch_size)
68
+ rows = nil
68
69
  batch = 0
69
70
  loop do
70
- spec.view_parameters = spec.view_parameters.merge({ skip: batch * batch_size, limit: batch_size })
71
- results = view(spec)
72
- yield results
73
- break if results.size < batch_size
71
+ spec.view_parameters = spec
72
+ .view_parameters
73
+ .merge({limit: batch_size})
74
+ .merge(
75
+ if rows
76
+ {
77
+ startkey: rows&.last&.dig('key'),
78
+ startkey_docid: rows&.last&.dig('id'),
79
+ skip: 1
80
+ }
81
+ else
82
+ {}
83
+ end
84
+ )
85
+ result = raw_view(spec)
86
+ rows = result['rows']
87
+ yield process_view_results(result, spec)
88
+ break if rows.size < batch_size
74
89
 
75
90
  batch += 1
76
91
  end
@@ -198,27 +213,34 @@ module CouchPotato
198
213
 
199
214
  def view_without_caching(spec)
200
215
  ActiveSupport::Notifications.instrument('couch_potato.view', name: "#{spec.design_document}/#{spec.view_name}") do
201
- results = CouchPotato::View::ViewQuery.new(
202
- couchrest_database,
203
- spec.design_document,
204
- { spec.view_name => {
205
- map: spec.map_function,
206
- reduce: spec.reduce_function
207
- } },
208
- ({ spec.list_name => spec.list_function } unless spec.list_name.nil?),
209
- spec.lib,
210
- spec.language
211
- ).query_view!(spec.view_parameters)
212
- processed_results = spec.process_results results
213
- if processed_results.respond_to?(:database=)
214
- processed_results.database = self
215
- elsif processed_results.respond_to?(:each)
216
- processed_results.each do |document|
217
- document.database = self if document.respond_to?(:database=)
218
- end
216
+ process_view_results(raw_view(spec), spec)
217
+ end
218
+ end
219
+
220
+ def process_view_results(results, spec)
221
+ processed_results = spec.process_results results
222
+ if processed_results.respond_to?(:database=)
223
+ processed_results.database = self
224
+ elsif processed_results.respond_to?(:each)
225
+ processed_results.each do |document|
226
+ document.database = self if document.respond_to?(:database=)
219
227
  end
220
- processed_results
221
228
  end
229
+ processed_results
230
+ end
231
+
232
+ def raw_view(spec)
233
+ CouchPotato::View::ViewQuery.new(
234
+ couchrest_database,
235
+ spec.design_document,
236
+ { spec.view_name => {
237
+ map: spec.map_function,
238
+ reduce: spec.reduce_function
239
+ } },
240
+ ({ spec.list_name => spec.list_function } unless spec.list_name.nil?),
241
+ spec.lib,
242
+ spec.language
243
+ ).query_view!(spec.view_parameters)
222
244
  end
223
245
 
224
246
  def load_document_without_caching(id)
@@ -1,4 +1,4 @@
1
1
  module CouchPotato
2
- VERSION = '1.10.1'.freeze
2
+ VERSION = '1.11.0'.freeze
3
3
  RSPEC_VERSION = '4.0.2'.freeze
4
4
  end
@@ -430,11 +430,11 @@ describe CouchPotato::Database, '#view_in_batches' do
430
430
  let(:view_query) do
431
431
  instance_double(
432
432
  CouchPotato::View::ViewQuery,
433
- query_view!: { 'rows' => [result] }
433
+ query_view!: { 'rows' => [] }
434
434
  )
435
435
  end
436
- let(:result) { double('result') }
437
- let(:spec) { double('view spec', process_results: [result]).as_null_object }
436
+ let(:processed_result) { double(:processed_result) }
437
+ let(:spec) { double('view spec', process_results: processed_result).as_null_object }
438
438
  let(:couchrest_db) { double('couchrest db').as_null_object }
439
439
  let(:db) { CouchPotato::Database.new(couchrest_db) }
440
440
 
@@ -443,22 +443,41 @@ describe CouchPotato::Database, '#view_in_batches' do
443
443
  .to receive_messages(new: view_query)
444
444
  end
445
445
 
446
- it 'sets skip/limit for each batch' do
447
- allow(spec).to receive(:process_results).and_return([result, result], [result]) # run twice
446
+ it 'sets no skip/startkey/startkey_docid for the first batch' do
448
447
  allow(spec).to receive(:view_parameters) { { key: 'x' } }
449
448
 
450
449
  expect(spec).to receive(:view_parameters=)
451
- .with({key: 'x', skip: 0, limit: 2})
450
+ .with({key: 'x', limit: 2})
451
+
452
+ db.view_in_batches(spec, batch_size: 2) { |results| }
453
+ end
454
+
455
+ it 'sets skip/startkey/startkey_docid for each other batch' do
456
+ allow(spec).to receive(:view_parameters) { { key: 'x' } }
457
+ allow(view_query).to receive(:query_view!)
458
+ .and_return({'rows' => [{}, {'key' => 'k1', 'id' => 'id1'}]}, {'rows' => [{}]})
459
+ allow(spec).to receive(:view_parameters=)
460
+
452
461
  expect(spec).to receive(:view_parameters=)
453
- .with({key: 'x', skip: 2, limit: 2})
462
+ .with({key: 'x', limit: 2, startkey: 'k1', startkey_docid: 'id1', skip: 1})
454
463
 
455
464
  db.view_in_batches(spec, batch_size: 2) { |results| }
456
465
  end
457
466
 
467
+ it 'yields processed results to the block' do
468
+ allow(view_query).to receive(:query_view!)
469
+ .and_return({'rows' => [{'key' => 'k1', 'id' => 'id1'}]})
470
+ allow(spec).to receive(:view_parameters=)
471
+
472
+ expect { |x| db.view_in_batches(spec, batch_size: 2, &x) }.to yield_with_args(processed_result)
473
+ end
474
+
458
475
  it 'yields batches until running out of data' do
459
- allow(spec).to receive(:process_results).and_return([result, result], [result])
476
+ allow(view_query).to receive(:query_view!)
477
+ .and_return({'rows' => [{}, {}]}, {'rows' => [{}]})
478
+ allow(spec).to receive(:process_results).and_return([processed_result, processed_result], [processed_result])
460
479
 
461
- expect { |b| db.view_in_batches(spec, batch_size: 2, &b) }.to yield_successive_args([result, result], [result])
480
+ expect { |b| db.view_in_batches(spec, batch_size: 2, &b) }.to yield_successive_args([processed_result, processed_result], [processed_result])
462
481
  end
463
482
  end
464
483
 
data/spec/views_spec.rb CHANGED
@@ -405,4 +405,15 @@ describe 'views' do
405
405
  expect(@db.view(Build.timeline(stale: 'ok'))).to be_empty
406
406
  end
407
407
  end
408
+
409
+ describe 'view_in_batches' do
410
+ it 'yields docs in batches until all gone' do
411
+ build1 = Build.new(time: 1).tap {|b| @db.save!(b) }
412
+ build2 = Build.new(time: 2).tap {|b| @db.save!(b) }
413
+ build3 = Build.new(time: 3).tap {|b| @db.save!(b) }
414
+
415
+ expect {|block| @db.view_in_batches(Build.timeline, batch_size: 2, &block)}
416
+ .to yield_successive_args([build1, build2], [build3])
417
+ end
418
+ end
408
419
  end
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.10.1
4
+ version: 1.11.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: 2022-02-07 00:00:00.000000000 Z
11
+ date: 2022-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel