samlown-couchrest_extended_document 1.0.0

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 (70) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +46 -0
  3. data/Rakefile +67 -0
  4. data/THANKS.md +19 -0
  5. data/examples/model/example.rb +144 -0
  6. data/history.txt +130 -0
  7. data/lib/couchrest/casted_array.rb +25 -0
  8. data/lib/couchrest/casted_model.rb +59 -0
  9. data/lib/couchrest/extended_document.rb +318 -0
  10. data/lib/couchrest/mixins.rb +12 -0
  11. data/lib/couchrest/mixins/attribute_protection.rb +74 -0
  12. data/lib/couchrest/mixins/callbacks.rb +532 -0
  13. data/lib/couchrest/mixins/class_proxy.rb +120 -0
  14. data/lib/couchrest/mixins/collection.rb +260 -0
  15. data/lib/couchrest/mixins/design_doc.rb +121 -0
  16. data/lib/couchrest/mixins/document_queries.rb +80 -0
  17. data/lib/couchrest/mixins/extended_attachments.rb +70 -0
  18. data/lib/couchrest/mixins/properties.rb +154 -0
  19. data/lib/couchrest/mixins/validation.rb +245 -0
  20. data/lib/couchrest/mixins/views.rb +148 -0
  21. data/lib/couchrest/monkeypatches.rb +5 -0
  22. data/lib/couchrest/property.rb +50 -0
  23. data/lib/couchrest/support/couchrest.rb +56 -0
  24. data/lib/couchrest/support/rails.rb +42 -0
  25. data/lib/couchrest/typecast.rb +175 -0
  26. data/lib/couchrest/validation/auto_validate.rb +156 -0
  27. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  28. data/lib/couchrest/validation/validation_errors.rb +125 -0
  29. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  30. data/lib/couchrest/validation/validators/confirmation_validator.rb +107 -0
  31. data/lib/couchrest/validation/validators/format_validator.rb +122 -0
  32. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  33. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  34. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  35. data/lib/couchrest/validation/validators/length_validator.rb +139 -0
  36. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  37. data/lib/couchrest/validation/validators/numeric_validator.rb +109 -0
  38. data/lib/couchrest/validation/validators/required_field_validator.rb +114 -0
  39. data/spec/couchrest/attribute_protection_spec.rb +150 -0
  40. data/spec/couchrest/casted_extended_doc_spec.rb +79 -0
  41. data/spec/couchrest/casted_model_spec.rb +406 -0
  42. data/spec/couchrest/extended_doc_attachment_spec.rb +135 -0
  43. data/spec/couchrest/extended_doc_inherited_spec.rb +40 -0
  44. data/spec/couchrest/extended_doc_spec.rb +824 -0
  45. data/spec/couchrest/extended_doc_subclass_spec.rb +99 -0
  46. data/spec/couchrest/extended_doc_view_spec.rb +473 -0
  47. data/spec/couchrest/property_spec.rb +628 -0
  48. data/spec/fixtures/attachments/README +3 -0
  49. data/spec/fixtures/attachments/couchdb.png +0 -0
  50. data/spec/fixtures/attachments/test.html +11 -0
  51. data/spec/fixtures/more/article.rb +35 -0
  52. data/spec/fixtures/more/card.rb +22 -0
  53. data/spec/fixtures/more/cat.rb +22 -0
  54. data/spec/fixtures/more/course.rb +22 -0
  55. data/spec/fixtures/more/event.rb +8 -0
  56. data/spec/fixtures/more/invoice.rb +17 -0
  57. data/spec/fixtures/more/person.rb +9 -0
  58. data/spec/fixtures/more/question.rb +6 -0
  59. data/spec/fixtures/more/service.rb +12 -0
  60. data/spec/fixtures/more/user.rb +22 -0
  61. data/spec/fixtures/views/lib.js +3 -0
  62. data/spec/fixtures/views/test_view/lib.js +3 -0
  63. data/spec/fixtures/views/test_view/only-map.js +4 -0
  64. data/spec/fixtures/views/test_view/test-map.js +3 -0
  65. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  66. data/spec/spec.opts +5 -0
  67. data/spec/spec_helper.rb +49 -0
  68. data/utils/remap.rb +27 -0
  69. data/utils/subset.rb +30 -0
  70. metadata +181 -0
@@ -0,0 +1,99 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+ require File.join(FIXTURE_PATH, 'more', 'person')
3
+ require File.join(FIXTURE_PATH, 'more', 'card')
4
+ require File.join(FIXTURE_PATH, 'more', 'course')
5
+
6
+ # add a default value
7
+ Card.property :bg_color, :default => '#ccc'
8
+
9
+ class BusinessCard < Card
10
+ property :extension_code
11
+ property :job_title
12
+ end
13
+
14
+ class DesignBusinessCard < BusinessCard
15
+ property :bg_color, :default => '#eee'
16
+ end
17
+
18
+ class OnlineCourse < Course
19
+ property :url
20
+ view_by :url
21
+ end
22
+
23
+ class Animal < CouchRest::ExtendedDocument
24
+ use_database TEST_SERVER.default_database
25
+ property :name
26
+ view_by :name
27
+ end
28
+
29
+ class Dog < Animal; end
30
+
31
+ describe "Subclassing an ExtendedDocument" do
32
+
33
+ before(:each) do
34
+ @card = BusinessCard.new
35
+ end
36
+
37
+ it "shouldn't messup the parent's properties" do
38
+ Card.properties.should_not == BusinessCard.properties
39
+ end
40
+
41
+ it "should share the same db default" do
42
+ @card.database.uri.should == Card.database.uri
43
+ end
44
+
45
+ it "should share the same autovalidation details" do
46
+ @card.auto_validation.should be_true
47
+ end
48
+
49
+ it "should have kept the validation details" do
50
+ @card.should_not be_valid
51
+ end
52
+
53
+ it "should have added the new validation details" do
54
+ validated_fields = @card.class.validators.contexts[:default].map{|v| v.field_name}
55
+ validated_fields.should include(:extension_code)
56
+ validated_fields.should include(:job_title)
57
+ end
58
+
59
+ it "should not add to the parent's validations" do
60
+ validated_fields = Card.validators.contexts[:default].map{|v| v.field_name}
61
+ validated_fields.should_not include(:extension_code)
62
+ validated_fields.should_not include(:job_title)
63
+ end
64
+
65
+ it "should inherit default property values" do
66
+ @card.bg_color.should == '#ccc'
67
+ end
68
+
69
+ it "should be able to overwrite a default property" do
70
+ DesignBusinessCard.new.bg_color.should == '#eee'
71
+ end
72
+
73
+ it "should have a design doc slug based on the subclass name" do
74
+ Course.refresh_design_doc
75
+ OnlineCourse.design_doc_slug.should =~ /^OnlineCourse/
76
+ end
77
+
78
+ it "should have its own design_doc_fresh" do
79
+ Animal.refresh_design_doc
80
+ Dog.send(:design_doc_fresh, Dog.database).should_not == true
81
+ Dog.refresh_design_doc
82
+ Dog.send(:design_doc_fresh, Dog.database).should == true
83
+ end
84
+
85
+ it "should not add views to the parent's design_doc" do
86
+ Course.design_doc['views'].keys.should_not include('by_url')
87
+ end
88
+
89
+ it "should not add the parent's views to its design doc" do
90
+ Course.refresh_design_doc
91
+ OnlineCourse.refresh_design_doc
92
+ OnlineCourse.design_doc['views'].keys.should_not include('by_title')
93
+ end
94
+
95
+ it "should have an all view with a guard clause for couchrest-type == subclass name in the map function" do
96
+ OnlineCourse.design_doc['views']['all']['map'].should =~ /if \(doc\['couchrest-type'\] == 'OnlineCourse'\)/
97
+ end
98
+ end
99
+
@@ -0,0 +1,473 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+ require File.join(FIXTURE_PATH, 'more', 'article')
3
+ require File.join(FIXTURE_PATH, 'more', 'course')
4
+
5
+ describe "ExtendedDocument views" do
6
+
7
+ class Unattached < CouchRest::ExtendedDocument
8
+ # Note: no use_database here
9
+ property :title
10
+ property :questions
11
+ property :professor
12
+ view_by :title
13
+ end
14
+
15
+ describe "a model with simple views and a default param" do
16
+ before(:all) do
17
+ Article.all.map{|a| a.destroy(true)}
18
+ Article.database.bulk_delete
19
+ written_at = Time.now - 24 * 3600 * 7
20
+ @titles = ["this and that", "also interesting", "more fun", "some junk"]
21
+ @titles.each do |title|
22
+ a = Article.new(:title => title)
23
+ a.date = written_at
24
+ a.save
25
+ written_at += 24 * 3600
26
+ end
27
+ end
28
+ it "should have a design doc" do
29
+ Article.design_doc["views"]["by_date"].should_not be_nil
30
+ end
31
+ it "should save the design doc" do
32
+ Article.by_date #rescue nil
33
+ doc = Article.database.get Article.design_doc.id
34
+ doc['views']['by_date'].should_not be_nil
35
+ end
36
+ it "should return the matching raw view result" do
37
+ view = Article.by_date :raw => true
38
+ view['rows'].length.should == 4
39
+ end
40
+ it "should not include non-Articles" do
41
+ Article.database.save_doc({"date" => 1})
42
+ view = Article.by_date :raw => true
43
+ view['rows'].length.should == 4
44
+ end
45
+ it "should return the matching objects (with default argument :descending => true)" do
46
+ articles = Article.by_date
47
+ articles.collect{|a|a.title}.should == @titles.reverse
48
+ end
49
+ it "should allow you to override default args" do
50
+ articles = Article.by_date :descending => false
51
+ articles.collect{|a|a.title}.should == @titles
52
+ end
53
+ it "should allow you to create a new view on the fly" do
54
+ lambda{Article.by_title}.should raise_error
55
+ Article.view_by :title
56
+ lambda{Article.by_title}.should_not raise_error
57
+ end
58
+
59
+ end
60
+
61
+ describe "another model with a simple view" do
62
+ before(:all) do
63
+ reset_test_db!
64
+ %w{aaa bbb ddd eee}.each do |title|
65
+ Course.new(:title => title).save
66
+ end
67
+ end
68
+ it "should make the design doc upon first query" do
69
+ Course.by_title
70
+ doc = Course.design_doc
71
+ doc['views']['all']['map'].should include('Course')
72
+ end
73
+ it "should can query via view" do
74
+ # register methods with method-missing, for local dispatch. method
75
+ # missing lookup table, no heuristics.
76
+ view = Course.view :by_title
77
+ designed = Course.by_title
78
+ view.should == designed
79
+ end
80
+ it "should get them" do
81
+ rs = Course.by_title
82
+ rs.length.should == 4
83
+ end
84
+ it "should yield" do
85
+ courses = []
86
+ Course.view(:by_title) do |course|
87
+ courses << course
88
+ end
89
+ courses[0]["doc"]["title"].should =='aaa'
90
+ end
91
+ it "should yield with by_key method" do
92
+ courses = []
93
+ Course.by_title do |course|
94
+ courses << course
95
+ end
96
+ courses[0]["doc"]["title"].should =='aaa'
97
+ end
98
+ end
99
+
100
+ describe "a ducktype view" do
101
+ before(:all) do
102
+ reset_test_db!
103
+ @id = DB.save_doc({:dept => true})['id']
104
+ end
105
+ it "should setup" do
106
+ duck = Course.get(@id) # from a different db
107
+ duck["dept"].should == true
108
+ end
109
+ it "should make the design doc" do
110
+ @as = Course.by_dept
111
+ @doc = Course.design_doc
112
+ @doc["views"]["by_dept"]["map"].should_not include("couchrest")
113
+ end
114
+ it "should not look for class" do
115
+ @as = Course.by_dept
116
+ @as[0]['_id'].should == @id
117
+ end
118
+ end
119
+
120
+ describe "a model class not tied to a database" do
121
+ before(:all) do
122
+ reset_test_db!
123
+ @db = DB
124
+ %w{aaa bbb ddd eee}.each do |title|
125
+ u = Unattached.new(:title => title)
126
+ u.database = @db
127
+ u.save
128
+ @first_id ||= u.id
129
+ end
130
+ end
131
+ it "should barf on all if no database given" do
132
+ lambda{Unattached.all}.should raise_error
133
+ end
134
+ it "should query all" do
135
+ # Unattached.cleanup_design_docs!(@db)
136
+ rs = Unattached.all :database => @db
137
+ rs.length.should == 4
138
+ end
139
+ it "should barf on query if no database given" do
140
+ lambda{Unattached.view :by_title}.should raise_error
141
+ end
142
+ it "should make the design doc upon first query" do
143
+ Unattached.by_title :database => @db
144
+ doc = Unattached.design_doc
145
+ doc['views']['all']['map'].should include('Unattached')
146
+ end
147
+ it "should merge query params" do
148
+ rs = Unattached.by_title :database=>@db, :startkey=>"bbb", :endkey=>"eee"
149
+ rs.length.should == 3
150
+ end
151
+ it "should query via view" do
152
+ view = Unattached.view :by_title, :database=>@db
153
+ designed = Unattached.by_title :database=>@db
154
+ view.should == designed
155
+ end
156
+ it "should yield" do
157
+ things = []
158
+ Unattached.view(:by_title, :database=>@db) do |thing|
159
+ things << thing
160
+ end
161
+ things[0]["doc"]["title"].should =='aaa'
162
+ end
163
+ it "should yield with by_key method" do
164
+ things = []
165
+ Unattached.by_title(:database=>@db) do |thing|
166
+ things << thing
167
+ end
168
+ things[0]["doc"]["title"].should =='aaa'
169
+ end
170
+ it "should return nil on get if no database given" do
171
+ Unattached.get("aaa").should be_nil
172
+ end
173
+ it "should barf on get! if no database given" do
174
+ lambda{Unattached.get!("aaa")}.should raise_error
175
+ end
176
+ it "should get from specific database" do
177
+ u = Unattached.get(@first_id, @db)
178
+ u.title.should == "aaa"
179
+ end
180
+ it "should barf on first if no database given" do
181
+ lambda{Unattached.first}.should raise_error
182
+ end
183
+ it "should get first" do
184
+ u = Unattached.first :database=>@db
185
+ u.title.should =~ /\A...\z/
186
+ end
187
+ it "should barf on all_design_doc_versions if no database given" do
188
+ lambda{Unattached.all_design_doc_versions}.should raise_error
189
+ end
190
+ it "should be able to cleanup the db/bump the revision number" do
191
+ # if the previous specs were not run, the model_design_doc will be blank
192
+ Unattached.use_database DB
193
+ Unattached.view_by :questions
194
+ Unattached.by_questions(:database => @db)
195
+ original_revision = Unattached.model_design_doc(@db)['_rev']
196
+ Unattached.save_design_doc!(@db)
197
+ Unattached.model_design_doc(@db)['_rev'].should_not == original_revision
198
+ end
199
+ end
200
+
201
+ describe "class proxy" do
202
+ before(:all) do
203
+ reset_test_db!
204
+ # setup the class default doc to save the design doc
205
+ Unattached.use_database nil # just to be sure it is really unattached
206
+ @us = Unattached.on(DB)
207
+ %w{aaa bbb ddd eee}.each do |title|
208
+ u = @us.new(:title => title)
209
+ u.save
210
+ @first_id ||= u.id
211
+ end
212
+ end
213
+ it "should query all" do
214
+ rs = @us.all
215
+ rs.length.should == 4
216
+ end
217
+ it "should count" do
218
+ @us.count.should == 4
219
+ end
220
+ it "should make the design doc upon first query" do
221
+ @us.by_title
222
+ doc = @us.design_doc
223
+ doc['views']['all']['map'].should include('Unattached')
224
+ end
225
+ it "should merge query params" do
226
+ rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
227
+ rs.length.should == 3
228
+ end
229
+ it "should query via view" do
230
+ view = @us.view :by_title
231
+ designed = @us.by_title
232
+ view.should == designed
233
+ end
234
+ it "should yield" do
235
+ things = []
236
+ @us.view(:by_title) do |thing|
237
+ things << thing
238
+ end
239
+ things[0]["doc"]["title"].should =='aaa'
240
+ end
241
+ it "should yield with by_key method" do
242
+ things = []
243
+ @us.by_title do |thing|
244
+ things << thing
245
+ end
246
+ things[0]["doc"]["title"].should =='aaa'
247
+ end
248
+ it "should get from specific database" do
249
+ u = @us.get(@first_id)
250
+ u.title.should == "aaa"
251
+ end
252
+ it "should get first" do
253
+ u = @us.first
254
+ u.title.should =~ /\A...\z/
255
+ end
256
+ it "should set database on first retreived document" do
257
+ u = @us.first
258
+ u.database.should === DB
259
+ end
260
+ it "should set database on all retreived documents" do
261
+ @us.all.each do |u|
262
+ u.database.should === DB
263
+ end
264
+ end
265
+ it "should set database on each retreived document" do
266
+ rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
267
+ rs.length.should == 3
268
+ rs.each do |u|
269
+ u.database.should === DB
270
+ end
271
+ end
272
+ it "should set database on document retreived by id" do
273
+ u = @us.get(@first_id)
274
+ u.database.should === DB
275
+ end
276
+ it "should not attempt to set database on raw results using :all" do
277
+ @us.all(:raw => true).each do |u|
278
+ u.respond_to?(:database).should be_false
279
+ end
280
+ end
281
+ it "should not attempt to set database on raw results using view" do
282
+ @us.by_title(:raw => true).each do |u|
283
+ u.respond_to?(:database).should be_false
284
+ end
285
+ end
286
+ # Sam Lown 2010-04-07
287
+ # Removed as unclear why this should happen as before my changes
288
+ # this happend by accident, not explicitly.
289
+ # If requested, this feature should be added as a specific method.
290
+ #
291
+ #it "should clean up design docs left around on specific database" do
292
+ # @us.by_title
293
+ # original_id = @us.model_design_doc['_rev']
294
+ # Unattached.view_by :professor
295
+ # @us.by_professor
296
+ # @us.model_design_doc['_rev'].should_not == original_id
297
+ #end
298
+ end
299
+
300
+ describe "a model with a compound key view" do
301
+ before(:all) do
302
+ Article.by_user_id_and_date.each{|a| a.destroy(true)}
303
+ Article.database.bulk_delete
304
+ written_at = Time.now - 24 * 3600 * 7
305
+ @titles = ["uniq one", "even more interesting", "less fun", "not junk"]
306
+ @user_ids = ["quentin", "aaron"]
307
+ @titles.each_with_index do |title,i|
308
+ u = i % 2
309
+ a = Article.new(:title => title, :user_id => @user_ids[u])
310
+ a.date = written_at
311
+ a.save
312
+ written_at += 24 * 3600
313
+ end
314
+ end
315
+ it "should create the design doc" do
316
+ Article.by_user_id_and_date rescue nil
317
+ doc = Article.design_doc
318
+ doc['views']['by_date'].should_not be_nil
319
+ end
320
+ it "should sort correctly" do
321
+ articles = Article.by_user_id_and_date
322
+ articles.collect{|a|a['user_id']}.should == ['aaron', 'aaron', 'quentin',
323
+ 'quentin']
324
+ articles[1].title.should == 'not junk'
325
+ end
326
+ it "should be queryable with couchrest options" do
327
+ articles = Article.by_user_id_and_date :limit => 1, :startkey => 'quentin'
328
+ articles.length.should == 1
329
+ articles[0].title.should == "even more interesting"
330
+ end
331
+ end
332
+
333
+ describe "with a custom view" do
334
+ before(:all) do
335
+ @titles = ["very uniq one", "even less interesting", "some fun",
336
+ "really junk", "crazy bob"]
337
+ @tags = ["cool", "lame"]
338
+ @titles.each_with_index do |title,i|
339
+ u = i % 2
340
+ a = Article.new(:title => title, :tags => [@tags[u]])
341
+ a.save
342
+ end
343
+ end
344
+ it "should be available raw" do
345
+ view = Article.by_tags :raw => true
346
+ view['rows'].length.should == 5
347
+ end
348
+
349
+ it "should be default to :reduce => false" do
350
+ ars = Article.by_tags
351
+ ars.first.tags.first.should == 'cool'
352
+ end
353
+
354
+ it "should be raw when reduce is true" do
355
+ view = Article.by_tags :reduce => true, :group => true
356
+ view['rows'].find{|r|r['key'] == 'cool'}['value'].should == 3
357
+ end
358
+ end
359
+
360
+ # TODO: moved to Design, delete
361
+ describe "adding a view" do
362
+ before(:each) do
363
+ reset_test_db!
364
+ Article.by_date
365
+ @original_doc_rev = Article.model_design_doc['_rev']
366
+ @design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
367
+ end
368
+ it "should not create a design doc on view definition" do
369
+ Article.view_by :created_at
370
+ newdocs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
371
+ newdocs["rows"].length.should == @design_docs["rows"].length
372
+ end
373
+ it "should create a new version of the design document on view access" do
374
+ ddocs = Article.all_design_doc_versions["rows"].length
375
+ Article.view_by :updated_at
376
+ Article.by_updated_at
377
+ @original_doc_rev.should_not == Article.model_design_doc['_rev']
378
+ Article.design_doc["views"].keys.should include("by_updated_at")
379
+ end
380
+ end
381
+
382
+ describe "with a collection" do
383
+ before(:all) do
384
+ reset_test_db!
385
+ titles = ["very uniq one", "really interesting", "some fun",
386
+ "really awesome", "crazy bob", "this rocks", "super rad"]
387
+ titles.each_with_index do |title,i|
388
+ a = Article.new(:title => title, :date => Date.today)
389
+ a.save
390
+ end
391
+
392
+ titles = ["yesterday very uniq one", "yesterday really interesting", "yesterday some fun",
393
+ "yesterday really awesome", "yesterday crazy bob", "yesterday this rocks"]
394
+ titles.each_with_index do |title,i|
395
+ a = Article.new(:title => title, :date => Date.today - 1)
396
+ a.save
397
+ end
398
+ end
399
+ require 'date'
400
+ it "should return a proxy that looks like an array of 7 Article objects" do
401
+ articles = Article.by_date :key => Date.today
402
+ articles.class.should == Array
403
+ articles.size.should == 7
404
+ end
405
+ it "should get a subset of articles using paginate" do
406
+ articles = Article.by_date :key => Date.today
407
+ articles.paginate(:page => 1, :per_page => 3).size.should == 3
408
+ articles.paginate(:page => 2, :per_page => 3).size.should == 3
409
+ articles.paginate(:page => 3, :per_page => 3).size.should == 1
410
+ end
411
+ it "should get all articles, a few at a time, using paginated each" do
412
+ articles = Article.by_date :key => Date.today
413
+ articles.paginated_each(:per_page => 3) do |a|
414
+ a.should_not be_nil
415
+ end
416
+ end
417
+ it "should provide a class method to access the collection directly" do
418
+ articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
419
+ :key => Date.today, :include_docs => true)
420
+ articles.class.should == Array
421
+ articles.size.should == 7
422
+ end
423
+ it "should provide a class method for paginate" do
424
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
425
+ :per_page => 3, :descending => true, :key => Date.today, :include_docs => true)
426
+ articles.size.should == 3
427
+
428
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
429
+ :per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
430
+ articles.size.should == 3
431
+
432
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
433
+ :per_page => 3, :page => 3, :descending => true, :key => Date.today, :include_docs => true)
434
+ articles.size.should == 1
435
+ end
436
+ it "should provide a class method for paginated_each" do
437
+ options = { :design_doc => 'Article', :view_name => 'by_date',
438
+ :per_page => 3, :page => 1, :descending => true, :key => Date.today,
439
+ :include_docs => true }
440
+ Article.paginated_each(options) do |a|
441
+ a.should_not be_nil
442
+ end
443
+ end
444
+ it "should provide a class method to get a collection for a view" do
445
+ articles = Article.find_all_article_details(:key => Date.today)
446
+ articles.class.should == Array
447
+ articles.size.should == 7
448
+ end
449
+ it "should raise an exception if design_doc is not provided" do
450
+ lambda{Article.collection_proxy_for(nil, 'by_date')}.should raise_error
451
+ lambda{Article.paginate(:view_name => 'by_date')}.should raise_error
452
+ end
453
+ it "should raise an exception if view_name is not provided" do
454
+ lambda{Article.collection_proxy_for('Article', nil)}.should raise_error
455
+ lambda{Article.paginate(:design_doc => 'Article')}.should raise_error
456
+ end
457
+ it "should be able to span multiple keys" do
458
+ articles = Article.by_date :startkey => Date.today, :endkey => Date.today - 1
459
+ articles.paginate(:page => 1, :per_page => 3).size.should == 3
460
+ articles.paginate(:page => 2, :per_page => 3).size.should == 3
461
+ articles.paginate(:page => 3, :per_page => 3).size.should == 3
462
+ articles.paginate(:page => 4, :per_page => 3).size.should == 3
463
+ articles.paginate(:page => 5, :per_page => 3).size.should == 1
464
+ end
465
+ it "should pass database parameter to pager" do
466
+ proxy = mock(:proxy)
467
+ proxy.stub!(:paginate)
468
+ ::CouchRest::Mixins::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
469
+ Article.paginate(:design_doc => 'Article', :view_name => 'by_date', :database => 'database')
470
+ end
471
+ end
472
+
473
+ end