couchrest_model_thought 1.0.0.beta8

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/Gemfile +9 -0
  2. data/LICENSE +176 -0
  3. data/README.md +320 -0
  4. data/Rakefile +69 -0
  5. data/THANKS.md +19 -0
  6. data/examples/model/example.rb +144 -0
  7. data/lib/couchrest/model/associations.rb +207 -0
  8. data/lib/couchrest/model/attribute_protection.rb +74 -0
  9. data/lib/couchrest/model/attributes.rb +91 -0
  10. data/lib/couchrest/model/base.rb +111 -0
  11. data/lib/couchrest/model/callbacks.rb +27 -0
  12. data/lib/couchrest/model/casted_array.rb +39 -0
  13. data/lib/couchrest/model/casted_model.rb +68 -0
  14. data/lib/couchrest/model/class_proxy.rb +122 -0
  15. data/lib/couchrest/model/collection.rb +260 -0
  16. data/lib/couchrest/model/design_doc.rb +126 -0
  17. data/lib/couchrest/model/document_queries.rb +82 -0
  18. data/lib/couchrest/model/errors.rb +23 -0
  19. data/lib/couchrest/model/extended_attachments.rb +73 -0
  20. data/lib/couchrest/model/persistence.rb +141 -0
  21. data/lib/couchrest/model/properties.rb +144 -0
  22. data/lib/couchrest/model/property.rb +96 -0
  23. data/lib/couchrest/model/support/couchrest.rb +19 -0
  24. data/lib/couchrest/model/support/hash.rb +9 -0
  25. data/lib/couchrest/model/typecast.rb +170 -0
  26. data/lib/couchrest/model/validations/casted_model.rb +14 -0
  27. data/lib/couchrest/model/validations/locale/en.yml +5 -0
  28. data/lib/couchrest/model/validations/uniqueness.rb +42 -0
  29. data/lib/couchrest/model/validations.rb +68 -0
  30. data/lib/couchrest/model/version.rb +5 -0
  31. data/lib/couchrest/model/views.rb +160 -0
  32. data/lib/couchrest/model.rb +5 -0
  33. data/lib/couchrest_model.rb +53 -0
  34. data/spec/couchrest/assocations_spec.rb +213 -0
  35. data/spec/couchrest/attachment_spec.rb +148 -0
  36. data/spec/couchrest/attribute_protection_spec.rb +153 -0
  37. data/spec/couchrest/base_spec.rb +463 -0
  38. data/spec/couchrest/casted_model_spec.rb +424 -0
  39. data/spec/couchrest/casted_spec.rb +75 -0
  40. data/spec/couchrest/class_proxy_spec.rb +132 -0
  41. data/spec/couchrest/inherited_spec.rb +40 -0
  42. data/spec/couchrest/persistence_spec.rb +409 -0
  43. data/spec/couchrest/property_spec.rb +804 -0
  44. data/spec/couchrest/subclass_spec.rb +99 -0
  45. data/spec/couchrest/validations.rb +85 -0
  46. data/spec/couchrest/view_spec.rb +463 -0
  47. data/spec/fixtures/attachments/README +3 -0
  48. data/spec/fixtures/attachments/couchdb.png +0 -0
  49. data/spec/fixtures/attachments/test.html +11 -0
  50. data/spec/fixtures/base.rb +139 -0
  51. data/spec/fixtures/more/article.rb +35 -0
  52. data/spec/fixtures/more/card.rb +17 -0
  53. data/spec/fixtures/more/cat.rb +19 -0
  54. data/spec/fixtures/more/course.rb +25 -0
  55. data/spec/fixtures/more/event.rb +8 -0
  56. data/spec/fixtures/more/invoice.rb +14 -0
  57. data/spec/fixtures/more/person.rb +9 -0
  58. data/spec/fixtures/more/question.rb +7 -0
  59. data/spec/fixtures/more/service.rb +10 -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 +48 -0
  68. data/utils/remap.rb +27 -0
  69. data/utils/subset.rb +30 -0
  70. metadata +215 -0
@@ -0,0 +1,99 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+ require File.join(FIXTURE_PATH, 'more', 'cat')
3
+ require File.join(FIXTURE_PATH, 'more', 'person')
4
+ require File.join(FIXTURE_PATH, 'more', 'card')
5
+ require File.join(FIXTURE_PATH, 'more', 'course')
6
+
7
+ # add a default value
8
+ Card.property :bg_color, :default => '#ccc'
9
+
10
+ class BusinessCard < Card
11
+ property :extension_code
12
+ property :job_title
13
+
14
+ validates_presence_of :extension_code
15
+ validates_presence_of :job_title
16
+ end
17
+
18
+ class DesignBusinessCard < BusinessCard
19
+ property :bg_color, :default => '#eee'
20
+ end
21
+
22
+ class OnlineCourse < Course
23
+ property :url
24
+ view_by :url
25
+ end
26
+
27
+ class Animal < CouchRest::Model::Base
28
+ use_database TEST_SERVER.default_database
29
+ property :name
30
+ view_by :name
31
+ end
32
+
33
+ class Dog < Animal; end
34
+
35
+ describe "Subclassing a Model" do
36
+
37
+ before(:each) do
38
+ @card = BusinessCard.new
39
+ end
40
+
41
+ it "shouldn't messup the parent's properties" do
42
+ Card.properties.should_not == BusinessCard.properties
43
+ end
44
+
45
+ it "should share the same db default" do
46
+ @card.database.uri.should == Card.database.uri
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.map{|v| v.attributes}.flatten
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.map{|v| v.attributes}.flatten
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,85 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ require File.join(FIXTURE_PATH, 'more', 'cat')
4
+ require File.join(FIXTURE_PATH, 'more', 'article')
5
+ require File.join(FIXTURE_PATH, 'more', 'course')
6
+ require File.join(FIXTURE_PATH, 'more', 'card')
7
+ require File.join(FIXTURE_PATH, 'base')
8
+
9
+ # TODO Move validations from other specs to here
10
+
11
+ describe "Validations" do
12
+
13
+ describe "Uniqueness" do
14
+
15
+ before(:all) do
16
+ @objs = ['title 1', 'title 2', 'title 3'].map{|t| WithUniqueValidation.create(:title => t)}
17
+ end
18
+
19
+ it "should validate a new unique document" do
20
+ @obj = WithUniqueValidation.create(:title => 'title 4')
21
+ @obj.new?.should_not be_true
22
+ @obj.should be_valid
23
+ end
24
+
25
+ it "should not validate a non-unique document" do
26
+ @obj = WithUniqueValidation.create(:title => 'title 1')
27
+ @obj.should_not be_valid
28
+ @obj.errors[:title].should eql(['is already taken'])
29
+ end
30
+
31
+ it "should save already created document" do
32
+ @obj = @objs.first
33
+ @obj.save.should_not be_false
34
+ @obj.should be_valid
35
+ end
36
+
37
+ it "should allow own view to be specified" do
38
+ # validates_uniqueness_of :code, :view => 'all'
39
+ WithUniqueValidationView.create(:title => 'title 1', :code => '1234')
40
+ @obj = WithUniqueValidationView.new(:title => 'title 5', :code => '1234')
41
+ @obj.should_not be_valid
42
+ end
43
+
44
+ it "should raise an error if specified view does not exist" do
45
+ WithUniqueValidationView.validates_uniqueness_of :title, :view => 'fooobar'
46
+ @obj = WithUniqueValidationView.new(:title => 'title 2', :code => '12345')
47
+ lambda {
48
+ @obj.valid?
49
+ }.should raise_error
50
+ end
51
+
52
+ context "with a pre-defined view" do
53
+ it "should not try to create new view" do
54
+ @obj = @objs[1]
55
+ @obj.class.should_not_receive('view_by')
56
+ @obj.class.should_receive('has_view?').and_return(true)
57
+ @obj.class.should_receive('view').and_return({'rows' => [ ]})
58
+ @obj.valid?
59
+ end
60
+
61
+ end
62
+
63
+ context "with a proxy parameter" do
64
+ it "should be used" do
65
+ @obj = WithUniqueValidationProxy.new(:title => 'test 6')
66
+ proxy = @obj.should_receive('proxy').and_return(@obj.class)
67
+ @obj.valid?.should be_true
68
+ end
69
+
70
+ it "should allow specific view" do
71
+ @obj = WithUniqueValidationProxy.new(:title => 'test 7')
72
+ @obj.class.should_not_receive('view_by')
73
+ proxy = mock('Proxy')
74
+ @obj.should_receive('proxy').and_return(proxy)
75
+ proxy.should_receive('has_view?').and_return(true)
76
+ proxy.should_receive('view').and_return({'rows' => [ ]})
77
+ @obj.valid?
78
+ end
79
+
80
+ end
81
+
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,463 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+ require File.join(FIXTURE_PATH, 'more', 'cat')
3
+ require File.join(FIXTURE_PATH, 'more', 'person')
4
+ require File.join(FIXTURE_PATH, 'more', 'article')
5
+ require File.join(FIXTURE_PATH, 'more', 'course')
6
+
7
+ describe "Model views" do
8
+
9
+ class Unattached < CouchRest::Model::Base
10
+ # Note: no use_database here
11
+ property :title
12
+ property :questions
13
+ property :professor
14
+ view_by :title
15
+ end
16
+
17
+
18
+ describe "ClassMethods" do
19
+ # NOTE! Add more unit tests!
20
+
21
+ describe "#view" do
22
+
23
+ it "should not alter original query" do
24
+ options = { :database => DB }
25
+ view = Article.view('by_date', options)
26
+ options[:database].should_not be_nil
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ describe "a model with simple views and a default param" do
33
+ before(:all) do
34
+ Article.all.map{|a| a.destroy(true)}
35
+ Article.database.bulk_delete
36
+ written_at = Time.now - 24 * 3600 * 7
37
+ @titles = ["this and that", "also interesting", "more fun", "some junk"]
38
+ @titles.each do |title|
39
+ a = Article.new(:title => title)
40
+ a.date = written_at
41
+ a.save
42
+ written_at += 24 * 3600
43
+ end
44
+ end
45
+ it "should have a design doc" do
46
+ Article.design_doc["views"]["by_date"].should_not be_nil
47
+ end
48
+ it "should save the design doc" do
49
+ Article.by_date #rescue nil
50
+ doc = Article.database.get Article.design_doc.id
51
+ doc['views']['by_date'].should_not be_nil
52
+ end
53
+ it "should save design doc if a view changed" do
54
+ Article.by_date
55
+ orig = Article.stored_design_doc
56
+ orig['views']['by_date']['map'] = "function() { }"
57
+ Article.database.save_doc(orig)
58
+ rev = Article.stored_design_doc['_rev']
59
+ Article.req_design_doc_refresh # prepare for re-load
60
+ Article.by_date
61
+ orig = Article.stored_design_doc
62
+ orig['views']['by_date']['map'].should eql(Article.design_doc['views']['by_date']['map'])
63
+ orig['_rev'].should_not eql(rev)
64
+ end
65
+ it "should not save design doc if not changed" do
66
+ Article.by_date
67
+ orig = Article.stored_design_doc['_rev']
68
+ Article.req_design_doc_refresh
69
+ Article.by_date
70
+ Article.stored_design_doc['_rev'].should eql(orig)
71
+ end
72
+
73
+
74
+ it "should return the matching raw view result" do
75
+ view = Article.by_date :raw => true
76
+ view['rows'].length.should == 4
77
+ end
78
+ it "should not include non-Articles" do
79
+ Article.database.save_doc({"date" => 1})
80
+ view = Article.by_date :raw => true
81
+ view['rows'].length.should == 4
82
+ end
83
+ it "should return the matching objects (with default argument :descending => true)" do
84
+ articles = Article.by_date
85
+ articles.collect{|a|a.title}.should == @titles.reverse
86
+ end
87
+ it "should allow you to override default args" do
88
+ articles = Article.by_date :descending => false
89
+ articles.collect{|a|a.title}.should == @titles
90
+ end
91
+ it "should allow you to create a new view on the fly" do
92
+ lambda{Article.by_title}.should raise_error
93
+ Article.view_by :title
94
+ lambda{Article.by_title}.should_not raise_error
95
+ end
96
+
97
+ end
98
+
99
+ describe "another model with a simple view" do
100
+ before(:all) do
101
+ reset_test_db!
102
+ %w{aaa bbb ddd eee}.each do |title|
103
+ Course.new(:title => title).save
104
+ end
105
+ end
106
+ it "should make the design doc upon first query" do
107
+ Course.by_title
108
+ doc = Course.design_doc
109
+ doc['views']['all']['map'].should include('Course')
110
+ end
111
+ it "should can query via view" do
112
+ # register methods with method-missing, for local dispatch. method
113
+ # missing lookup table, no heuristics.
114
+ view = Course.view :by_title
115
+ designed = Course.by_title
116
+ view.should == designed
117
+ end
118
+ it "should get them" do
119
+ rs = Course.by_title
120
+ rs.length.should == 4
121
+ end
122
+ it "should yield" do
123
+ courses = []
124
+ Course.view(:by_title) do |course|
125
+ courses << course
126
+ end
127
+ courses[0]["doc"]["title"].should =='aaa'
128
+ end
129
+ it "should yield with by_key method" do
130
+ courses = []
131
+ Course.by_title do |course|
132
+ courses << course
133
+ end
134
+ courses[0]["doc"]["title"].should =='aaa'
135
+ end
136
+ end
137
+
138
+ describe "find a single item using a view" do
139
+ before(:all) do
140
+ reset_test_db!
141
+ %w{aaa bbb ddd eee}.each do |title|
142
+ Course.new(:title => title, :active => (title == 'bbb')).save
143
+ end
144
+ end
145
+
146
+ it "should return single matched record with find helper" do
147
+ course = Course.find_by_title('bbb')
148
+ course.should_not be_nil
149
+ course.title.should eql('bbb') # Ensure really is a Course!
150
+ end
151
+
152
+ it "should return nil if not found" do
153
+ course = Course.find_by_title('fff')
154
+ course.should be_nil
155
+ end
156
+
157
+ it "should peform search on view with two properties" do
158
+ course = Course.find_by_title_and_active(['bbb', true])
159
+ course.should_not be_nil
160
+ course.title.should eql('bbb') # Ensure really is a Course!
161
+ end
162
+
163
+ it "should return nil if not found" do
164
+ course = Course.find_by_title_and_active(['bbb', false])
165
+ course.should be_nil
166
+ end
167
+
168
+ it "should raise exception if view not present" do
169
+ lambda { Course.find_by_foobar('123') }.should raise_error(NoMethodError)
170
+ end
171
+
172
+ it "should perform a search directly with specific key" do
173
+ course = Course.first_from_view('by_title', 'bbb')
174
+ course.title.should eql('bbb')
175
+ end
176
+
177
+ it "should perform a search directly with specific key with options" do
178
+ course = Course.first_from_view('by_title', 'bbb', :reverse => true)
179
+ course.title.should eql('bbb')
180
+ end
181
+
182
+ it "should perform a search directly with range" do
183
+ course = Course.first_from_view('by_title', :startkey => 'bbb', :endkey => 'eee')
184
+ course.title.should eql('bbb')
185
+ end
186
+
187
+ end
188
+
189
+ describe "a ducktype view" do
190
+ before(:all) do
191
+ reset_test_db!
192
+ @id = DB.save_doc({:dept => true})['id']
193
+ end
194
+ it "should setup" do
195
+ duck = Course.get(@id) # from a different db
196
+ duck["dept"].should == true
197
+ end
198
+ it "should make the design doc" do
199
+ @as = Course.by_dept
200
+ @doc = Course.design_doc
201
+ @doc["views"]["by_dept"]["map"].should_not include("couchrest")
202
+ end
203
+ it "should not look for class" do
204
+ @as = Course.by_dept
205
+ @as[0]['_id'].should == @id
206
+ end
207
+ end
208
+
209
+ describe "a model class not tied to a database" do
210
+ before(:all) do
211
+ reset_test_db!
212
+ @db = DB
213
+ %w{aaa bbb ddd eee}.each do |title|
214
+ u = Unattached.new(:title => title)
215
+ u.database = @db
216
+ u.save
217
+ @first_id ||= u.id
218
+ end
219
+ end
220
+ it "should barf on all if no database given" do
221
+ lambda{Unattached.all}.should raise_error
222
+ end
223
+ it "should query all" do
224
+ # Unattached.cleanup_design_docs!(@db)
225
+ rs = Unattached.all :database => @db
226
+ rs.length.should == 4
227
+ end
228
+ it "should barf on query if no database given" do
229
+ lambda{Unattached.view :by_title}.should raise_error
230
+ end
231
+ it "should make the design doc upon first query" do
232
+ Unattached.by_title :database => @db
233
+ doc = Unattached.design_doc
234
+ doc['views']['all']['map'].should include('Unattached')
235
+ end
236
+ it "should merge query params" do
237
+ rs = Unattached.by_title :database=>@db, :startkey=>"bbb", :endkey=>"eee"
238
+ rs.length.should == 3
239
+ end
240
+ it "should query via view" do
241
+ view = Unattached.view :by_title, :database=>@db
242
+ designed = Unattached.by_title :database=>@db
243
+ view.should == designed
244
+ end
245
+ it "should yield" do
246
+ things = []
247
+ Unattached.view(:by_title, :database=>@db) do |thing|
248
+ things << thing
249
+ end
250
+ things[0]["doc"]["title"].should =='aaa'
251
+ end
252
+ it "should yield with by_key method" do
253
+ things = []
254
+ Unattached.by_title(:database=>@db) do |thing|
255
+ things << thing
256
+ end
257
+ things[0]["doc"]["title"].should =='aaa'
258
+ end
259
+ it "should return nil on get if no database given" do
260
+ Unattached.get("aaa").should be_nil
261
+ end
262
+ it "should barf on get! if no database given" do
263
+ lambda{Unattached.get!("aaa")}.should raise_error
264
+ end
265
+ it "should get from specific database" do
266
+ u = Unattached.get(@first_id, @db)
267
+ u.title.should == "aaa"
268
+ end
269
+ it "should barf on first if no database given" do
270
+ lambda{Unattached.first}.should raise_error
271
+ end
272
+ it "should get first" do
273
+ u = Unattached.first :database=>@db
274
+ u.title.should =~ /\A...\z/
275
+ end
276
+ it "should barf on all_design_doc_versions if no database given" do
277
+ lambda{Unattached.all_design_doc_versions}.should raise_error
278
+ end
279
+ it "should be able to cleanup the db/bump the revision number" do
280
+ # if the previous specs were not run, the model_design_doc will be blank
281
+ Unattached.use_database DB
282
+ Unattached.view_by :questions
283
+ Unattached.by_questions(:database => @db)
284
+ original_revision = Unattached.model_design_doc(@db)['_rev']
285
+ Unattached.save_design_doc!(@db)
286
+ Unattached.model_design_doc(@db)['_rev'].should_not == original_revision
287
+ end
288
+ end
289
+
290
+ describe "a model with a compound key view" do
291
+ before(:all) do
292
+ Article.by_user_id_and_date.each{|a| a.destroy(true)}
293
+ Article.database.bulk_delete
294
+ written_at = Time.now - 24 * 3600 * 7
295
+ @titles = ["uniq one", "even more interesting", "less fun", "not junk"]
296
+ @user_ids = ["quentin", "aaron"]
297
+ @titles.each_with_index do |title,i|
298
+ u = i % 2
299
+ a = Article.new(:title => title, :user_id => @user_ids[u])
300
+ a.date = written_at
301
+ a.save
302
+ written_at += 24 * 3600
303
+ end
304
+ end
305
+ it "should create the design doc" do
306
+ Article.by_user_id_and_date rescue nil
307
+ doc = Article.design_doc
308
+ doc['views']['by_date'].should_not be_nil
309
+ end
310
+ it "should sort correctly" do
311
+ articles = Article.by_user_id_and_date
312
+ articles.collect{|a|a['user_id']}.should == ['aaron', 'aaron', 'quentin',
313
+ 'quentin']
314
+ articles[1].title.should == 'not junk'
315
+ end
316
+ it "should be queryable with couchrest options" do
317
+ articles = Article.by_user_id_and_date :limit => 1, :startkey => 'quentin'
318
+ articles.length.should == 1
319
+ articles[0].title.should == "even more interesting"
320
+ end
321
+ end
322
+
323
+ describe "with a custom view" do
324
+ before(:all) do
325
+ @titles = ["very uniq one", "even less interesting", "some fun",
326
+ "really junk", "crazy bob"]
327
+ @tags = ["cool", "lame"]
328
+ @titles.each_with_index do |title,i|
329
+ u = i % 2
330
+ a = Article.new(:title => title, :tags => [@tags[u]])
331
+ a.save
332
+ end
333
+ end
334
+ it "should be available raw" do
335
+ view = Article.by_tags :raw => true
336
+ view['rows'].length.should == 5
337
+ end
338
+
339
+ it "should be default to :reduce => false" do
340
+ ars = Article.by_tags
341
+ ars.first.tags.first.should == 'cool'
342
+ end
343
+
344
+ it "should be raw when reduce is true" do
345
+ view = Article.by_tags :reduce => true, :group => true
346
+ view['rows'].find{|r|r['key'] == 'cool'}['value'].should == 3
347
+ end
348
+ end
349
+
350
+ # TODO: moved to Design, delete
351
+ describe "adding a view" do
352
+ before(:each) do
353
+ reset_test_db!
354
+ Article.by_date
355
+ @original_doc_rev = Article.model_design_doc['_rev']
356
+ @design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
357
+ end
358
+ it "should not create a design doc on view definition" do
359
+ Article.view_by :created_at
360
+ newdocs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
361
+ newdocs["rows"].length.should == @design_docs["rows"].length
362
+ end
363
+ it "should create a new version of the design document on view access" do
364
+ ddocs = Article.all_design_doc_versions["rows"].length
365
+ Article.view_by :updated_at
366
+ Article.by_updated_at
367
+ @original_doc_rev.should_not == Article.model_design_doc['_rev']
368
+ Article.design_doc["views"].keys.should include("by_updated_at")
369
+ end
370
+ end
371
+
372
+ describe "with a collection" do
373
+ before(:all) do
374
+ reset_test_db!
375
+ titles = ["very uniq one", "really interesting", "some fun",
376
+ "really awesome", "crazy bob", "this rocks", "super rad"]
377
+ titles.each_with_index do |title,i|
378
+ a = Article.new(:title => title, :date => Date.today)
379
+ a.save
380
+ end
381
+
382
+ titles = ["yesterday very uniq one", "yesterday really interesting", "yesterday some fun",
383
+ "yesterday really awesome", "yesterday crazy bob", "yesterday this rocks"]
384
+ titles.each_with_index do |title,i|
385
+ a = Article.new(:title => title, :date => Date.today - 1)
386
+ a.save
387
+ end
388
+ end
389
+ require 'date'
390
+ it "should return a proxy that looks like an array of 7 Article objects" do
391
+ articles = Article.by_date :key => Date.today
392
+ articles.class.should == Array
393
+ articles.size.should == 7
394
+ end
395
+ it "should get a subset of articles using paginate" do
396
+ articles = Article.by_date :key => Date.today
397
+ articles.paginate(:page => 1, :per_page => 3).size.should == 3
398
+ articles.paginate(:page => 2, :per_page => 3).size.should == 3
399
+ articles.paginate(:page => 3, :per_page => 3).size.should == 1
400
+ end
401
+ it "should get all articles, a few at a time, using paginated each" do
402
+ articles = Article.by_date :key => Date.today
403
+ articles.paginated_each(:per_page => 3) do |a|
404
+ a.should_not be_nil
405
+ end
406
+ end
407
+ it "should provide a class method to access the collection directly" do
408
+ articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
409
+ :key => Date.today, :include_docs => true)
410
+ articles.class.should == Array
411
+ articles.size.should == 7
412
+ end
413
+ it "should provide a class method for paginate" do
414
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
415
+ :per_page => 3, :descending => true, :key => Date.today, :include_docs => true)
416
+ articles.size.should == 3
417
+
418
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
419
+ :per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
420
+ articles.size.should == 3
421
+
422
+ articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
423
+ :per_page => 3, :page => 3, :descending => true, :key => Date.today, :include_docs => true)
424
+ articles.size.should == 1
425
+ end
426
+ it "should provide a class method for paginated_each" do
427
+ options = { :design_doc => 'Article', :view_name => 'by_date',
428
+ :per_page => 3, :page => 1, :descending => true, :key => Date.today,
429
+ :include_docs => true }
430
+ Article.paginated_each(options) do |a|
431
+ a.should_not be_nil
432
+ end
433
+ end
434
+ it "should provide a class method to get a collection for a view" do
435
+ articles = Article.find_all_article_details(:key => Date.today)
436
+ articles.class.should == Array
437
+ articles.size.should == 7
438
+ end
439
+ it "should raise an exception if design_doc is not provided" do
440
+ lambda{Article.collection_proxy_for(nil, 'by_date')}.should raise_error
441
+ lambda{Article.paginate(:view_name => 'by_date')}.should raise_error
442
+ end
443
+ it "should raise an exception if view_name is not provided" do
444
+ lambda{Article.collection_proxy_for('Article', nil)}.should raise_error
445
+ lambda{Article.paginate(:design_doc => 'Article')}.should raise_error
446
+ end
447
+ it "should be able to span multiple keys" do
448
+ articles = Article.by_date :startkey => Date.today, :endkey => Date.today - 1
449
+ articles.paginate(:page => 1, :per_page => 3).size.should == 3
450
+ articles.paginate(:page => 2, :per_page => 3).size.should == 3
451
+ articles.paginate(:page => 3, :per_page => 3).size.should == 3
452
+ articles.paginate(:page => 4, :per_page => 3).size.should == 3
453
+ articles.paginate(:page => 5, :per_page => 3).size.should == 1
454
+ end
455
+ it "should pass database parameter to pager" do
456
+ proxy = mock(:proxy)
457
+ proxy.stub!(:paginate)
458
+ ::CouchRest::Model::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
459
+ Article.paginate(:design_doc => 'Article', :view_name => 'by_date', :database => 'database')
460
+ end
461
+ end
462
+
463
+ end
@@ -0,0 +1,3 @@
1
+ This is an example README file.
2
+
3
+ More of the README, whee.
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test</title>
5
+ </head>
6
+ <body>
7
+ <p>
8
+ Test
9
+ </p>
10
+ </body>
11
+ </html>