openlogic-couchrest_model 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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