couchrest_model 1.1.2 → 1.2.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -2
- data/VERSION +1 -1
- data/couchrest_model.gemspec +2 -1
- data/history.md +8 -0
- data/lib/couchrest/model/base.rb +0 -20
- data/lib/couchrest/model/configuration.rb +2 -0
- data/lib/couchrest/model/core_extensions/time_parsing.rb +35 -9
- data/lib/couchrest/model/designs/design.rb +182 -0
- data/lib/couchrest/model/designs/view.rb +91 -48
- data/lib/couchrest/model/designs.rb +72 -19
- data/lib/couchrest/model/document_queries.rb +15 -45
- data/lib/couchrest/model/properties.rb +43 -2
- data/lib/couchrest/model/proxyable.rb +20 -54
- data/lib/couchrest/model/typecast.rb +1 -1
- data/lib/couchrest/model/validations/uniqueness.rb +7 -6
- data/lib/couchrest_model.rb +1 -5
- data/spec/fixtures/models/article.rb +22 -20
- data/spec/fixtures/models/base.rb +15 -7
- data/spec/fixtures/models/course.rb +7 -4
- data/spec/fixtures/models/project.rb +4 -1
- data/spec/fixtures/models/sale_entry.rb +5 -3
- data/spec/unit/base_spec.rb +51 -5
- data/spec/unit/core_extensions/time_parsing.rb +41 -0
- data/spec/unit/designs/design_spec.rb +291 -0
- data/spec/unit/designs/view_spec.rb +135 -40
- data/spec/unit/designs_spec.rb +341 -30
- data/spec/unit/dirty_spec.rb +67 -0
- data/spec/unit/inherited_spec.rb +2 -2
- data/spec/unit/property_protection_spec.rb +3 -1
- data/spec/unit/property_spec.rb +43 -3
- data/spec/unit/proxyable_spec.rb +57 -98
- data/spec/unit/subclass_spec.rb +14 -5
- data/spec/unit/validations_spec.rb +14 -12
- metadata +172 -129
- data/lib/couchrest/model/class_proxy.rb +0 -135
- data/lib/couchrest/model/collection.rb +0 -273
- data/lib/couchrest/model/design_doc.rb +0 -115
- data/lib/couchrest/model/support/couchrest_design.rb +0 -33
- data/lib/couchrest/model/views.rb +0 -148
- data/spec/unit/class_proxy_spec.rb +0 -167
- data/spec/unit/collection_spec.rb +0 -86
- data/spec/unit/design_doc_spec.rb +0 -212
- data/spec/unit/view_spec.rb +0 -352
data/spec/unit/base_spec.rb
CHANGED
@@ -81,6 +81,53 @@ describe "Model Base" do
|
|
81
81
|
@doc.name.should eql("foobar")
|
82
82
|
end
|
83
83
|
end
|
84
|
+
describe "multipart attributes" do
|
85
|
+
context "with valid params" do
|
86
|
+
it "should parse a legal date" do
|
87
|
+
valid_date_params = { "exec_date(1i)"=>"2011",
|
88
|
+
"exec_date(2i)"=>"10",
|
89
|
+
"exec_date(3i)"=>"18"}
|
90
|
+
@obj = WithDateAndTime.new valid_date_params
|
91
|
+
@obj.exec_date.should_not be_nil
|
92
|
+
@obj.exec_date.should be_kind_of(Date)
|
93
|
+
@obj.exec_date.should == Date.new(2011, 10 ,18)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should parse a legal time" do
|
97
|
+
valid_time_params = { "exec_time(1i)"=>"2011",
|
98
|
+
"exec_time(2i)"=>"10",
|
99
|
+
"exec_time(3i)"=>"18",
|
100
|
+
"exec_time(4i)"=>"15",
|
101
|
+
"exec_time(5i)"=>"15",
|
102
|
+
"exec_time(6i)"=>"15",}
|
103
|
+
@obj = WithDateAndTime.new valid_time_params
|
104
|
+
@obj.exec_time.should_not be_nil
|
105
|
+
@obj.exec_time.should be_kind_of(Time)
|
106
|
+
@obj.exec_time.should == Time.utc(2011, 10 ,18, 15, 15, 15)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "with invalid params" do
|
111
|
+
before(:each) do
|
112
|
+
@invalid_date_params = { "exec_date(1i)"=>"2011",
|
113
|
+
"exec_date(2i)"=>"foo",
|
114
|
+
"exec_date(3i)"=>"18"}
|
115
|
+
end
|
116
|
+
it "should still create a model if there are invalid attributes" do
|
117
|
+
@obj = WithDateAndTime.new @invalid_date_params
|
118
|
+
@obj.should_not be_nil
|
119
|
+
@obj.should be_kind_of(WithDateAndTime)
|
120
|
+
end
|
121
|
+
it "should not crash because of an empty value" do
|
122
|
+
@invalid_date_params["exec_date(2i)"] = ""
|
123
|
+
@obj = WithDateAndTime.new @invalid_date_params
|
124
|
+
@obj.should_not be_nil
|
125
|
+
@obj.exec_date.should_not be_kind_of(Date)
|
126
|
+
@obj.should be_kind_of(WithDateAndTime)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
84
131
|
|
85
132
|
describe "ActiveModel compatability Basic" do
|
86
133
|
|
@@ -355,25 +402,24 @@ describe "Model Base" do
|
|
355
402
|
|
356
403
|
describe "counting all instances of a model" do
|
357
404
|
before(:each) do
|
358
|
-
|
405
|
+
reset_test_db!
|
359
406
|
end
|
360
|
-
|
407
|
+
|
361
408
|
it ".count should return 0 if there are no docuemtns" do
|
362
409
|
WithTemplateAndUniqueID.count.should == 0
|
363
410
|
end
|
364
|
-
|
411
|
+
|
365
412
|
it ".count should return the number of documents" do
|
366
413
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
367
414
|
WithTemplateAndUniqueID.new('slug' => '2').save
|
368
415
|
WithTemplateAndUniqueID.new('slug' => '3').save
|
369
|
-
|
370
416
|
WithTemplateAndUniqueID.count.should == 3
|
371
417
|
end
|
372
418
|
end
|
373
419
|
|
374
420
|
describe "finding the first instance of a model" do
|
375
421
|
before(:each) do
|
376
|
-
|
422
|
+
reset_test_db!
|
377
423
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
378
424
|
WithTemplateAndUniqueID.new('slug' => '2').save
|
379
425
|
WithTemplateAndUniqueID.new('slug' => '3').save
|
@@ -9,6 +9,47 @@ describe "Time Parsing core extension" do
|
|
9
9
|
Time.respond_to?("parse_iso8601").should be_true
|
10
10
|
end
|
11
11
|
|
12
|
+
describe "#as_json" do
|
13
|
+
|
14
|
+
it "should convert local time to JSON string" do
|
15
|
+
time = Time.new(2011, 04, 01, 19, 05, 30, "+02:00")
|
16
|
+
time.as_json.should eql("2011-04-01T19:05:30.000+02:00")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should convert utc time to JSON string" do
|
20
|
+
time = Time.utc(2011, 04, 01, 19, 05, 30)
|
21
|
+
time.as_json.should eql("2011-04-01T19:05:30.000Z")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should convert local time with fraction to JSON" do
|
25
|
+
time = Time.new(2011, 04, 01, 19, 05, 30.123, "+02:00")
|
26
|
+
time.as_json.should eql("2011-04-01T19:05:30.123+02:00")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should convert utc time with fraction to JSON" do
|
30
|
+
time = Time.utc(2011, 04, 01, 19, 05, 30.123)
|
31
|
+
time.as_json.should eql("2011-04-01T19:05:30.123Z")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow fraction digits" do
|
35
|
+
time = Time.utc(2011, 04, 01, 19, 05, 30.123456)
|
36
|
+
time.as_json(:fraction_digits => 6).should eql("2011-04-01T19:05:30.123456Z")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should use CouchRest::Model::Base.time_fraction_digits config option" do
|
40
|
+
CouchRest::Model::Base.time_fraction_digits = 6
|
41
|
+
time = Time.utc(2011, 04, 01, 19, 05, 30.123456)
|
42
|
+
time.as_json.should eql("2011-04-01T19:05:30.123456Z")
|
43
|
+
CouchRest::Model::Base.time_fraction_digits = 3 # Back to normal
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should cope with a nil options parameter" do
|
47
|
+
time = Time.utc(2011, 04, 01, 19, 05, 30.123456)
|
48
|
+
lambda { time.as_json(nil) }.should_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
12
53
|
describe ".parse_iso8601" do
|
13
54
|
|
14
55
|
describe "parsing" do
|
@@ -0,0 +1,291 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe CouchRest::Model::Designs::Design do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
reset_test_db!
|
9
|
+
end
|
10
|
+
|
11
|
+
class DesignSampleModel < CouchRest::Model::Base
|
12
|
+
use_database DB
|
13
|
+
property :name
|
14
|
+
property :surname
|
15
|
+
design do
|
16
|
+
view :by_name
|
17
|
+
end
|
18
|
+
design :stats do
|
19
|
+
view :by_surname
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "class methods" do
|
24
|
+
|
25
|
+
before :all do
|
26
|
+
@klass = CouchRest::Model::Designs::Design
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".method_name" do
|
30
|
+
it "should return standard method name" do
|
31
|
+
@klass.method_name.should eql('design_doc')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should add prefix to standard method name" do
|
35
|
+
@klass.method_name('stats').should eql('stats_design_doc')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "base methods" do
|
42
|
+
|
43
|
+
before :each do
|
44
|
+
@model = mock("ModelExample")
|
45
|
+
@model.stub(:to_s).and_return("ModelExample")
|
46
|
+
@obj = CouchRest::Model::Designs::Design.new(@model)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
describe "initialisation without prefix" do
|
51
|
+
it "should associate model and set method name" do
|
52
|
+
@obj.model.should eql(@model)
|
53
|
+
@obj.method_name.should eql("design_doc")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should generate correct id" do
|
57
|
+
@obj['_id'].should eql("_design/ModelExample")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should apply defaults" do
|
61
|
+
@obj['language'].should eql('javascript')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "initialisation with prefix" do
|
66
|
+
|
67
|
+
it "should associate model and set method name" do
|
68
|
+
@obj = CouchRest::Model::Designs::Design.new(@model, 'stats')
|
69
|
+
@obj.model.should eql(@model)
|
70
|
+
@obj.method_name.should eql("stats_design_doc")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should generate correct id with prefix" do
|
74
|
+
@obj = CouchRest::Model::Designs::Design.new(@model, 'stats')
|
75
|
+
@obj['_id'].should eql("_design/ModelExample_stats")
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
describe "#sync and #sync!" do
|
83
|
+
|
84
|
+
it "should skip if auto update disabled" do
|
85
|
+
@obj.auto_update = false
|
86
|
+
@obj.should_not_receive(:sync!)
|
87
|
+
@obj.sync
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "with real model" do
|
91
|
+
|
92
|
+
before :all do
|
93
|
+
reset_test_db!
|
94
|
+
@mod = DesignSampleModel
|
95
|
+
@doc = @mod.design_doc
|
96
|
+
@db = @mod.database
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should not have been saved up until sync called" do
|
100
|
+
lambda { @mod.database.get(@doc['_id']) }.should raise_error(RestClient::ResourceNotFound)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
it "should save a design that is in cache and has changed" do
|
105
|
+
@doc.sync # put in cache
|
106
|
+
@doc['views']['all']['map'] += '// comment'
|
107
|
+
# This would fail if changes were not detected!
|
108
|
+
@doc.sync
|
109
|
+
doc = @db.get(@doc['_id'])
|
110
|
+
doc['views']['all']['map'].should eql(@doc['views']['all']['map'])
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not save a design that is not in cache and has not changed" do
|
114
|
+
@doc.sync # put doc in cache
|
115
|
+
@doc.send(:set_cache_checksum, @doc.database, nil)
|
116
|
+
|
117
|
+
@db.should_not_receive(:save_doc)
|
118
|
+
@doc.should_receive(:set_cache_checksum)
|
119
|
+
@doc.sync
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should not reload a design that is in cache and has not changed" do
|
123
|
+
@doc.sync
|
124
|
+
@doc.should_not_receive(:load_from_database)
|
125
|
+
@doc.sync
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should be re-created if database destroyed" do
|
129
|
+
@doc.sync # saved
|
130
|
+
reset_test_db!
|
131
|
+
@db.should_receive(:save_doc).with(@doc)
|
132
|
+
@doc.sync
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should not update the local design definition" do
|
136
|
+
@doc.sync!
|
137
|
+
doc = @db.get(@doc['_id'])
|
138
|
+
doc['views']['test'] = {'map' => "function(d) { if (d) { emit(d._id, null); } }"}
|
139
|
+
@db.save_doc(doc)
|
140
|
+
@doc.send(:set_cache_checksum, @doc.database, nil)
|
141
|
+
@doc.sync
|
142
|
+
@doc['views'].should_not have_key('test')
|
143
|
+
@doc['_rev'].should be_nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should save a non existant design" do
|
147
|
+
begin
|
148
|
+
doc = @db.get(@doc['_id'])
|
149
|
+
rescue
|
150
|
+
doc = nil
|
151
|
+
end
|
152
|
+
@db.delete_doc(doc) if doc
|
153
|
+
@doc.sync!
|
154
|
+
doc = @db.get(@doc['_id'])
|
155
|
+
doc.should_not be_nil
|
156
|
+
doc['views']['all'].should eql(@doc['views']['all'])
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
describe "checksum" do
|
164
|
+
|
165
|
+
before :all do
|
166
|
+
@mod = DesignSampleModel
|
167
|
+
@doc = @mod.design_doc
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should return fresh checksum when not calculated earlier" do
|
171
|
+
@doc.checksum.should_not be_blank
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should provide same checksum without refresh on re-request" do
|
175
|
+
chk = @doc.checksum
|
176
|
+
@doc.should_not_receive(:chaecksum!)
|
177
|
+
@doc.checksum.should eql(chk)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should provide new checksum if the design has changed" do
|
181
|
+
chk = @doc.checksum
|
182
|
+
@doc['views']['all']['map'] += '// comment'
|
183
|
+
@doc.checksum.should_not eql(chk)
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "database" do
|
189
|
+
it "should provide model's database" do
|
190
|
+
@mod = DesignSampleModel
|
191
|
+
@doc = @mod.design_doc
|
192
|
+
@mod.should_receive(:database)
|
193
|
+
@doc.database
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
describe "#uri" do
|
199
|
+
it "should provide complete url" do
|
200
|
+
@doc = DesignSampleModel.design_doc
|
201
|
+
@doc.uri.should eql("#{DesignSampleModel.database.root}/_design/DesignSampleModel")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "#view" do
|
206
|
+
it "should instantiate a new view and pass options" do
|
207
|
+
CouchRest::Model::Designs::View.should_receive(:new).with(@obj, @model, {}, 'by_test')
|
208
|
+
@obj.view('by_test', {})
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "#view_names" do
|
213
|
+
it "should provide a list of all the views available" do
|
214
|
+
@doc = DesignSampleModel.design_doc
|
215
|
+
@doc.view_names.should eql(['by_name', 'all'])
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "#has_view?" do
|
220
|
+
before :each do
|
221
|
+
@doc = DesignSampleModel.design_doc
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should tell us if a view exists" do
|
225
|
+
@doc.has_view?('by_name').should be_true
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should tell us if a view exists as symbol" do
|
229
|
+
@doc.has_view?(:by_name).should be_true
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should tell us if a view does not exist" do
|
233
|
+
@doc.has_view?(:by_foobar).should be_false
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "#create_view" do
|
238
|
+
before :each do
|
239
|
+
@doc = DesignSampleModel.design_doc
|
240
|
+
@doc['views'] = @doc['views'].clone
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should forward view creation to View model" do
|
244
|
+
CouchRest::Model::Designs::View.should_receive(:define_and_create).with(@doc, 'by_other_name', {})
|
245
|
+
@doc.create_view('by_other_name')
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should forward view creation to View model with opts" do
|
249
|
+
CouchRest::Model::Designs::View.should_receive(:define_and_create).with(@doc, 'by_other_name', {:by => 'name'})
|
250
|
+
@doc.create_view('by_other_name', :by => 'name')
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
describe "#create_filter" do
|
256
|
+
before :each do
|
257
|
+
@doc = DesignSampleModel.design_doc
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should add simple filter" do
|
261
|
+
@doc.create_filter('test', 'foobar')
|
262
|
+
@doc['filters']['test'].should eql('foobar')
|
263
|
+
@doc['filters'] = nil # cleanup
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
describe "Checksum calculations" do
|
271
|
+
|
272
|
+
it "should calculate a consistent checksum for model" do
|
273
|
+
#WithTemplateAndUniqueID.design_doc.checksum.should eql('caa2b4c27abb82b4e37421de76d96ffc')
|
274
|
+
WithTemplateAndUniqueID.design_doc.checksum.should eql('f0973aaa72e4db0efeb2a281ea297cec')
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should calculate checksum for complex model" do
|
278
|
+
#Article.design_doc.checksum.should eql('70dff8caea143bf40fad09adf0701104')
|
279
|
+
Article.design_doc.checksum.should eql('7ef39bffdf5837e8b078411ac417d860')
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should cache the generated checksum value" do
|
283
|
+
Article.design_doc.checksum
|
284
|
+
Article.design_doc['couchrest-hash'].should_not be_blank
|
285
|
+
Article.first
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
end
|
@@ -16,6 +16,7 @@ describe "Design View" do
|
|
16
16
|
describe "(unit tests)" do
|
17
17
|
|
18
18
|
before :each do
|
19
|
+
@mod = DesignViewModel
|
19
20
|
@klass = CouchRest::Model::Designs::View
|
20
21
|
end
|
21
22
|
|
@@ -30,14 +31,15 @@ describe "Design View" do
|
|
30
31
|
describe "with CouchRest Model" do
|
31
32
|
|
32
33
|
it "should setup attributes" do
|
33
|
-
@obj = @klass.new(
|
34
|
-
@obj.
|
34
|
+
@obj = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
|
35
|
+
@obj.design_doc.should eql(@mod.design_doc)
|
36
|
+
@obj.model.should eql(@mod)
|
35
37
|
@obj.name.should eql('test_view')
|
36
38
|
@obj.query.should be_empty
|
37
39
|
end
|
38
40
|
|
39
41
|
it "should complain if there is no name" do
|
40
|
-
lambda { @klass.new(
|
42
|
+
lambda { @klass.new(@mod.design_doc, @mod, {}, nil) }.should raise_error(/Name must be provided/)
|
41
43
|
end
|
42
44
|
|
43
45
|
end
|
@@ -45,56 +47,142 @@ describe "Design View" do
|
|
45
47
|
describe "with previous view instance" do
|
46
48
|
|
47
49
|
before :each do
|
48
|
-
first = @klass.new(
|
49
|
-
@obj = @klass.new(first, {:foo => :bar})
|
50
|
+
first = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
|
51
|
+
@obj = @klass.new(@mod.design_doc, first, {:foo => :bar})
|
50
52
|
end
|
51
53
|
|
52
54
|
it "should copy attributes" do
|
53
|
-
@obj.model.should eql(
|
55
|
+
@obj.model.should eql(@mod)
|
54
56
|
@obj.name.should eql('test_view')
|
55
57
|
@obj.query.should eql({:foo => :bar})
|
56
58
|
end
|
57
59
|
|
58
60
|
end
|
59
61
|
|
60
|
-
|
62
|
+
describe "with proxy in query for first initialization" do
|
63
|
+
it "should set model to proxy object and remove from query" do
|
64
|
+
proxy = mock("Proxy")
|
65
|
+
@obj = @klass.new(@mod.design_doc, @mod, {:proxy => proxy}, 'test_view')
|
66
|
+
@obj.model.should eql(proxy)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "with proxy in query for chained instance" do
|
71
|
+
it "should set the model to proxy object instead of parents model" do
|
72
|
+
proxy = mock("Proxy")
|
73
|
+
@obj = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
|
74
|
+
@obj.model.should eql(@mod)
|
75
|
+
@obj = @obj.proxy(proxy)
|
76
|
+
@obj.model.should eql(proxy)
|
77
|
+
end
|
78
|
+
end
|
61
79
|
|
62
|
-
|
80
|
+
end
|
63
81
|
|
82
|
+
describe ".define_and_create" do
|
64
83
|
before :each do
|
65
|
-
@design_doc = {}
|
66
|
-
DesignViewModel.stub!(:design_doc).and_return(@design_doc)
|
84
|
+
@design_doc = { }
|
67
85
|
end
|
68
86
|
|
69
|
-
it "should
|
70
|
-
@klass.
|
71
|
-
@design_doc
|
87
|
+
it "should call define and create_model_methods method" do
|
88
|
+
@klass.should_receive(:define).with(@design_doc, 'test', {}).and_return(nil)
|
89
|
+
@klass.should_receive(:create_model_methods).with(@design_doc, 'test', {}).and_return(nil)
|
90
|
+
@klass.define_and_create(@design_doc, 'test')
|
72
91
|
end
|
73
92
|
|
74
|
-
it "should
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
str.should include("emit(doc['title'], 1);")
|
79
|
-
str = @design_doc['views']['by_title']['reduce']
|
80
|
-
str.should include("return sum(values);")
|
93
|
+
it "should call define and create_model_methods method with opts" do
|
94
|
+
@klass.should_receive(:define).with(@design_doc, 'test', {:foo => :bar}).and_return(nil)
|
95
|
+
@klass.should_receive(:create_model_methods).with(@design_doc, 'test', {:foo => :bar}).and_return(nil)
|
96
|
+
@klass.define_and_create(@design_doc, 'test', {:foo => :bar})
|
81
97
|
end
|
82
98
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
describe ".define" do
|
102
|
+
|
103
|
+
describe "with no auto update" do
|
104
|
+
before :each do
|
105
|
+
@design_doc = { }
|
106
|
+
@design_doc.stub!(:model).and_return(DesignViewModel)
|
107
|
+
@design_doc.stub!(:auto_update).and_return(false)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should set map view to true" do
|
111
|
+
@klass.define(@design_doc, 'test_view')
|
112
|
+
@design_doc['views']['test_view']['map'].should eql(true)
|
113
|
+
@design_doc['views']['test_view']['reduce'].should be_false
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should set reduce to true if set" do
|
117
|
+
@klass.define(@design_doc, 'test_view', :reduce => true)
|
118
|
+
@design_doc['views']['test_view']['map'].should eql(true)
|
119
|
+
@design_doc['views']['test_view']['reduce'].should eql(true)
|
120
|
+
end
|
90
121
|
end
|
91
122
|
|
123
|
+
describe "with auto update" do
|
124
|
+
|
125
|
+
before :each do
|
126
|
+
@design_doc = { }
|
127
|
+
@design_doc.stub!(:model).and_return(DesignViewModel)
|
128
|
+
@design_doc.stub!(:auto_update).and_return(true)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should add a basic view" do
|
132
|
+
@klass.define(@design_doc, 'test_view', :map => 'foo')
|
133
|
+
@design_doc['views']['test_view'].should_not be_nil
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should auto generate mapping from name" do
|
137
|
+
lambda { @klass.define(@design_doc, 'by_title') }.should_not raise_error
|
138
|
+
str = @design_doc['views']['by_title']['map']
|
139
|
+
str.should include("((doc['#{DesignViewModel.model_type_key}'] == 'DesignViewModel') && (doc['title'] != null))")
|
140
|
+
str.should include("emit(doc['title'], 1);")
|
141
|
+
str = @design_doc['views']['by_title']['reduce']
|
142
|
+
str.should include("return sum(values);")
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should auto generate mapping from name with and" do
|
146
|
+
@klass.define(@design_doc, 'by_title_and_name')
|
147
|
+
str = @design_doc['views']['by_title_and_name']['map']
|
148
|
+
str.should include("(doc['title'] != null) && (doc['name'] != null)")
|
149
|
+
str.should include("emit([doc['title'], doc['name']], 1);")
|
150
|
+
str = @design_doc['views']['by_title_and_name']['reduce']
|
151
|
+
str.should include("return sum(values);")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe ".create_model_methods" do
|
156
|
+
before :each do
|
157
|
+
@model = DesignViewModel
|
158
|
+
@design_doc = { }
|
159
|
+
@design_doc.stub!(:model).and_return(@model)
|
160
|
+
@design_doc.stub!(:method_name).and_return("design_doc")
|
161
|
+
@model.stub!('design_doc').and_return(@design_doc)
|
162
|
+
end
|
163
|
+
it "should create standard view method" do
|
164
|
+
@klass.create_model_methods(@design_doc, 'by_name')
|
165
|
+
@model.should respond_to('by_name')
|
166
|
+
@design_doc.should_receive('view').with('by_name', {})
|
167
|
+
@model.by_name
|
168
|
+
end
|
169
|
+
it "should create find_ view method" do
|
170
|
+
@klass.create_model_methods(@design_doc, 'by_name')
|
171
|
+
@model.should respond_to('find_by_name')
|
172
|
+
view = mock("View")
|
173
|
+
view.should_receive('key').with('fred').and_return(view)
|
174
|
+
view.should_receive('first').and_return(nil)
|
175
|
+
@design_doc.should_receive('view').and_return(view)
|
176
|
+
@model.find_by_name('fred')
|
177
|
+
end
|
178
|
+
end
|
92
179
|
end
|
93
180
|
|
181
|
+
|
94
182
|
describe "instance methods" do
|
95
183
|
|
96
184
|
before :each do
|
97
|
-
@obj = @klass.new(
|
185
|
+
@obj = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
|
98
186
|
end
|
99
187
|
|
100
188
|
describe "#rows" do
|
@@ -468,6 +556,20 @@ describe "Design View" do
|
|
468
556
|
end
|
469
557
|
end
|
470
558
|
|
559
|
+
describe "#stale" do
|
560
|
+
it "should update query with ok" do
|
561
|
+
@obj.should_receive(:update_query).with(:stale => 'ok')
|
562
|
+
@obj.stale('ok')
|
563
|
+
end
|
564
|
+
it "should update query with update_after" do
|
565
|
+
@obj.should_receive(:update_query).with(:stale => 'update_after')
|
566
|
+
@obj.stale('update_after')
|
567
|
+
end
|
568
|
+
it "should fail if anything else is provided" do
|
569
|
+
lambda { @obj.stale('yes') }.should raise_error(/can only be set with/)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
471
573
|
describe "#include_docs" do
|
472
574
|
it "should call include_docs! on new view" do
|
473
575
|
@obj.should_receive(:update_query).and_return(@obj)
|
@@ -532,13 +634,6 @@ describe "Design View" do
|
|
532
634
|
end
|
533
635
|
end
|
534
636
|
|
535
|
-
describe "#design_doc" do
|
536
|
-
it "should call design_doc on model" do
|
537
|
-
@obj.model.should_receive(:design_doc)
|
538
|
-
@obj.send(:design_doc)
|
539
|
-
end
|
540
|
-
end
|
541
|
-
|
542
637
|
describe "#can_reduce?" do
|
543
638
|
it "should check and prove true" do
|
544
639
|
@obj.should_receive(:name).and_return('test_view')
|
@@ -557,8 +652,8 @@ describe "Design View" do
|
|
557
652
|
# disable real execution!
|
558
653
|
@design_doc = mock("DesignDoc")
|
559
654
|
@design_doc.stub!(:view_on)
|
560
|
-
@
|
561
|
-
@obj.
|
655
|
+
@design_doc.stub!(:sync)
|
656
|
+
@obj.stub!(:design_doc).and_return(@design_doc)
|
562
657
|
end
|
563
658
|
|
564
659
|
it "should return previous result if set" do
|
@@ -582,7 +677,7 @@ describe "Design View" do
|
|
582
677
|
|
583
678
|
it "should call to save the design document" do
|
584
679
|
@obj.should_receive(:can_reduce?).and_return(false)
|
585
|
-
@
|
680
|
+
@design_doc.should_receive(:sync).with(DB)
|
586
681
|
@obj.send(:execute)
|
587
682
|
end
|
588
683
|
|
@@ -595,9 +690,9 @@ describe "Design View" do
|
|
595
690
|
|
596
691
|
it "should remove nil values from query" do
|
597
692
|
@obj.should_receive(:can_reduce?).and_return(true)
|
598
|
-
@obj.stub!(:use_database).and_return(
|
693
|
+
@obj.stub!(:use_database).and_return(@mod.database)
|
599
694
|
@obj.query = {:reduce => true, :limit => nil, :skip => nil}
|
600
|
-
@design_doc.should_receive(:view_on).with(
|
695
|
+
@design_doc.should_receive(:view_on).with(@mod.database, 'test_view', {:reduce => true})
|
601
696
|
@obj.send(:execute)
|
602
697
|
end
|
603
698
|
|