couch_potato 1.7.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +50 -0
  3. data/.gitignore +3 -0
  4. data/CHANGES.md +180 -130
  5. data/Gemfile +4 -0
  6. data/README.md +61 -85
  7. data/Rakefile +11 -10
  8. data/couch_potato-rspec.gemspec +2 -1
  9. data/couch_potato.gemspec +9 -7
  10. data/gemfiles/active_support_5_0 +6 -0
  11. data/gemfiles/active_support_5_1 +7 -0
  12. data/gemfiles/active_support_5_2 +6 -0
  13. data/gemfiles/active_support_6_0 +6 -0
  14. data/gemfiles/active_support_6_1 +6 -0
  15. data/gemfiles/active_support_7_0 +6 -0
  16. data/lib/couch_potato/database.rb +170 -71
  17. data/lib/couch_potato/persistence/dirty_attributes.rb +3 -21
  18. data/lib/couch_potato/persistence/magic_timestamps.rb +3 -3
  19. data/lib/couch_potato/persistence/properties.rb +15 -10
  20. data/lib/couch_potato/persistence/simple_property.rb +0 -4
  21. data/lib/couch_potato/persistence/type_caster.rb +11 -6
  22. data/lib/couch_potato/persistence.rb +0 -1
  23. data/lib/couch_potato/railtie.rb +6 -11
  24. data/lib/couch_potato/validation.rb +8 -0
  25. data/lib/couch_potato/version.rb +2 -2
  26. data/lib/couch_potato/view/base_view_spec.rb +8 -32
  27. data/lib/couch_potato/view/custom_views.rb +4 -3
  28. data/lib/couch_potato/view/flex_view_spec.rb +121 -0
  29. data/lib/couch_potato/view/view_parameters.rb +34 -0
  30. data/lib/couch_potato.rb +37 -16
  31. data/spec/callbacks_spec.rb +45 -19
  32. data/spec/conflict_handling_spec.rb +1 -2
  33. data/spec/property_spec.rb +12 -3
  34. data/spec/railtie_spec.rb +10 -0
  35. data/spec/spec_helper.rb +4 -3
  36. data/spec/unit/active_model_compliance_spec.rb +7 -3
  37. data/spec/unit/attributes_spec.rb +54 -1
  38. data/spec/unit/caching_spec.rb +105 -0
  39. data/spec/unit/couch_potato_spec.rb +70 -5
  40. data/spec/unit/create_spec.rb +5 -4
  41. data/spec/unit/database_spec.rb +239 -135
  42. data/spec/unit/dirty_attributes_spec.rb +5 -26
  43. data/spec/unit/flex_view_spec_spec.rb +17 -0
  44. data/spec/unit/model_view_spec_spec.rb +1 -1
  45. data/spec/unit/rspec_stub_db_spec.rb +31 -0
  46. data/spec/unit/validation_spec.rb +42 -2
  47. data/spec/unit/view_query_spec.rb +12 -7
  48. data/spec/views_spec.rb +214 -103
  49. data/vendor/pouchdb-collate/LICENSE +202 -0
  50. data/vendor/pouchdb-collate/pouchdb-collate.js +430 -0
  51. metadata +47 -36
  52. data/.ruby-version +0 -1
  53. data/.travis.yml +0 -21
  54. data/gemfiles/active_support_4_0 +0 -11
  55. data/gemfiles/active_support_4_1 +0 -11
  56. data/gemfiles/active_support_4_2 +0 -11
  57. data/lib/couch_potato/persistence/deep_dirty_attributes.rb +0 -180
  58. data/spec/unit/deep_dirty_attributes_spec.rb +0 -434
data/spec/views_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  class Build
@@ -5,20 +7,35 @@ class Build
5
7
 
6
8
  property :state
7
9
  property :time
8
- property :type, :type => String, :default => 'Build'
9
-
10
- view :timeline, :key => :time
11
- view :count, :key => :time, :reduce => true
12
- view :minimal_timeline, :key => :time, :properties => [:state], :type => :properties
13
- view :key_array_timeline, :key => [:time, :state]
14
- view :custom_timeline, :map => "function(doc) { emit(doc._id, {state: 'custom_' + doc.state}); }", :type => :custom
15
- view :custom_timeline_returns_docs, :map => "function(doc) { emit(doc._id, null); }", :include_docs => true, :type => :custom
16
- view :custom_with_reduce, :map => "function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}", :reduce => "function(key, values) {return({\"count\": sum(values)});}", :group => true, :type => :custom
17
- view :custom_count_with_reduce, :map => "function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}", :reduce => "function(key, values) {return(sum(values));}", :group => true, :type => :custom
18
- view :raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}"
19
- view :filtered_raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}", :results_filter => lambda{|res| res['rows'].map{|row| row['value']}}
20
- view :with_view_options, :group => true, :key => :time
21
- view :all, :map => "function(doc) { if (doc && doc.type == 'Build') emit(doc._id, 1); }", :include_docs => true, :type => :custom
10
+ property :type, type: String, default: 'Build'
11
+
12
+ view :timeline, key: :time
13
+ view :count, key: :time, reduce: true
14
+ view :minimal_timeline, key: :time, properties: [:state], type: :properties
15
+ view :key_array_timeline, key: %i[time state]
16
+ view :custom_timeline, map: "function(doc) { emit(doc._id, {state: 'custom_' + doc.state}); }", type: :custom
17
+ view :custom_timeline_returns_docs, map: 'function(doc) { emit(doc._id, null); }', include_docs: true, type: :custom
18
+ view :custom_with_reduce, map: 'function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}', reduce: 'function(key, values) {return({"count": sum(values)});}', group: true, type: :custom
19
+ view :custom_count_with_reduce, map: 'function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}', reduce: 'function(key, values) {return(sum(values));}', group: true, type: :custom
20
+ view :raw, type: :raw, map: 'function(doc) {emit(doc._id, doc.state)}'
21
+ view :filtered_raw, type: :raw, map: 'function(doc) {emit(doc._id, doc.state)}', results_filter: ->(res) { res['rows'].map { |row| row['value'] } }
22
+ view :with_view_options, group: true, key: :time
23
+ view :all, map: "function(doc) { if (doc && doc.type == 'Build') emit(doc._id, 1); }", include_docs: true, type: :custom
24
+
25
+ module TimesToInt
26
+ def times_to_int
27
+ docs.map { |doc| doc.time.to_i }
28
+ end
29
+ end
30
+ view :flex_with_key, type: :flex, key: :time, extend_results: TimesToInt
31
+ view :flex_with_custom,
32
+ type: :flex,
33
+ map: <<~JS,
34
+ function(doc) {
35
+ emit(doc.time, 1);
36
+ }
37
+ JS
38
+ reduce: '_sum'
22
39
  end
23
40
 
24
41
  class CustomBuild < Build
@@ -30,8 +47,8 @@ class ErlangBuild
30
47
  property :name
31
48
  property :code
32
49
 
33
- view :by_name, :key => :name, :language => :erlang
34
- view :by_name_and_code, :key => [:name, :code], :language => :erlang
50
+ view :by_name, key: :name, language: :erlang
51
+ view :by_name_and_code, key: %i[name code], language: :erlang
35
52
  end
36
53
 
37
54
  describe 'views' do
@@ -42,7 +59,7 @@ describe 'views' do
42
59
 
43
60
  context 'in erlang' do
44
61
  it 'builds views with single keys' do
45
- build = ErlangBuild.new(:name => 'erlang')
62
+ build = ErlangBuild.new(name: 'erlang')
46
63
  @db.save_document build
47
64
 
48
65
  results = @db.view(ErlangBuild.by_name('erlang'))
@@ -50,98 +67,98 @@ describe 'views' do
50
67
  end
51
68
 
52
69
  it 'does not crash couchdb when a document does not have the key' do
53
- build = {'ruby_class' => 'ErlangBuild'}
70
+ build = { 'ruby_class' => 'ErlangBuild' }
54
71
  @db.couchrest_database.save_doc build
55
72
 
56
- results = @db.view(ErlangBuild.by_name(:key => nil))
73
+ results = @db.view(ErlangBuild.by_name(key: nil))
57
74
  expect(results.size).to eq(1)
58
75
  end
59
76
 
60
77
  it 'builds views with composite keys' do
61
- build = ErlangBuild.new(:name => 'erlang', :code => '123')
78
+ build = ErlangBuild.new(name: 'erlang', code: '123')
62
79
  @db.save_document build
63
80
 
64
- results = @db.view(ErlangBuild.by_name_and_code(['erlang', '123']))
81
+ results = @db.view(ErlangBuild.by_name_and_code(%w[erlang 123]))
65
82
  expect(results).to eq([build])
66
83
  end
67
84
 
68
85
  it 'can reduce over erlang views' do
69
- build = ErlangBuild.new(:name => 'erlang')
86
+ build = ErlangBuild.new(name: 'erlang')
70
87
  @db.save_document build
71
88
 
72
- results = @db.view(ErlangBuild.by_name(:reduce => true))
89
+ results = @db.view(ErlangBuild.by_name(reduce: true))
73
90
  expect(results).to eq(1)
74
91
  end
75
92
  end
76
93
 
77
- it "should return instances of the class" do
78
- @db.save_document Build.new(:state => 'success', :time => '2008-01-01')
94
+ it 'should return instances of the class' do
95
+ @db.save_document Build.new(state: 'success', time: '2008-01-01')
79
96
  results = @db.view(Build.timeline)
80
97
  expect(results.map(&:class)).to eq([Build])
81
98
  end
82
99
 
83
- it "should return the ids if there document was not included" do
84
- build = Build.new(:state => 'success', :time => '2008-01-01')
100
+ it 'should return the ids if there document was not included' do
101
+ build = Build.new(state: 'success', time: '2008-01-01')
85
102
  @db.save_document build
86
- results = @db.view(Build.timeline(:include_docs => false))
103
+ results = @db.view(Build.timeline(include_docs: false))
87
104
  expect(results).to eq([build.id])
88
105
  end
89
106
 
90
- it "should pass the view options to the view query" do
107
+ it 'should pass the view options to the view query' do
91
108
  query = double 'query'
92
109
  allow(CouchPotato::View::ViewQuery).to receive(:new).and_return(query)
93
- expect(query).to receive(:query_view!).with(hash_including(:key => 1)).and_return('rows' => [])
94
- @db.view Build.timeline(:key => 1)
110
+ expect(query).to receive(:query_view!).with(hash_including(key: 1)).and_return('rows' => [])
111
+ @db.view Build.timeline(key: 1)
95
112
  end
96
113
 
97
114
  it "should not return documents that don't have a matching JSON.create_id" do
98
- CouchPotato.couchrest_database.save_doc({:time => 'x'})
115
+ CouchPotato.couchrest_database.save_doc({ time: 'x' })
99
116
  expect(@db.view(Build.timeline)).to eq([])
100
117
  end
101
118
 
102
- it "should count documents" do
103
- @db.save_document! Build.new(:state => 'success', :time => '2008-01-01')
104
- expect(@db.view(Build.count(:reduce => true))).to eq(1)
119
+ it 'should count documents' do
120
+ @db.save_document! Build.new(state: 'success', time: '2008-01-01')
121
+ expect(@db.view(Build.count(reduce: true))).to eq(1)
105
122
  end
106
123
 
107
- it "should count zero documents" do
108
- expect(@db.view(Build.count(:reduce => true))).to eq(0)
124
+ it 'should count zero documents' do
125
+ expect(@db.view(Build.count(reduce: true))).to eq(0)
109
126
  end
110
127
 
111
- describe "with multiple keys" do
112
- it "should return the documents with matching keys" do
113
- build = Build.new(:state => 'success', :time => '2008-01-01')
128
+ describe 'with multiple keys' do
129
+ it 'should return the documents with matching keys' do
130
+ build = Build.new(state: 'success', time: '2008-01-01')
114
131
  @db.save! build
115
- expect(@db.view(Build.timeline(:keys => ['2008-01-01']))).to eq([build])
132
+ expect(@db.view(Build.timeline(keys: ['2008-01-01']))).to eq([build])
116
133
  end
117
134
 
118
- it "should not return documents with non-matching keys" do
119
- build = Build.new(:state => 'success', :time => '2008-01-01')
135
+ it 'should not return documents with non-matching keys' do
136
+ build = Build.new(state: 'success', time: '2008-01-01')
120
137
  @db.save! build
121
- expect(@db.view(Build.timeline(:keys => ['2008-01-02']))).to be_empty
138
+ expect(@db.view(Build.timeline(keys: ['2008-01-02']))).to be_empty
122
139
  end
123
140
  end
124
141
 
125
- describe "properties defined" do
126
- it "assigns the configured properties" do
142
+ describe 'properties defined' do
143
+ it 'assigns the configured properties' do
127
144
  CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')
128
145
  expect(@db.view(Build.minimal_timeline).first.state).to eql('success')
129
146
  end
130
147
 
131
- it "does not assign the properties not configured" do
148
+ it 'does not assign the properties not configured' do
132
149
  CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')
133
150
  expect(@db.view(Build.minimal_timeline).first.time).to be_nil
134
151
  end
135
152
 
136
- it "assigns the id even if it is not configured" do
153
+ it 'assigns the id even if it is not configured' do
137
154
  id = CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')['id']
138
155
  expect(@db.view(Build.minimal_timeline).first._id).to eql(id)
139
156
  end
140
157
  end
141
158
 
142
- describe "no properties defined" do
143
- it "should assign all properties to the objects by default" do
144
- id = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build'})['id']
159
+ describe 'no properties defined' do
160
+ it 'should assign all properties to the objects by default' do
161
+ id = CouchPotato.couchrest_database.save_doc({ :state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build' })['id']
145
162
  result = @db.view(Build.timeline).first
146
163
  expect(result.state).to eq('success')
147
164
  expect(result.time).to eq('2008-01-01')
@@ -149,116 +166,210 @@ describe 'views' do
149
166
  end
150
167
  end
151
168
 
152
- describe "map function given" do
153
- it "should still return instances of the class" do
154
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
169
+ describe 'map function given' do
170
+ it 'should still return instances of the class' do
171
+ CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
155
172
  expect(@db.view(Build.custom_timeline).map(&:class)).to eq([Build])
156
173
  end
157
174
 
158
- it "should assign the properties from the value" do
159
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
175
+ it 'should assign the properties from the value' do
176
+ CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
160
177
  expect(@db.view(Build.custom_timeline).map(&:state)).to eq(['custom_success'])
161
178
  end
162
179
 
163
- it "should assign the id" do
164
- doc = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
180
+ it 'should assign the id' do
181
+ doc = CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
165
182
  expect(@db.view(Build.custom_timeline).map(&:_id)).to eq([doc['id']])
166
183
  end
167
184
 
168
- it "should leave the other properties blank" do
169
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
185
+ it 'should leave the other properties blank' do
186
+ CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
170
187
  expect(@db.view(Build.custom_timeline).map(&:time)).to eq([nil])
171
188
  end
172
189
 
173
- describe "that returns null documents" do
174
- it "should return instances of the class" do
175
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
190
+ describe 'that returns null documents' do
191
+ it 'should return instances of the class' do
192
+ CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
176
193
  expect(@db.view(Build.custom_timeline_returns_docs).map(&:class)).to eq([Build])
177
194
  end
178
195
 
179
- it "should assign the properties from the value" do
180
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
196
+ it 'should assign the properties from the value' do
197
+ CouchPotato.couchrest_database.save_doc({ state: 'success', time: '2008-01-01' })
181
198
  expect(@db.view(Build.custom_timeline_returns_docs).map(&:state)).to eq(['success'])
182
199
  end
183
200
 
184
- it "should still return instance of class if document included JSON.create_id" do
185
- CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => "Build"})
201
+ it 'should still return instance of class if document included JSON.create_id' do
202
+ CouchPotato.couchrest_database.save_doc({ :state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build' })
186
203
  view_data = @db.view(Build.custom_timeline_returns_docs)
187
204
  expect(view_data.map(&:class)).to eq([Build])
188
205
  expect(view_data.map(&:state)).to eq(['success'])
189
206
  end
190
207
  end
191
208
 
192
- describe "additional reduce function given" do
193
- it "should still assign the id" do
209
+ describe 'additional reduce function given' do
210
+ it 'should still assign the id' do
194
211
  doc = CouchPotato.couchrest_database.save_doc({})
195
- CouchPotato.couchrest_database.save_doc({:foreign_key => doc['id']})
212
+ CouchPotato.couchrest_database.save_doc({ foreign_key: doc['id'] })
196
213
  expect(@db.view(Build.custom_with_reduce).map(&:_id)).to eq([doc['id']])
197
214
  end
198
215
 
199
- describe "when the additional reduce function is a typical count" do
200
- it "should parse the reduce count" do
216
+ describe 'when the additional reduce function is a typical count' do
217
+ it 'should parse the reduce count' do
201
218
  doc = CouchPotato.couchrest_database.save_doc({})
202
- CouchPotato.couchrest_database.save_doc({:foreign_key => doc['id']})
203
- expect(@db.view(Build.custom_count_with_reduce(:reduce => true))).to eq(2)
219
+ CouchPotato.couchrest_database.save_doc({ foreign_key: doc['id'] })
220
+ expect(@db.view(Build.custom_count_with_reduce(reduce: true))).to eq(2)
204
221
  end
205
222
  end
206
223
  end
207
224
  end
208
225
 
209
- describe "with array as key" do
210
- it "should create a map function with the composite key" do
211
- expect(CouchPotato::View::ViewQuery).to receive(:new) do |db, design_name, view, list|
226
+ describe 'with array as key' do
227
+ it 'should create a map function with the composite key' do
228
+ expect(CouchPotato::View::ViewQuery).to receive(:new) do |_db, _design_name, view, _list|
212
229
  expect(view['key_array_timeline'][:map]).to match(/emit\(\[doc\['time'\], doc\['state'\]\]/)
213
230
 
214
- double('view query', :query_view! => {'rows' => []})
231
+ double('view query', query_view!: { 'rows' => [] })
215
232
  end
216
233
  @db.view Build.key_array_timeline
217
234
  end
218
235
  end
219
236
 
220
- describe "raw view" do
221
- it "should return the raw data" do
222
- @db.save_document Build.new(:state => 'success', :time => '2008-01-01')
237
+ describe 'raw view' do
238
+ it 'should return the raw data' do
239
+ @db.save_document Build.new(state: 'success', time: '2008-01-01')
223
240
  expect(@db.view(Build.raw)['rows'][0]['value']).to eq('success')
224
241
  end
225
242
 
226
- it "should return filtred raw data" do
227
- @db.save_document Build.new(:state => 'success', :time => '2008-01-01')
243
+ it 'should return filtred raw data' do
244
+ @db.save_document Build.new(state: 'success', time: '2008-01-01')
228
245
  expect(@db.view(Build.filtered_raw)).to eq(['success'])
229
246
  end
230
247
 
231
- it "should pass view options declared in the view declaration to the query" do
232
- view_query = double 'view_query'
233
- allow(CouchPotato::View::ViewQuery).to receive(:new).and_return(view_query)
234
- expect(view_query).to receive(:query_view!).with(hash_including(:group => true)).and_return({'rows' => []})
235
- @db.view(Build.with_view_options)
248
+ it 'should pass view options declared in the view declaration to the query' do
249
+ view_query = double 'view_query'
250
+ allow(CouchPotato::View::ViewQuery).to receive(:new).and_return(view_query)
251
+ expect(view_query).to receive(:query_view!).with(hash_including(group: true)).and_return({ 'rows' => [] })
252
+ @db.view(Build.with_view_options)
253
+ end
254
+ end
255
+
256
+ describe 'flex view' do
257
+ it 'supports a given key' do
258
+ @db.save_document Build.new(id: 'b1', state: 'success', time: '2008-01-01')
259
+ @db.save_document Build.new(state: 'success', time: '2008-01-02')
260
+
261
+ rows = @db.view(Build.flex_with_key('2008-01-01')).raw['rows']
262
+
263
+ expect(rows.map { |row| row['id'] }).to eq(['b1'])
264
+ end
265
+
266
+ it 'supports a given map function' do
267
+ @db.save_document Build.new(id: 'b1', time: '2008-01-01')
268
+ @db.save_document Build.new(time: '2008-01-02')
269
+
270
+ rows = @db.view(Build.flex_with_custom('2008-01-01')).raw['rows']
271
+
272
+ expect(rows.map { |row| row['id'] }).to eq(['b1'])
273
+ end
274
+
275
+ it 'supports a given reduce function' do
276
+ @db.save_document Build.new(time: '2008-01-01')
277
+ @db.save_document Build.new(time: '2008-01-02')
278
+
279
+ raw = @db.view(Build.flex_with_custom(reduce: true)).raw
280
+
281
+ expect(raw['rows'][0]['value']).to eq(2)
282
+ end
283
+
284
+ it 'returns ids' do
285
+ @db.save_document Build.new(id: 'b1')
286
+ @db.save_document Build.new(id: 'b2')
287
+
288
+ ids = @db.view(Build.flex_with_key).ids
289
+
290
+ expect(ids).to eq(%w[b1 b2])
291
+ end
292
+
293
+ it 'returns keys' do
294
+ @db.save_document Build.new(time: '1')
295
+ @db.save_document Build.new(time: '2')
296
+
297
+ ids = @db.view(Build.flex_with_key).keys
298
+
299
+ expect(ids).to eq(%w[1 2])
300
+ end
301
+
302
+ it 'returns values' do
303
+ @db.save_document Build.new(time: '1')
304
+ @db.save_document Build.new(time: '2')
305
+
306
+ ids = @db.view(Build.flex_with_key).values
307
+
308
+ expect(ids).to eq([1, 1])
309
+ end
310
+
311
+ it 'returns docs' do
312
+ @db.save_document Build.new(time: '1')
313
+
314
+ docs = @db.view(Build.flex_with_key(include_docs: true)).docs
315
+
316
+ expect(docs.map(&:time)).to eq(['1'])
317
+ expect(docs.first.database).to eq(@db)
318
+ end
319
+
320
+ it 'returns the value of reduce' do
321
+ @db.save_document Build.new(time: '1')
322
+ @db.save_document Build.new(time: '1')
323
+
324
+ value = @db.view(Build.flex_with_key(reduce: true)).reduce_value
325
+
326
+ expect(value).to eq(2)
327
+ end
328
+
329
+ it 'returns the raw results' do
330
+ @db.save_document Build.new(id: 'b1', time: '1')
331
+
332
+ raw = @db.view(Build.flex_with_key).raw
333
+
334
+ expect(raw).to eq(
335
+ 'total_rows' => 1, 'offset' => 0,
336
+ 'rows' => [{ 'id' => 'b1', 'key' => '1', 'value' => 1 }]
337
+ )
338
+ end
339
+
340
+ it 'returns the results via a custom method' do
341
+ @db.save_document Build.new(id: 'b1', time: '100')
342
+ @db.save_document Build.new(id: 'b2', time: '200')
343
+
344
+ custom = @db.view(Build.flex_with_key(include_docs: true)).times_to_int
345
+
346
+ expect(custom).to eq([100, 200])
236
347
  end
237
348
  end
238
349
 
239
- describe "inherited views" do
240
- it "should support parent views for objects of the subclass" do
241
- @db.save_document CustomBuild.new(:state => 'success', :time => '2008-01-01')
350
+ describe 'inherited views' do
351
+ it 'should support parent views for objects of the subclass' do
352
+ @db.save_document CustomBuild.new(state: 'success', time: '2008-01-01')
242
353
  expect(@db.view(CustomBuild.timeline).size).to eq(1)
243
354
  expect(@db.view(CustomBuild.timeline).first).to be_kind_of(CustomBuild)
244
355
  end
245
356
 
246
- it "should return instances of subclasses as well if a special view exists" do
247
- @db.save_document Build.new(:state => 'success', :time => '2008-01-01')
248
- @db.save_document CustomBuild.new(:state => 'success', :time => '2008-01-01', :server => 'Jenkins')
357
+ it 'should return instances of subclasses as well if a special view exists' do
358
+ @db.save_document Build.new(state: 'success', time: '2008-01-01')
359
+ @db.save_document CustomBuild.new(state: 'success', time: '2008-01-01', server: 'Jenkins')
249
360
  results = @db.view(Build.all)
250
361
  expect(results.map(&:class)).to eq([CustomBuild, Build])
251
362
  end
252
363
  end
253
364
 
254
- describe "list functions" do
365
+ describe 'list functions' do
255
366
  class Coworker
256
367
  include CouchPotato::Persistence
257
368
 
258
369
  property :name
259
370
 
260
- view :all_with_list, :key => :name, :list => :append_doe
261
- view :all, :key => :name
371
+ view :all_with_list, key: :name, list: :append_doe
372
+ view :all, key: :name
262
373
 
263
374
  list :append_doe, <<-JS
264
375
  function(head, req) {
@@ -273,14 +384,14 @@ describe 'views' do
273
384
  JS
274
385
  end
275
386
 
276
- it "should use the list function declared at class level" do
277
- @db.save! Coworker.new(:name => 'joe')
387
+ it 'should use the list function declared at class level' do
388
+ @db.save! Coworker.new(name: 'joe')
278
389
  expect(@db.view(Coworker.all_with_list).first.name).to eq('joe doe')
279
390
  end
280
391
 
281
- it "should use the list function passed at runtime" do
282
- @db.save! Coworker.new(:name => 'joe')
283
- expect(@db.view(Coworker.all(:list => :append_doe)).first.name).to eq('joe doe')
392
+ it 'should use the list function passed at runtime' do
393
+ @db.save! Coworker.new(name: 'joe')
394
+ expect(@db.view(Coworker.all(list: :append_doe)).first.name).to eq('joe doe')
284
395
  end
285
396
  end
286
397
 
@@ -291,7 +402,7 @@ describe 'views' do
291
402
  @db.view(Build.timeline)
292
403
  @db.destroy build
293
404
 
294
- expect(@db.view(Build.timeline(:stale => 'ok'))).to be_empty
405
+ expect(@db.view(Build.timeline(stale: 'ok'))).to be_empty
295
406
  end
296
407
  end
297
408
  end