couch_potato 1.10.0 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 699af51806a63fca2975c8eff17636647a5ca7c12f9131df7e30a5f843ab3028
4
- data.tar.gz: 1e305be23ca0606bef97e7f89b06f166f694a7ec937a2641c782274dc9a8cf51
3
+ metadata.gz: fc65386f8f391b222c93733fbf83cb00050bc37b2fa1787be8d73e4847b2fa43
4
+ data.tar.gz: a2c6fe4017c646b3bceaa9baaa236044ffe286fd3380095296a602034511d817
5
5
  SHA512:
6
- metadata.gz: bee39cf067a428f14b646948dc0ceea5e5b0bfde2f0eafd9e1ea025dbd5833bcfc8c328f8457aaa4ecb72aabf07a2e327f329296d1224dafb8c7967cf37d1eeb
7
- data.tar.gz: 4f371624eb17e5d03fb25a13ae9375705f1b143fccb30c8e7cbfdeaeb98d8549b7cc29f9b7a7fe83ec0ac06abef1200670ea092aebd5e46bb7aa94265ee48191
6
+ metadata.gz: 5f7c933270982e090183aacdb7fdd52e76e2739476e7e4d87cbcad1239c62b4973f31ce62278f181c33612bc6c2dc8ee7abbc2ffca0bef4560b919b8a37359c8
7
+ data.tar.gz: 7f79c9a6b3c31f5f1fc0eea3f4a16da6e7cb6ace5a68232a9a127d7d056b5144d88714e12e128a64eba34a9377e073311408077958c14b818c0f4037853a59a5
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [2.6, 2.7, "jruby"]
19
+ ruby: [2.7, '3.0', "jruby"]
20
20
  gemfile:
21
21
  - "active_support_5_0"
22
22
  - "active_support_5_1"
@@ -25,10 +25,16 @@ jobs:
25
25
  - "active_support_6_1"
26
26
  - "active_support_7_0"
27
27
  exclude:
28
- - ruby: 2.6
29
- gemfile: "active_support_7_0"
30
28
  - ruby: "jruby"
31
29
  gemfile: "active_support_7_0"
30
+ - ruby: "3.0"
31
+ gemfile: "active_support_5_0"
32
+ - ruby: "3.0"
33
+ gemfile: "active_support_5_1"
34
+ - ruby: "3.0"
35
+ gemfile: "active_support_5_2"
36
+ - ruby: "3.0"
37
+ gemfile: "active_support_6_0"
32
38
  steps:
33
39
  - uses: actions/checkout@v2
34
40
  - name: Set up CouchDB
data/CHANGES.md CHANGED
@@ -1,5 +1,13 @@
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
+
7
+ ### 1.10.1
8
+
9
+ - support passing an empty array to CouchPotato::Database#load
10
+
3
11
  ### 1.10.0
4
12
 
5
13
  - add spec/support for Rails 7
data/couch_potato.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_dependency 'json', '~> 2.3'
19
19
 
20
20
  s.add_development_dependency 'rake', '~>12.0'
21
- s.add_development_dependency 'rspec', '~>3.5.0'
21
+ s.add_development_dependency 'rspec', '~>3.10.0'
22
22
  s.add_development_dependency 'timecop'
23
23
  s.add_development_dependency 'tzinfo'
24
24
 
@@ -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)
@@ -269,6 +291,8 @@ module CouchPotato
269
291
  end
270
292
 
271
293
  def bulk_load(ids)
294
+ return [] if ids.empty?
295
+
272
296
  response = couchrest_database.bulk_load ids
273
297
  docs = response['rows'].map { |row| row['doc'] }.compact
274
298
  docs.each do |doc|
@@ -1,4 +1,4 @@
1
1
  module CouchPotato
2
- VERSION = '1.10.0'.freeze
2
+ VERSION = '1.11.0'.freeze
3
3
  RSPEC_VERSION = '4.0.2'.freeze
4
4
  end
data/spec/railtie_spec.rb CHANGED
@@ -87,7 +87,7 @@ describe "railtie" do
87
87
  it 'assigns additional_databases to config' do
88
88
  allow(File).to receive_messages(:read => "test:\n database: test\n additional_databases:\n db2: test2")
89
89
 
90
- expect(CouchPotato::Config).to receive(:additional_databases=).with('db2' => 'test2')
90
+ expect(CouchPotato::Config).to receive(:additional_databases=).with({'db2' => 'test2'})
91
91
 
92
92
  CouchPotato.rails_init
93
93
  end
@@ -98,6 +98,10 @@ describe CouchPotato::Database, 'load' do
98
98
 
99
99
  db.load(['1'])
100
100
  end
101
+
102
+ it 'returns an empty array when passing an empty array' do
103
+ expect(db.load([])).to eq([])
104
+ end
101
105
  end
102
106
  end
103
107
 
@@ -426,11 +430,11 @@ describe CouchPotato::Database, '#view_in_batches' do
426
430
  let(:view_query) do
427
431
  instance_double(
428
432
  CouchPotato::View::ViewQuery,
429
- query_view!: { 'rows' => [result] }
433
+ query_view!: { 'rows' => [] }
430
434
  )
431
435
  end
432
- let(:result) { double('result') }
433
- 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 }
434
438
  let(:couchrest_db) { double('couchrest db').as_null_object }
435
439
  let(:db) { CouchPotato::Database.new(couchrest_db) }
436
440
 
@@ -439,22 +443,41 @@ describe CouchPotato::Database, '#view_in_batches' do
439
443
  .to receive_messages(new: view_query)
440
444
  end
441
445
 
442
- it 'sets skip/limit for each batch' do
443
- 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
444
447
  allow(spec).to receive(:view_parameters) { { key: 'x' } }
445
448
 
446
449
  expect(spec).to receive(:view_parameters=)
447
- .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
+
448
461
  expect(spec).to receive(:view_parameters=)
449
- .with(key: 'x', skip: 2, limit: 2)
462
+ .with({key: 'x', limit: 2, startkey: 'k1', startkey_docid: 'id1', skip: 1})
450
463
 
451
464
  db.view_in_batches(spec, batch_size: 2) { |results| }
452
465
  end
453
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
+
454
475
  it 'yields batches until running out of data' do
455
- 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])
456
479
 
457
- 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])
458
481
  end
459
482
  end
460
483
 
@@ -15,10 +15,12 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
15
15
 
16
16
  it 'updates a view if it does not exist' do
17
17
  expect(db).to receive(:save_doc).with(
18
- 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}, 'lib' => {'test' => '<lib_code>'}},
19
- 'lists' => {},
20
- "_id" => "_design/design",
21
- "language" => "javascript"
18
+ {
19
+ 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}, 'lib' => {'test' => '<lib_code>'}},
20
+ 'lists' => {},
21
+ "_id" => "_design/design",
22
+ "language" => "javascript"
23
+ }
22
24
  )
23
25
 
24
26
  CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, {'test' => "<lib_code>"}).query_view!
@@ -46,8 +48,11 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
46
48
 
47
49
  it 'updates a view in erlang if it does not exist' do
48
50
  expect(db).to receive(:save_doc).with(
49
- 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
50
- 'lists' => {}, "_id" => "_design/design", "language" => "erlang")
51
+ {
52
+ 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
53
+ 'lists' => {}, "_id" => "_design/design", "language" => "erlang"
54
+ }
55
+ )
51
56
 
52
57
  CouchPotato::View::ViewQuery.new(db, 'design',
53
58
  {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}},
@@ -120,7 +125,7 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
120
125
 
121
126
  it 'does not pass in reduce or lib keys if there is no lib or reduce object' do
122
127
  allow(db).to receive(:get).and_return({'views' => {}})
123
- expect(db).to receive(:save_doc).with('views' => {'view7' => {'map' => '<map code>'}})
128
+ expect(db).to receive(:save_doc).with({'views' => {'view7' => {'map' => '<map code>'}}})
124
129
  CouchPotato::View::ViewQuery.new(db, 'design', :view7 => {:map => '<map code>', :reduce => nil}).query_view!
125
130
  end
126
131
 
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.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Lang
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-28 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
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 3.5.0
81
+ version: 3.10.0
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: 3.5.0
88
+ version: 3.10.0
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: timecop
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -219,7 +219,7 @@ files:
219
219
  homepage: http://github.com/langalex/couch_potato
220
220
  licenses: []
221
221
  metadata: {}
222
- post_install_message:
222
+ post_install_message:
223
223
  rdoc_options: []
224
224
  require_paths:
225
225
  - lib
@@ -234,8 +234,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
234
  - !ruby/object:Gem::Version
235
235
  version: '0'
236
236
  requirements: []
237
- rubygems_version: 3.1.6
238
- signing_key:
237
+ rubygems_version: 3.2.32
238
+ signing_key:
239
239
  specification_version: 4
240
240
  summary: Ruby persistence layer for CouchDB
241
241
  test_files: