couch_potato 1.7.0 → 1.10.1
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 +5 -5
- data/.github/workflows/ruby.yml +50 -0
- data/.gitignore +3 -0
- data/CHANGES.md +180 -130
- data/Gemfile +4 -0
- data/README.md +61 -85
- data/Rakefile +11 -10
- data/couch_potato-rspec.gemspec +2 -1
- data/couch_potato.gemspec +9 -7
- data/gemfiles/active_support_5_0 +6 -0
- data/gemfiles/active_support_5_1 +7 -0
- data/gemfiles/active_support_5_2 +6 -0
- data/gemfiles/active_support_6_0 +6 -0
- data/gemfiles/active_support_6_1 +6 -0
- data/gemfiles/active_support_7_0 +6 -0
- data/lib/couch_potato/database.rb +170 -71
- data/lib/couch_potato/persistence/dirty_attributes.rb +3 -21
- data/lib/couch_potato/persistence/magic_timestamps.rb +3 -3
- data/lib/couch_potato/persistence/properties.rb +15 -10
- data/lib/couch_potato/persistence/simple_property.rb +0 -4
- data/lib/couch_potato/persistence/type_caster.rb +11 -6
- data/lib/couch_potato/persistence.rb +0 -1
- data/lib/couch_potato/railtie.rb +6 -11
- data/lib/couch_potato/validation.rb +8 -0
- data/lib/couch_potato/version.rb +2 -2
- data/lib/couch_potato/view/base_view_spec.rb +8 -32
- data/lib/couch_potato/view/custom_views.rb +4 -3
- data/lib/couch_potato/view/flex_view_spec.rb +121 -0
- data/lib/couch_potato/view/view_parameters.rb +34 -0
- data/lib/couch_potato.rb +37 -16
- data/spec/callbacks_spec.rb +45 -19
- data/spec/conflict_handling_spec.rb +1 -2
- data/spec/property_spec.rb +12 -3
- data/spec/railtie_spec.rb +10 -0
- data/spec/spec_helper.rb +4 -3
- data/spec/unit/active_model_compliance_spec.rb +7 -3
- data/spec/unit/attributes_spec.rb +54 -1
- data/spec/unit/caching_spec.rb +105 -0
- data/spec/unit/couch_potato_spec.rb +70 -5
- data/spec/unit/create_spec.rb +5 -4
- data/spec/unit/database_spec.rb +239 -135
- data/spec/unit/dirty_attributes_spec.rb +5 -26
- data/spec/unit/flex_view_spec_spec.rb +17 -0
- data/spec/unit/model_view_spec_spec.rb +1 -1
- data/spec/unit/rspec_stub_db_spec.rb +31 -0
- data/spec/unit/validation_spec.rb +42 -2
- data/spec/unit/view_query_spec.rb +12 -7
- data/spec/views_spec.rb +214 -103
- data/vendor/pouchdb-collate/LICENSE +202 -0
- data/vendor/pouchdb-collate/pouchdb-collate.js +430 -0
- metadata +47 -36
- data/.ruby-version +0 -1
- data/.travis.yml +0 -21
- data/gemfiles/active_support_4_0 +0 -11
- data/gemfiles/active_support_4_1 +0 -11
- data/gemfiles/active_support_4_2 +0 -11
- data/lib/couch_potato/persistence/deep_dirty_attributes.rb +0 -180
- 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, :
|
9
|
-
|
10
|
-
view :timeline, :
|
11
|
-
view :count, :
|
12
|
-
view :minimal_timeline, :
|
13
|
-
view :key_array_timeline, :
|
14
|
-
view :custom_timeline, :
|
15
|
-
view :custom_timeline_returns_docs, :
|
16
|
-
view :custom_with_reduce, :
|
17
|
-
view :custom_count_with_reduce, :
|
18
|
-
view :raw, :
|
19
|
-
view :filtered_raw, :
|
20
|
-
view :with_view_options, :
|
21
|
-
view :all, :
|
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, :
|
34
|
-
view :by_name_and_code, :
|
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(:
|
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(:
|
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(:
|
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([
|
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(:
|
86
|
+
build = ErlangBuild.new(name: 'erlang')
|
70
87
|
@db.save_document build
|
71
88
|
|
72
|
-
results = @db.view(ErlangBuild.by_name(:
|
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
|
78
|
-
@db.save_document Build.new(:
|
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
|
84
|
-
build = Build.new(:
|
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(:
|
103
|
+
results = @db.view(Build.timeline(include_docs: false))
|
87
104
|
expect(results).to eq([build.id])
|
88
105
|
end
|
89
106
|
|
90
|
-
it
|
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(:
|
94
|
-
@db.view Build.timeline(:
|
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({:
|
115
|
+
CouchPotato.couchrest_database.save_doc({ time: 'x' })
|
99
116
|
expect(@db.view(Build.timeline)).to eq([])
|
100
117
|
end
|
101
118
|
|
102
|
-
it
|
103
|
-
@db.save_document! Build.new(:
|
104
|
-
expect(@db.view(Build.count(:
|
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
|
108
|
-
expect(@db.view(Build.count(:
|
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
|
112
|
-
it
|
113
|
-
build = Build.new(:
|
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(:
|
132
|
+
expect(@db.view(Build.timeline(keys: ['2008-01-01']))).to eq([build])
|
116
133
|
end
|
117
134
|
|
118
|
-
it
|
119
|
-
build = Build.new(:
|
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(:
|
138
|
+
expect(@db.view(Build.timeline(keys: ['2008-01-02']))).to be_empty
|
122
139
|
end
|
123
140
|
end
|
124
141
|
|
125
|
-
describe
|
126
|
-
it
|
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
|
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
|
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
|
143
|
-
it
|
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
|
153
|
-
it
|
154
|
-
CouchPotato.couchrest_database.save_doc({:
|
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
|
159
|
-
CouchPotato.couchrest_database.save_doc({:
|
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
|
164
|
-
doc = CouchPotato.couchrest_database.save_doc({:
|
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
|
169
|
-
CouchPotato.couchrest_database.save_doc({:
|
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
|
174
|
-
it
|
175
|
-
CouchPotato.couchrest_database.save_doc({:
|
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
|
180
|
-
CouchPotato.couchrest_database.save_doc({:
|
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
|
185
|
-
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym =>
|
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
|
193
|
-
it
|
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({:
|
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
|
200
|
-
it
|
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({:
|
203
|
-
expect(@db.view(Build.custom_count_with_reduce(:
|
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
|
210
|
-
it
|
211
|
-
expect(CouchPotato::View::ViewQuery).to receive(:new) do |
|
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',
|
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
|
221
|
-
it
|
222
|
-
@db.save_document Build.new(:
|
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
|
227
|
-
@db.save_document Build.new(:
|
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
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
240
|
-
it
|
241
|
-
@db.save_document CustomBuild.new(:
|
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
|
247
|
-
@db.save_document Build.new(:
|
248
|
-
@db.save_document CustomBuild.new(:
|
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
|
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, :
|
261
|
-
view :all, :
|
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
|
277
|
-
@db.save! Coworker.new(:
|
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
|
282
|
-
@db.save! Coworker.new(:
|
283
|
-
expect(@db.view(Coworker.all(:
|
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(:
|
405
|
+
expect(@db.view(Build.timeline(stale: 'ok'))).to be_empty
|
295
406
|
end
|
296
407
|
end
|
297
408
|
end
|