openlogic-couchrest_model 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 (107) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +4 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +176 -0
  5. data/README.md +137 -0
  6. data/Rakefile +38 -0
  7. data/THANKS.md +21 -0
  8. data/VERSION +1 -0
  9. data/benchmarks/dirty.rb +118 -0
  10. data/couchrest_model.gemspec +36 -0
  11. data/history.md +309 -0
  12. data/init.rb +1 -0
  13. data/lib/couchrest/model.rb +10 -0
  14. data/lib/couchrest/model/associations.rb +231 -0
  15. data/lib/couchrest/model/base.rb +129 -0
  16. data/lib/couchrest/model/callbacks.rb +28 -0
  17. data/lib/couchrest/model/casted_array.rb +83 -0
  18. data/lib/couchrest/model/casted_by.rb +33 -0
  19. data/lib/couchrest/model/casted_hash.rb +84 -0
  20. data/lib/couchrest/model/class_proxy.rb +135 -0
  21. data/lib/couchrest/model/collection.rb +273 -0
  22. data/lib/couchrest/model/configuration.rb +67 -0
  23. data/lib/couchrest/model/connection.rb +70 -0
  24. data/lib/couchrest/model/core_extensions/hash.rb +9 -0
  25. data/lib/couchrest/model/core_extensions/time_parsing.rb +66 -0
  26. data/lib/couchrest/model/design_doc.rb +128 -0
  27. data/lib/couchrest/model/designs.rb +91 -0
  28. data/lib/couchrest/model/designs/view.rb +513 -0
  29. data/lib/couchrest/model/dirty.rb +39 -0
  30. data/lib/couchrest/model/document_queries.rb +99 -0
  31. data/lib/couchrest/model/embeddable.rb +78 -0
  32. data/lib/couchrest/model/errors.rb +25 -0
  33. data/lib/couchrest/model/extended_attachments.rb +83 -0
  34. data/lib/couchrest/model/persistence.rb +178 -0
  35. data/lib/couchrest/model/properties.rb +228 -0
  36. data/lib/couchrest/model/property.rb +114 -0
  37. data/lib/couchrest/model/property_protection.rb +71 -0
  38. data/lib/couchrest/model/proxyable.rb +183 -0
  39. data/lib/couchrest/model/support/couchrest_database.rb +13 -0
  40. data/lib/couchrest/model/support/couchrest_design.rb +33 -0
  41. data/lib/couchrest/model/typecast.rb +154 -0
  42. data/lib/couchrest/model/validations.rb +80 -0
  43. data/lib/couchrest/model/validations/casted_model.rb +16 -0
  44. data/lib/couchrest/model/validations/locale/en.yml +5 -0
  45. data/lib/couchrest/model/validations/uniqueness.rb +69 -0
  46. data/lib/couchrest/model/views.rb +151 -0
  47. data/lib/couchrest/railtie.rb +24 -0
  48. data/lib/couchrest_model.rb +66 -0
  49. data/lib/rails/generators/couchrest_model.rb +16 -0
  50. data/lib/rails/generators/couchrest_model/config/config_generator.rb +18 -0
  51. data/lib/rails/generators/couchrest_model/config/templates/couchdb.yml +21 -0
  52. data/lib/rails/generators/couchrest_model/model/model_generator.rb +27 -0
  53. data/lib/rails/generators/couchrest_model/model/templates/model.rb +2 -0
  54. data/spec/.gitignore +1 -0
  55. data/spec/fixtures/attachments/README +3 -0
  56. data/spec/fixtures/attachments/couchdb.png +0 -0
  57. data/spec/fixtures/attachments/test.html +11 -0
  58. data/spec/fixtures/config/couchdb.yml +10 -0
  59. data/spec/fixtures/models/article.rb +36 -0
  60. data/spec/fixtures/models/base.rb +164 -0
  61. data/spec/fixtures/models/card.rb +19 -0
  62. data/spec/fixtures/models/cat.rb +23 -0
  63. data/spec/fixtures/models/client.rb +6 -0
  64. data/spec/fixtures/models/course.rb +27 -0
  65. data/spec/fixtures/models/event.rb +8 -0
  66. data/spec/fixtures/models/invoice.rb +14 -0
  67. data/spec/fixtures/models/key_chain.rb +5 -0
  68. data/spec/fixtures/models/membership.rb +4 -0
  69. data/spec/fixtures/models/person.rb +11 -0
  70. data/spec/fixtures/models/project.rb +6 -0
  71. data/spec/fixtures/models/question.rb +7 -0
  72. data/spec/fixtures/models/sale_entry.rb +9 -0
  73. data/spec/fixtures/models/sale_invoice.rb +14 -0
  74. data/spec/fixtures/models/service.rb +10 -0
  75. data/spec/fixtures/models/user.rb +22 -0
  76. data/spec/fixtures/views/lib.js +3 -0
  77. data/spec/fixtures/views/test_view/lib.js +3 -0
  78. data/spec/fixtures/views/test_view/only-map.js +4 -0
  79. data/spec/fixtures/views/test_view/test-map.js +3 -0
  80. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  81. data/spec/functional/validations_spec.rb +8 -0
  82. data/spec/spec_helper.rb +60 -0
  83. data/spec/unit/active_model_lint_spec.rb +30 -0
  84. data/spec/unit/assocations_spec.rb +242 -0
  85. data/spec/unit/attachment_spec.rb +176 -0
  86. data/spec/unit/base_spec.rb +537 -0
  87. data/spec/unit/casted_spec.rb +72 -0
  88. data/spec/unit/class_proxy_spec.rb +167 -0
  89. data/spec/unit/collection_spec.rb +86 -0
  90. data/spec/unit/configuration_spec.rb +77 -0
  91. data/spec/unit/connection_spec.rb +148 -0
  92. data/spec/unit/core_extensions/time_parsing.rb +77 -0
  93. data/spec/unit/design_doc_spec.rb +241 -0
  94. data/spec/unit/designs/view_spec.rb +831 -0
  95. data/spec/unit/designs_spec.rb +134 -0
  96. data/spec/unit/dirty_spec.rb +436 -0
  97. data/spec/unit/embeddable_spec.rb +498 -0
  98. data/spec/unit/inherited_spec.rb +33 -0
  99. data/spec/unit/persistence_spec.rb +481 -0
  100. data/spec/unit/property_protection_spec.rb +192 -0
  101. data/spec/unit/property_spec.rb +481 -0
  102. data/spec/unit/proxyable_spec.rb +376 -0
  103. data/spec/unit/subclass_spec.rb +85 -0
  104. data/spec/unit/typecast_spec.rb +521 -0
  105. data/spec/unit/validations_spec.rb +140 -0
  106. data/spec/unit/view_spec.rb +367 -0
  107. metadata +301 -0
@@ -0,0 +1,140 @@
1
+ require "spec_helper"
2
+
3
+ describe CouchRest::Model::Validations do
4
+
5
+ describe "Uniqueness" do
6
+
7
+ context "basic" do
8
+ before(:all) do
9
+ @objs = ['title 1', 'title 2', 'title 3'].map{|t| WithUniqueValidation.create(:title => t)}
10
+ end
11
+
12
+ it "should create a new view if none defined before performing" do
13
+ WithUniqueValidation.has_view?(:by_title).should be_true
14
+ end
15
+
16
+ it "should validate a new unique document" do
17
+ @obj = WithUniqueValidation.create(:title => 'title 4')
18
+ @obj.new?.should_not be_true
19
+ @obj.should be_valid
20
+ end
21
+
22
+ it "should not validate a non-unique document" do
23
+ @obj = WithUniqueValidation.create(:title => 'title 1')
24
+ @obj.should_not be_valid
25
+ @obj.errors[:title].should == ["has already been taken"]
26
+ end
27
+
28
+ it "should save already created document" do
29
+ @obj = @objs.first
30
+ @obj.save.should_not be_false
31
+ @obj.should be_valid
32
+ end
33
+
34
+
35
+ it "should allow own view to be specified" do
36
+ # validates_uniqueness_of :code, :view => 'all'
37
+ WithUniqueValidationView.create(:title => 'title 1', :code => '1234')
38
+ @obj = WithUniqueValidationView.new(:title => 'title 5', :code => '1234')
39
+ @obj.should_not be_valid
40
+ end
41
+
42
+ it "should raise an error if specified view does not exist" do
43
+ WithUniqueValidationView.validates_uniqueness_of :title, :view => 'fooobar'
44
+ @obj = WithUniqueValidationView.new(:title => 'title 2', :code => '12345')
45
+ lambda {
46
+ @obj.valid?
47
+ }.should raise_error
48
+ end
49
+
50
+ it "should not try to create a defined view" do
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
54
+ end
55
+
56
+
57
+ it "should not try to create new view when already defined" do
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' => [ ]})
62
+ @obj.valid?
63
+ end
64
+ end
65
+
66
+ context "with a proxy parameter" do
67
+
68
+ it "should create a new view despite proxy" do
69
+ WithUniqueValidationProxy.has_view?(:by_title).should be_true
70
+ end
71
+
72
+ it "should be used" do
73
+ @obj = WithUniqueValidationProxy.new(:title => 'test 6')
74
+ proxy = @obj.should_receive('proxy').and_return(@obj.class)
75
+ @obj.valid?.should be_true
76
+ end
77
+
78
+ it "should allow specific view" do
79
+ @obj = WithUniqueValidationProxy.new(:title => 'test 7')
80
+ @obj.class.should_not_receive('view_by')
81
+ proxy = mock('Proxy')
82
+ @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
+ @obj.valid?
86
+ end
87
+ end
88
+
89
+ context "when proxied" do
90
+ it "should lookup the model_proxy" do
91
+ mp = mock(:ModelProxy)
92
+ mp.should_receive(:view).and_return({'rows' => []})
93
+ @obj = WithUniqueValidation.new(:title => 'test 8')
94
+ @obj.stub!(:model_proxy).twice.and_return(mp)
95
+ @obj.valid?
96
+ end
97
+ end
98
+
99
+ context "with a scope" do
100
+ before(:all) do
101
+ @objs = [['title 1', 1], ['title 2', 1], ['title 3', 1]].map{|t| WithScopedUniqueValidation.create(:title => t[0], :parent_id => t[1])}
102
+ @objs_nil = [['title 1', nil], ['title 2', nil], ['title 3', nil]].map{|t| WithScopedUniqueValidation.create(:title => t[0], :parent_id => t[1])}
103
+ end
104
+
105
+ it "should create the view" do
106
+ @objs.first.class.has_view?('by_parent_id_and_title')
107
+ end
108
+
109
+ it "should validate unique document" do
110
+ @obj = WithScopedUniqueValidation.create(:title => 'title 4', :parent_id => 1)
111
+ @obj.should be_valid
112
+ end
113
+
114
+ it "should validate unique document outside of scope" do
115
+ @obj = WithScopedUniqueValidation.create(:title => 'title 1', :parent_id => 2)
116
+ @obj.should be_valid
117
+ end
118
+
119
+ it "should validate non-unique document" do
120
+ @obj = WithScopedUniqueValidation.create(:title => 'title 1', :parent_id => 1)
121
+ @obj.should_not be_valid
122
+ @obj.errors[:title].should == ["has already been taken"]
123
+ end
124
+
125
+ it "should validate unique document will nil scope" do
126
+ @obj = WithScopedUniqueValidation.create(:title => 'title 4', :parent_id => nil)
127
+ @obj.should be_valid
128
+ end
129
+
130
+ it "should validate non-unique document with nil scope" do
131
+ @obj = WithScopedUniqueValidation.create(:title => 'title 1', :parent_id => nil)
132
+ @obj.should_not be_valid
133
+ @obj.errors[:title].should == ["has already been taken"]
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,367 @@
1
+ require "spec_helper"
2
+
3
+ describe CouchRest::Model::Views do
4
+
5
+ class Unattached < CouchRest::Model::Base
6
+ property :title
7
+ property :questions
8
+ property :professor
9
+ view_by :title
10
+
11
+ # Force the database to always be nil
12
+ def self.database
13
+ nil
14
+ end
15
+ end
16
+
17
+ describe "ClassMethods" do
18
+ # NOTE! Add more unit tests!
19
+
20
+ describe "#view" do
21
+
22
+ it "should not alter original query" do
23
+ options = { :database => DB }
24
+ view = Article.view('by_date', options)
25
+ options[:database].should eql(DB)
26
+ end
27
+
28
+ end
29
+
30
+ describe "#has_view?" do
31
+ it "should check the design doc" do
32
+ Article.design_doc.should_receive(:has_view?).with(:test).and_return(true)
33
+ Article.has_view?(:test).should be_true
34
+ end
35
+ end
36
+
37
+ describe "#can_reduce_view?" do
38
+ it "should check if view has a reduce method" do
39
+ Article.design_doc.should_receive(:can_reduce_view?).with(:test).and_return(true)
40
+ Article.can_reduce_view?(:test).should be_true
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "a model with simple views and a default param" do
46
+ before(:all) do
47
+ Article.all.map{|a| a.destroy(true)}
48
+ Article.database.bulk_delete
49
+ written_at = Time.now - 24 * 3600 * 7
50
+ @titles = ["this and that", "also interesting", "more fun", "some junk"]
51
+ @titles.each do |title|
52
+ a = Article.new(:title => title)
53
+ a.date = written_at
54
+ a.save
55
+ written_at += 24 * 3600
56
+ end
57
+ end
58
+ it "should return the matching raw view result" do
59
+ view = Article.by_date :raw => true
60
+ view['rows'].length.should == 4
61
+ end
62
+ it "should not include non-Articles" do
63
+ Article.database.save_doc({"date" => 1})
64
+ view = Article.by_date :raw => true
65
+ view['rows'].length.should == 4
66
+ end
67
+ it "should return the matching objects (with default argument :descending => true)" do
68
+ articles = Article.by_date
69
+ articles.collect{|a|a.title}.should == @titles.reverse
70
+ end
71
+ it "should allow you to override default args" do
72
+ articles = Article.by_date :descending => false
73
+ articles.collect{|a|a.title}.should == @titles
74
+ end
75
+ it "should allow you to create a new view on the fly" do
76
+ lambda{Article.by_title}.should raise_error
77
+ Article.view_by :title
78
+ lambda{Article.by_title}.should_not raise_error
79
+ end
80
+ end
81
+
82
+ describe "another model with a simple view" do
83
+ before(:all) do
84
+ reset_test_db!
85
+ %w{aaa bbb ddd eee}.each do |title|
86
+ Course.new(:title => title).save
87
+ end
88
+ end
89
+ it "should make the design doc upon first query" do
90
+ Course.by_title
91
+ doc = Course.design_doc
92
+ doc['views']['all']['map'].should include('Course')
93
+ end
94
+ it "should can query via view" do
95
+ # register methods with method-missing, for local dispatch. method
96
+ # missing lookup table, no heuristics.
97
+ view = Course.view :by_title
98
+ designed = Course.by_title
99
+ view.should == designed
100
+ end
101
+ it "should get them" do
102
+ rs = Course.by_title
103
+ rs.length.should == 4
104
+ end
105
+ it "should yield" do
106
+ courses = []
107
+ Course.view(:by_title) do |course|
108
+ courses << course
109
+ end
110
+ courses[0]["doc"]["title"].should =='aaa'
111
+ end
112
+ it "should yield with by_key method" do
113
+ courses = []
114
+ Course.by_title do |course|
115
+ courses << course
116
+ end
117
+ courses[0]["doc"]["title"].should =='aaa'
118
+ end
119
+ end
120
+
121
+ describe "find a single item using a view" do
122
+ before(:all) do
123
+ reset_test_db!
124
+ %w{aaa bbb ddd eee}.each do |title|
125
+ Course.new(:title => title, :active => (title == 'bbb')).save
126
+ end
127
+ end
128
+
129
+ it "should return single matched record with find helper" do
130
+ course = Course.find_by_title('bbb')
131
+ course.should_not be_nil
132
+ course.title.should eql('bbb') # Ensure really is a Course!
133
+ end
134
+
135
+ it "should return nil if not found" do
136
+ course = Course.find_by_title('fff')
137
+ course.should be_nil
138
+ end
139
+
140
+ it "should peform search on view with two properties" do
141
+ course = Course.find_by_title_and_active(['bbb', true])
142
+ course.should_not be_nil
143
+ course.title.should eql('bbb') # Ensure really is a Course!
144
+ end
145
+
146
+ it "should return nil if not found" do
147
+ course = Course.find_by_title_and_active(['bbb', false])
148
+ course.should be_nil
149
+ end
150
+
151
+ it "should raise exception if view not present" do
152
+ lambda { Course.find_by_foobar('123') }.should raise_error(NoMethodError)
153
+ end
154
+
155
+ it "should perform a search directly with specific key" do
156
+ course = Course.first_from_view('by_title', 'bbb')
157
+ course.title.should eql('bbb')
158
+ end
159
+
160
+ it "should perform a search directly with specific key with options" do
161
+ course = Course.first_from_view('by_title', 'bbb', :reverse => true)
162
+ course.title.should eql('bbb')
163
+ end
164
+
165
+ it "should perform a search directly with range" do
166
+ course = Course.first_from_view('by_title', :startkey => 'bbb', :endkey => 'eee')
167
+ course.title.should eql('bbb')
168
+ end
169
+
170
+ it "should perform a search for first when reduce method present" do
171
+ course = Course.first_from_view('by_active')
172
+ course.should_not be_nil
173
+ end
174
+
175
+ end
176
+
177
+ describe "#method_missing for find_by methods" do
178
+ before(:all) { reset_test_db! }
179
+
180
+ specify { Course.should respond_to :find_by_title_and_active }
181
+ specify { Course.should respond_to :by_title }
182
+
183
+ specify "#method should work in ruby 1.9, but not 1.8" do
184
+ if RUBY_VERSION >= "1.9"
185
+ Course.method(:find_by_title_and_active).should be_a Method
186
+ else
187
+ expect { Course.method(:find_by_title_and_active) }.to raise_error(NameError)
188
+ end
189
+ end
190
+ end
191
+
192
+ describe "a ducktype view" do
193
+ before(:all) do
194
+ reset_test_db!
195
+ @id = DB.save_doc({:dept => true})['id']
196
+ end
197
+ it "should setup" do
198
+ duck = Course.get(@id) # from a different db
199
+ duck["dept"].should == true
200
+ end
201
+ it "should make the design doc" do
202
+ @as = Course.by_dept
203
+ @doc = Course.design_doc
204
+ @doc["views"]["by_dept"]["map"].should_not include("couchrest")
205
+ end
206
+ it "should not look for class" do
207
+ @as = Course.by_dept
208
+ @as[0]['_id'].should == @id
209
+ end
210
+ end
211
+
212
+ describe "a model class with database provided manually" do
213
+ before(:all) do
214
+ reset_test_db!
215
+ @db = DB
216
+ %w{aaa bbb ddd eee}.each do |title|
217
+ u = Unattached.new(:title => title)
218
+ u.database = @db
219
+ u.save
220
+ @first_id ||= u.id
221
+ end
222
+ end
223
+ it "should barf on all if no database given" do
224
+ lambda{Unattached.all}.should raise_error
225
+ end
226
+ it "should query all" do
227
+ rs = Unattached.all :database => @db
228
+ rs.length.should == 4
229
+ end
230
+ it "should barf on query if no database given" do
231
+ lambda{Unattached.view :by_title}.should raise_error
232
+ end
233
+ it "should make the design doc upon first query" do
234
+ Unattached.by_title :database => @db
235
+ doc = Unattached.design_doc
236
+ doc['views']['all']['map'].should include('Unattached')
237
+ end
238
+ it "should merge query params" do
239
+ rs = Unattached.by_title :database=>@db, :startkey=>"bbb", :endkey=>"eee"
240
+ rs.length.should == 3
241
+ end
242
+ it "should query via view" do
243
+ view = Unattached.view :by_title, :database=>@db
244
+ designed = Unattached.by_title :database=>@db
245
+ view.should == designed
246
+ end
247
+ it "should yield" do
248
+ things = []
249
+ Unattached.view(:by_title, :database=>@db) do |thing|
250
+ things << thing
251
+ end
252
+ things[0]["doc"]["title"].should =='aaa'
253
+ end
254
+ it "should yield with by_key method" do
255
+ things = []
256
+ Unattached.by_title(:database=>@db) do |thing|
257
+ things << thing
258
+ end
259
+ things[0]["doc"]["title"].should =='aaa'
260
+ end
261
+ it "should return nil on get if no database given" do
262
+ Unattached.get("aaa").should be_nil
263
+ end
264
+ it "should barf on get! if no database given" do
265
+ lambda{Unattached.get!("aaa")}.should raise_error
266
+ end
267
+ it "should get from specific database" do
268
+ u = Unattached.get(@first_id, @db)
269
+ u.title.should == "aaa"
270
+ end
271
+ it "should barf on first if no database given" do
272
+ lambda{Unattached.first}.should raise_error
273
+ end
274
+ it "should get first" do
275
+ u = Unattached.first :database=>@db
276
+ u.title.should =~ /\A...\z/
277
+ end
278
+
279
+ it "should get last" do
280
+ u = Unattached.last :database=>@db
281
+ u.title.should == "aaa"
282
+ end
283
+
284
+ end
285
+
286
+ describe "a model with a compound key view" do
287
+ before(:all) do
288
+ Article.by_user_id_and_date.each{|a| a.destroy(true)}
289
+ Article.database.bulk_delete
290
+ written_at = Time.now - 24 * 3600 * 7
291
+ @titles = ["uniq one", "even more interesting", "less fun", "not junk"]
292
+ @user_ids = ["quentin", "aaron"]
293
+ @titles.each_with_index do |title,i|
294
+ u = i % 2
295
+ a = Article.new(:title => title, :user_id => @user_ids[u])
296
+ a.date = written_at
297
+ a.save
298
+ written_at += 24 * 3600
299
+ end
300
+ end
301
+ it "should create the design doc" do
302
+ Article.by_user_id_and_date rescue nil
303
+ doc = Article.design_doc
304
+ doc['views']['by_date'].should_not be_nil
305
+ end
306
+ it "should sort correctly" do
307
+ articles = Article.by_user_id_and_date
308
+ articles.collect{|a|a['user_id']}.should == ['aaron', 'aaron', 'quentin',
309
+ 'quentin']
310
+ articles[1].title.should == 'not junk'
311
+ end
312
+ it "should be queryable with couchrest options" do
313
+ articles = Article.by_user_id_and_date :limit => 1, :startkey => 'quentin'
314
+ articles.length.should == 1
315
+ articles[0].title.should == "even more interesting"
316
+ end
317
+ end
318
+
319
+ describe "with a custom view" do
320
+ before(:all) do
321
+ @titles = ["very uniq one", "even less interesting", "some fun",
322
+ "really junk", "crazy bob"]
323
+ @tags = ["cool", "lame"]
324
+ @titles.each_with_index do |title,i|
325
+ u = i % 2
326
+ a = Article.new(:title => title, :tags => [@tags[u]])
327
+ a.save
328
+ end
329
+ end
330
+ it "should be available raw" do
331
+ view = Article.by_tags :raw => true
332
+ view['rows'].length.should == 5
333
+ end
334
+
335
+ it "should be default to :reduce => false" do
336
+ ars = Article.by_tags
337
+ ars.first.tags.first.should == 'cool'
338
+ end
339
+
340
+ it "should be raw when reduce is true" do
341
+ view = Article.by_tags :reduce => true, :group => true
342
+ view['rows'].find{|r|r['key'] == 'cool'}['value'].should == 3
343
+ end
344
+ end
345
+
346
+ # TODO: moved to Design, delete
347
+ describe "adding a view" do
348
+ before(:each) do
349
+ reset_test_db!
350
+ Article.by_date
351
+ @original_doc_rev = Article.stored_design_doc['_rev']
352
+ @design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
353
+ end
354
+ it "should not create a design doc on view definition" do
355
+ Article.view_by :created_at
356
+ newdocs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
357
+ newdocs["rows"].length.should == @design_docs["rows"].length
358
+ end
359
+ it "should create a new version of the design document on view access" do
360
+ Article.view_by :updated_at
361
+ Article.by_updated_at
362
+ @original_doc_rev.should_not == Article.stored_design_doc['_rev']
363
+ Article.design_doc["views"].keys.should include("by_updated_at")
364
+ end
365
+ end
366
+
367
+ end