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.
Files changed (43) hide show
  1. data/README.md +8 -2
  2. data/VERSION +1 -1
  3. data/couchrest_model.gemspec +2 -1
  4. data/history.md +8 -0
  5. data/lib/couchrest/model/base.rb +0 -20
  6. data/lib/couchrest/model/configuration.rb +2 -0
  7. data/lib/couchrest/model/core_extensions/time_parsing.rb +35 -9
  8. data/lib/couchrest/model/designs/design.rb +182 -0
  9. data/lib/couchrest/model/designs/view.rb +91 -48
  10. data/lib/couchrest/model/designs.rb +72 -19
  11. data/lib/couchrest/model/document_queries.rb +15 -45
  12. data/lib/couchrest/model/properties.rb +43 -2
  13. data/lib/couchrest/model/proxyable.rb +20 -54
  14. data/lib/couchrest/model/typecast.rb +1 -1
  15. data/lib/couchrest/model/validations/uniqueness.rb +7 -6
  16. data/lib/couchrest_model.rb +1 -5
  17. data/spec/fixtures/models/article.rb +22 -20
  18. data/spec/fixtures/models/base.rb +15 -7
  19. data/spec/fixtures/models/course.rb +7 -4
  20. data/spec/fixtures/models/project.rb +4 -1
  21. data/spec/fixtures/models/sale_entry.rb +5 -3
  22. data/spec/unit/base_spec.rb +51 -5
  23. data/spec/unit/core_extensions/time_parsing.rb +41 -0
  24. data/spec/unit/designs/design_spec.rb +291 -0
  25. data/spec/unit/designs/view_spec.rb +135 -40
  26. data/spec/unit/designs_spec.rb +341 -30
  27. data/spec/unit/dirty_spec.rb +67 -0
  28. data/spec/unit/inherited_spec.rb +2 -2
  29. data/spec/unit/property_protection_spec.rb +3 -1
  30. data/spec/unit/property_spec.rb +43 -3
  31. data/spec/unit/proxyable_spec.rb +57 -98
  32. data/spec/unit/subclass_spec.rb +14 -5
  33. data/spec/unit/validations_spec.rb +14 -12
  34. metadata +172 -129
  35. data/lib/couchrest/model/class_proxy.rb +0 -135
  36. data/lib/couchrest/model/collection.rb +0 -273
  37. data/lib/couchrest/model/design_doc.rb +0 -115
  38. data/lib/couchrest/model/support/couchrest_design.rb +0 -33
  39. data/lib/couchrest/model/views.rb +0 -148
  40. data/spec/unit/class_proxy_spec.rb +0 -167
  41. data/spec/unit/collection_spec.rb +0 -86
  42. data/spec/unit/design_doc_spec.rb +0 -212
  43. data/spec/unit/view_spec.rb +0 -352
@@ -148,141 +148,101 @@ describe CouchRest::Model::Proxyable do
148
148
  @klass = CouchRest::Model::Proxyable::ModelProxy
149
149
  end
150
150
 
151
- it "should initialize and set variables" do
152
- @obj = @klass.new(Cat, 'owner', 'owner_name', 'database')
153
- @obj.model.should eql(Cat)
154
- @obj.owner.should eql('owner')
155
- @obj.owner_name.should eql('owner_name')
156
- @obj.database.should eql('database')
151
+ before :each do
152
+ @design_doc = mock('Design')
153
+ @design_doc.stub!(:view_names).and_return(['all', 'by_name'])
154
+ @model = mock('Cat')
155
+ @model.stub!(:design_docs).and_return([@design_doc])
156
+ @obj = @klass.new(@model, 'owner', 'owner_name', 'database')
157
157
  end
158
158
 
159
- describe "instance" do
159
+ describe "initialization" do
160
160
 
161
- before :each do
162
- @obj = @klass.new(Cat, 'owner', 'owner_name', 'database')
161
+ it "should set base attributes" do
162
+ @obj.model.should eql(@model)
163
+ @obj.owner.should eql('owner')
164
+ @obj.owner_name.should eql('owner_name')
165
+ @obj.database.should eql('database')
163
166
  end
164
167
 
165
- it "should proxy new call" do
166
- @obj.should_receive(:proxy_block_update).with(:new, 'attrs', 'opts')
167
- @obj.new('attrs', 'opts')
168
+ it "should create view methods" do
169
+ @obj.should respond_to('all')
170
+ @obj.should respond_to('by_name')
171
+ @obj.should respond_to('find_all')
172
+ @obj.should respond_to('find_by_name')
168
173
  end
169
174
 
170
- it "should proxy build_from_database" do
171
- @obj.should_receive(:proxy_block_update).with(:build_from_database, 'attrs', 'opts')
172
- @obj.build_from_database('attrs', 'opts')
175
+ it "should create 'all' view method that forward to model's view with proxy" do
176
+ @model.should_receive(:all).with(:proxy => @obj).and_return(nil)
177
+ @obj.all
173
178
  end
174
179
 
175
- describe "#method_missing" do
176
- it "should return design view object" do
177
- m = "by_some_property"
178
- inst = mock('DesignView')
179
- inst.stub!(:proxy).and_return(inst)
180
- @obj.should_receive(:has_view?).with(m).and_return(true)
181
- Cat.should_receive(:respond_to?).with(m).and_return(true)
182
- Cat.should_receive(:send).with(m).and_return(inst)
183
- @obj.method_missing(m).should eql(inst)
184
- end
180
+ it "should create 'by_name' view method that forward to model's view with proxy" do
181
+ @model.should_receive(:by_name).with(:proxy => @obj).and_return(nil)
182
+ @obj.by_name
183
+ end
185
184
 
186
- it "should call view if necessary" do
187
- m = "by_some_property"
188
- @obj.should_receive(:has_view?).with(m).and_return(true)
189
- Cat.should_receive(:respond_to?).with(m).and_return(false)
190
- @obj.should_receive(:view).with(m, {}).and_return('view')
191
- @obj.method_missing(m).should eql('view')
192
- end
185
+ it "should create 'find_by_name' view that forwards to normal view" do
186
+ view = mock('view')
187
+ view.should_receive('key').with('name').and_return(view)
188
+ view.should_receive('first').and_return(nil)
189
+ @obj.should_receive(:by_name).and_return(view)
190
+ @obj.find_by_name('name')
191
+ end
193
192
 
194
- it "should provide wrapper for #first_from_view" do
195
- m = "find_by_some_property"
196
- view = "by_some_property"
197
- @obj.should_receive(:has_view?).with(m).and_return(false)
198
- @obj.should_receive(:has_view?).with(view).and_return(true)
199
- @obj.should_receive(:first_from_view).with(view).and_return('view')
200
- @obj.method_missing(m).should eql('view')
201
- end
193
+ end
202
194
 
195
+ describe "instance" do
196
+
197
+ it "should proxy new call" do
198
+ @obj.should_receive(:proxy_block_update).with(:new, 'attrs', 'opts')
199
+ @obj.new('attrs', 'opts')
203
200
  end
204
201
 
205
- it "should proxy #all" do
206
- Cat.should_receive(:all).with({:database => 'database'})
207
- @obj.should_receive(:proxy_update_all)
208
- @obj.all
202
+ it "should proxy build_from_database" do
203
+ @obj.should_receive(:proxy_block_update).with(:build_from_database, 'attrs', 'opts')
204
+ @obj.build_from_database('attrs', 'opts')
209
205
  end
210
-
206
+
211
207
  it "should proxy #count" do
212
- Cat.should_receive(:all).with({:database => 'database', :raw => true, :limit => 0}).and_return({'total_rows' => 3})
213
- @obj.count.should eql(3)
208
+ view = mock('View')
209
+ view.should_receive(:count).and_return(nil)
210
+ @model.should_receive(:all).and_return(view)
211
+ @obj.count
214
212
  end
215
213
 
216
214
  it "should proxy #first" do
217
- Cat.should_receive(:first).with({:database => 'database'})
218
- @obj.should_receive(:proxy_update)
215
+ view = mock('View')
216
+ view.should_receive(:first).and_return(nil)
217
+ @model.should_receive(:all).and_return(view)
219
218
  @obj.first
220
219
  end
221
220
 
222
221
  it "should proxy #last" do
223
- Cat.should_receive(:last).with({:database => 'database'})
224
- @obj.should_receive(:proxy_update)
222
+ view = mock('View')
223
+ view.should_receive(:last).and_return(nil)
224
+ @model.should_receive(:all).and_return(view)
225
225
  @obj.last
226
226
  end
227
227
 
228
228
  it "should proxy #get" do
229
- Cat.should_receive(:get).with(32, 'database')
229
+ @model.should_receive(:get).with(32, 'database')
230
230
  @obj.should_receive(:proxy_update)
231
231
  @obj.get(32)
232
232
  end
233
233
  it "should proxy #find" do
234
- Cat.should_receive(:get).with(32, 'database')
234
+ @model.should_receive(:get).with(32, 'database')
235
235
  @obj.should_receive(:proxy_update)
236
236
  @obj.find(32)
237
237
  end
238
238
 
239
- it "should proxy #has_view?" do
240
- Cat.should_receive(:has_view?).with('view').and_return(false)
241
- @obj.has_view?('view')
242
- end
243
-
244
- it "should proxy #view_by" do
245
- Cat.should_receive(:view_by).with('name').and_return(false)
246
- @obj.view_by('name')
247
- end
248
-
249
- it "should proxy #view" do
250
- Cat.should_receive(:view).with('view', {:database => 'database'})
251
- @obj.should_receive(:proxy_update_all)
252
- @obj.view('view')
253
- end
254
-
255
- it "should proxy #first_from_view" do
256
- Cat.should_receive(:first_from_view).with('view', {:database => 'database'})
257
- @obj.should_receive(:proxy_update)
258
- @obj.first_from_view('view')
259
- end
260
-
261
- it "should proxy design_doc" do
262
- Cat.should_receive(:design_doc)
263
- @obj.design_doc
264
- end
265
-
266
- describe "#save_design_doc" do
267
- it "should be proxied without args" do
268
- Cat.should_receive(:save_design_doc).with('database')
269
- @obj.save_design_doc
270
- end
271
-
272
- it "should be proxied with database arg" do
273
- Cat.should_receive(:save_design_doc).with('db')
274
- @obj.save_design_doc('db')
275
- end
276
- end
277
-
278
-
279
239
 
280
240
  ### Updating methods
281
241
 
282
242
  describe "#proxy_update" do
283
243
  it "should set returned doc fields" do
284
244
  doc = mock(:Document)
285
- doc.should_receive(:is_a?).with(Cat).and_return(true)
245
+ doc.should_receive(:is_a?).with(@model).and_return(true)
286
246
  doc.should_receive(:database=).with('database')
287
247
  doc.should_receive(:model_proxy=).with(@obj)
288
248
  doc.should_receive(:send).with('owner_name=', 'owner')
@@ -291,7 +251,7 @@ describe CouchRest::Model::Proxyable do
291
251
 
292
252
  it "should not set anything if matching document not provided" do
293
253
  doc = mock(:DocumentFoo)
294
- doc.should_receive(:is_a?).with(Cat).and_return(false)
254
+ doc.should_receive(:is_a?).with(@model).and_return(false)
295
255
  doc.should_not_receive(:database=)
296
256
  doc.should_not_receive(:model_proxy=)
297
257
  doc.should_not_receive(:owner_name=)
@@ -343,13 +303,12 @@ describe CouchRest::Model::Proxyable do
343
303
  view :by_total
344
304
  end
345
305
  end
346
-
347
-
348
306
  @company = ProxyableCompany.create(:slug => 'samco')
349
307
  end
350
308
 
351
309
  it "should create the new database" do
352
- @company.proxyable_invoices.all.should be_empty
310
+ view = @company.proxyable_invoices.all
311
+ view.should be_empty
353
312
  TEST_SERVER.databases.find{|db| db =~ /#{TESTDB}-samco/}.should_not be_nil
354
313
  end
355
314
 
@@ -17,13 +17,17 @@ end
17
17
 
18
18
  class OnlineCourse < Course
19
19
  property :url
20
- view_by :url
20
+ design do
21
+ view :by_url
22
+ end
21
23
  end
22
24
 
23
25
  class Animal < CouchRest::Model::Base
24
26
  use_database TEST_SERVER.default_database
25
27
  property :name
26
- view_by :name
28
+ design do
29
+ view :by_name
30
+ end
27
31
  end
28
32
 
29
33
  class Dog < Animal; end
@@ -67,19 +71,24 @@ describe "Subclassing a Model" do
67
71
  end
68
72
 
69
73
  it "should have a design doc slug based on the subclass name" do
70
- OnlineCourse.design_doc_slug.should =~ /^OnlineCourse/
74
+ OnlineCourse.design_doc['_id'].should =~ /OnlineCourse$/
71
75
  end
72
76
 
73
77
  it "should not add views to the parent's design_doc" do
74
78
  Course.design_doc['views'].keys.should_not include('by_url')
75
79
  end
76
80
 
77
- it "should not add the parent's views to its design doc" do
78
- OnlineCourse.design_doc['views'].keys.should_not include('by_title')
81
+ it "should add the parent's views to its design doc" do
82
+ OnlineCourse.design_doc['views'].keys.should include('by_title')
83
+ end
84
+
85
+ it "should add the parent's views but alter the model names in map function" do
86
+ OnlineCourse.design_doc['views']['by_title']['map'].should =~ /doc\['#{OnlineCourse.model_type_key}'\] == 'OnlineCourse'/
79
87
  end
80
88
 
81
89
  it "should have an all view with a guard clause for model == subclass name in the map function" do
82
90
  OnlineCourse.design_doc['views']['all']['map'].should =~ /if \(doc\['#{OnlineCourse.model_type_key}'\] == 'OnlineCourse'\)/
83
91
  end
92
+
84
93
  end
85
94
 
@@ -10,7 +10,7 @@ describe CouchRest::Model::Validations do
10
10
  end
11
11
 
12
12
  it "should create a new view if none defined before performing" do
13
- WithUniqueValidation.has_view?(:by_title).should be_true
13
+ WithUniqueValidation.design_doc.has_view?(:by_title).should be_true
14
14
  end
15
15
 
16
16
  it "should validate a new unique document" do
@@ -49,16 +49,14 @@ describe CouchRest::Model::Validations do
49
49
 
50
50
  it "should not try to create a defined view" do
51
51
  WithUniqueValidationView.validates_uniqueness_of :title, :view => 'fooobar'
52
- WithUniqueValidationView.has_view?('fooobar').should be_false
53
- WithUniqueValidationView.has_view?('by_title').should be_false
52
+ WithUniqueValidationView.design_doc.has_view?('fooobar').should be_false
53
+ WithUniqueValidationView.design_doc.has_view?('by_title').should be_false
54
54
  end
55
55
 
56
56
 
57
57
  it "should not try to create new view when already defined" do
58
58
  @obj = @objs[1]
59
- @obj.class.should_not_receive('view_by')
60
- @obj.class.should_receive('has_view?').and_return(true)
61
- @obj.class.should_receive('view').and_return({'rows' => [ ]})
59
+ @obj.class.design_doc.should_not_receive('create_view')
62
60
  @obj.valid?
63
61
  end
64
62
  end
@@ -66,7 +64,7 @@ describe CouchRest::Model::Validations do
66
64
  context "with a proxy parameter" do
67
65
 
68
66
  it "should create a new view despite proxy" do
69
- WithUniqueValidationProxy.has_view?(:by_title).should be_true
67
+ WithUniqueValidationProxy.design_doc.has_view?(:by_title).should be_true
70
68
  end
71
69
 
72
70
  it "should be used" do
@@ -77,19 +75,23 @@ describe CouchRest::Model::Validations do
77
75
 
78
76
  it "should allow specific view" do
79
77
  @obj = WithUniqueValidationProxy.new(:title => 'test 7')
80
- @obj.class.should_not_receive('view_by')
78
+ @obj.class.should_not_receive('by_title')
79
+ view = mock('View')
80
+ view.stub!(:rows).and_return([])
81
81
  proxy = mock('Proxy')
82
+ proxy.should_receive('by_title').and_return(view)
83
+ proxy.should_receive('respond_to?').with('by_title').and_return(true)
82
84
  @obj.should_receive('proxy').and_return(proxy)
83
- proxy.should_receive('has_view?').and_return(true)
84
- proxy.should_receive('view').and_return({'rows' => [ ]})
85
85
  @obj.valid?
86
86
  end
87
87
  end
88
88
 
89
89
  context "when proxied" do
90
90
  it "should lookup the model_proxy" do
91
+ view = mock('View')
92
+ view.stub!(:rows).and_return([])
91
93
  mp = mock(:ModelProxy)
92
- mp.should_receive(:view).and_return({'rows' => []})
94
+ mp.should_receive(:by_title).and_return(view)
93
95
  @obj = WithUniqueValidation.new(:title => 'test 8')
94
96
  @obj.stub!(:model_proxy).twice.and_return(mp)
95
97
  @obj.valid?
@@ -103,7 +105,7 @@ describe CouchRest::Model::Validations do
103
105
  end
104
106
 
105
107
  it "should create the view" do
106
- @objs.first.class.has_view?('by_parent_id_and_title')
108
+ @objs.first.class.design_doc.has_view?('by_parent_id_and_title')
107
109
  end
108
110
 
109
111
  it "should validate unique document" do