couchrest_model 1.1.2 → 1.2.0.beta
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.
- 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
|
|