couchrest 0.38 → 1.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. data/README.md +8 -8
  2. data/Rakefile +3 -4
  3. data/couchrest.gemspec +25 -105
  4. data/history.txt +5 -4
  5. data/lib/couchrest.rb +31 -52
  6. data/lib/couchrest/{core/database.rb → database.rb} +6 -11
  7. data/lib/couchrest/{core/design.rb → design.rb} +2 -2
  8. data/lib/couchrest/{core/document.rb → document.rb} +1 -1
  9. data/lib/couchrest/helper/attachments.rb +29 -0
  10. data/lib/couchrest/middlewares/logger.rb +3 -3
  11. data/lib/couchrest/monkeypatches.rb +1 -71
  12. data/lib/couchrest/{core/response.rb → response.rb} +0 -0
  13. data/lib/couchrest/{core/rest_api.rb → rest_api.rb} +8 -12
  14. data/lib/couchrest/{core/server.rb → server.rb} +0 -2
  15. data/spec/couchrest/{core/couchrest_spec.rb → couchrest_spec.rb} +15 -9
  16. data/spec/couchrest/{core/database_spec.rb → database_spec.rb} +4 -4
  17. data/spec/couchrest/{core/design_spec.rb → design_spec.rb} +2 -2
  18. data/spec/couchrest/{core/document_spec.rb → document_spec.rb} +1 -1
  19. data/spec/couchrest/{core/server_spec.rb → server_spec.rb} +2 -2
  20. data/spec/spec.opts +0 -1
  21. data/spec/spec_helper.rb +0 -4
  22. metadata +32 -133
  23. data/examples/model/example.rb +0 -144
  24. data/lib/couchrest/core/adapters/restclient.rb +0 -35
  25. data/lib/couchrest/core/http_abstraction.rb +0 -48
  26. data/lib/couchrest/core/view.rb +0 -4
  27. data/lib/couchrest/mixins.rb +0 -4
  28. data/lib/couchrest/mixins/attachments.rb +0 -31
  29. data/lib/couchrest/mixins/attribute_protection.rb +0 -74
  30. data/lib/couchrest/mixins/callbacks.rb +0 -532
  31. data/lib/couchrest/mixins/class_proxy.rb +0 -124
  32. data/lib/couchrest/mixins/collection.rb +0 -260
  33. data/lib/couchrest/mixins/design_doc.rb +0 -103
  34. data/lib/couchrest/mixins/document_queries.rb +0 -80
  35. data/lib/couchrest/mixins/extended_attachments.rb +0 -70
  36. data/lib/couchrest/mixins/extended_document_mixins.rb +0 -9
  37. data/lib/couchrest/mixins/properties.rb +0 -158
  38. data/lib/couchrest/mixins/validation.rb +0 -246
  39. data/lib/couchrest/mixins/views.rb +0 -173
  40. data/lib/couchrest/more/casted_model.rb +0 -58
  41. data/lib/couchrest/more/extended_document.rb +0 -310
  42. data/lib/couchrest/more/property.rb +0 -58
  43. data/lib/couchrest/more/typecast.rb +0 -180
  44. data/lib/couchrest/support/blank.rb +0 -42
  45. data/lib/couchrest/support/rails.rb +0 -42
  46. data/lib/couchrest/validation/auto_validate.rb +0 -157
  47. data/lib/couchrest/validation/contextual_validators.rb +0 -78
  48. data/lib/couchrest/validation/validation_errors.rb +0 -125
  49. data/lib/couchrest/validation/validators/absent_field_validator.rb +0 -74
  50. data/lib/couchrest/validation/validators/confirmation_validator.rb +0 -107
  51. data/lib/couchrest/validation/validators/format_validator.rb +0 -122
  52. data/lib/couchrest/validation/validators/formats/email.rb +0 -66
  53. data/lib/couchrest/validation/validators/formats/url.rb +0 -43
  54. data/lib/couchrest/validation/validators/generic_validator.rb +0 -120
  55. data/lib/couchrest/validation/validators/length_validator.rb +0 -139
  56. data/lib/couchrest/validation/validators/method_validator.rb +0 -89
  57. data/lib/couchrest/validation/validators/numeric_validator.rb +0 -109
  58. data/lib/couchrest/validation/validators/required_field_validator.rb +0 -114
  59. data/spec/couchrest/more/attribute_protection_spec.rb +0 -150
  60. data/spec/couchrest/more/casted_extended_doc_spec.rb +0 -73
  61. data/spec/couchrest/more/casted_model_spec.rb +0 -406
  62. data/spec/couchrest/more/extended_doc_attachment_spec.rb +0 -135
  63. data/spec/couchrest/more/extended_doc_inherited_spec.rb +0 -40
  64. data/spec/couchrest/more/extended_doc_spec.rb +0 -807
  65. data/spec/couchrest/more/extended_doc_subclass_spec.rb +0 -98
  66. data/spec/couchrest/more/extended_doc_view_spec.rb +0 -456
  67. data/spec/couchrest/more/property_spec.rb +0 -628
  68. data/spec/fixtures/more/article.rb +0 -35
  69. data/spec/fixtures/more/card.rb +0 -22
  70. data/spec/fixtures/more/cat.rb +0 -20
  71. data/spec/fixtures/more/course.rb +0 -22
  72. data/spec/fixtures/more/event.rb +0 -8
  73. data/spec/fixtures/more/invoice.rb +0 -17
  74. data/spec/fixtures/more/person.rb +0 -9
  75. data/spec/fixtures/more/question.rb +0 -6
  76. data/spec/fixtures/more/service.rb +0 -12
  77. data/spec/fixtures/more/user.rb +0 -22
@@ -1,135 +0,0 @@
1
- require File.expand_path('../../../spec_helper', __FILE__)
2
-
3
- describe "ExtendedDocument attachments" do
4
-
5
- describe "#has_attachment?" do
6
- before(:each) do
7
- reset_test_db!
8
- @obj = Basic.new
9
- @obj.save.should == true
10
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
11
- @attachment_name = 'my_attachment'
12
- @obj.create_attachment(:file => @file, :name => @attachment_name)
13
- end
14
-
15
- it 'should return false if there is no attachment' do
16
- @obj.has_attachment?('bogus').should be_false
17
- end
18
-
19
- it 'should return true if there is an attachment' do
20
- @obj.has_attachment?(@attachment_name).should be_true
21
- end
22
-
23
- it 'should return true if an object with an attachment is reloaded' do
24
- @obj.save.should be_true
25
- reloaded_obj = Basic.get(@obj.id)
26
- reloaded_obj.has_attachment?(@attachment_name).should be_true
27
- end
28
-
29
- it 'should return false if an attachment has been removed' do
30
- @obj.delete_attachment(@attachment_name)
31
- @obj.has_attachment?(@attachment_name).should be_false
32
- end
33
- end
34
-
35
- describe "creating an attachment" do
36
- before(:each) do
37
- @obj = Basic.new
38
- @obj.save.should == true
39
- @file_ext = File.open(FIXTURE_PATH + '/attachments/test.html')
40
- @file_no_ext = File.open(FIXTURE_PATH + '/attachments/README')
41
- @attachment_name = 'my_attachment'
42
- @content_type = 'media/mp3'
43
- end
44
-
45
- it "should create an attachment from file with an extension" do
46
- @obj.create_attachment(:file => @file_ext, :name => @attachment_name)
47
- @obj.save.should == true
48
- reloaded_obj = Basic.get(@obj.id)
49
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
50
- end
51
-
52
- it "should create an attachment from file without an extension" do
53
- @obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
54
- @obj.save.should == true
55
- reloaded_obj = Basic.get(@obj.id)
56
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
57
- end
58
-
59
- it 'should raise ArgumentError if :file is missing' do
60
- lambda{ @obj.create_attachment(:name => @attachment_name) }.should raise_error
61
- end
62
-
63
- it 'should raise ArgumentError if :name is missing' do
64
- lambda{ @obj.create_attachment(:file => @file_ext) }.should raise_error
65
- end
66
-
67
- it 'should set the content-type if passed' do
68
- @obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
69
- @obj['_attachments'][@attachment_name]['content_type'].should == @content_type
70
- end
71
- end
72
-
73
- describe 'reading, updating, and deleting an attachment' do
74
- before(:each) do
75
- @obj = Basic.new
76
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
77
- @attachment_name = 'my_attachment'
78
- @obj.create_attachment(:file => @file, :name => @attachment_name)
79
- @obj.save.should == true
80
- @file.rewind
81
- @content_type = 'media/mp3'
82
- end
83
-
84
- it 'should read an attachment that exists' do
85
- @obj.read_attachment(@attachment_name).should == @file.read
86
- end
87
-
88
- it 'should update an attachment that exists' do
89
- file = File.open(FIXTURE_PATH + '/attachments/README')
90
- @file.should_not == file
91
- @obj.update_attachment(:file => file, :name => @attachment_name)
92
- @obj.save
93
- reloaded_obj = Basic.get(@obj.id)
94
- file.rewind
95
- reloaded_obj.read_attachment(@attachment_name).should_not == @file.read
96
- reloaded_obj.read_attachment(@attachment_name).should == file.read
97
- end
98
-
99
- it 'should se the content-type if passed' do
100
- file = File.open(FIXTURE_PATH + '/attachments/README')
101
- @file.should_not == file
102
- @obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
103
- @obj['_attachments'][@attachment_name]['content_type'].should == @content_type
104
- end
105
-
106
- it 'should delete an attachment that exists' do
107
- @obj.delete_attachment(@attachment_name)
108
- @obj.save
109
- lambda{Basic.get(@obj.id).read_attachment(@attachment_name)}.should raise_error
110
- end
111
- end
112
-
113
- describe "#attachment_url" do
114
- before(:each) do
115
- @obj = Basic.new
116
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
117
- @attachment_name = 'my_attachment'
118
- @obj.create_attachment(:file => @file, :name => @attachment_name)
119
- @obj.save.should == true
120
- end
121
-
122
- it 'should return nil if attachment does not exist' do
123
- @obj.attachment_url('bogus').should be_nil
124
- end
125
-
126
- it 'should return the attachment URL as specified by CouchDB HttpDocumentApi' do
127
- @obj.attachment_url(@attachment_name).should == "#{Basic.database}/#{@obj.id}/#{@attachment_name}"
128
- end
129
-
130
- it 'should return the attachment URI' do
131
- @obj.attachment_uri(@attachment_name).should == "#{Basic.database.uri}/#{@obj.id}/#{@attachment_name}"
132
- end
133
-
134
- end
135
- end
@@ -1,40 +0,0 @@
1
- require File.expand_path('../../../spec_helper', __FILE__)
2
-
3
- begin
4
- require 'rubygems' unless ENV['SKIP_RUBYGEMS']
5
- require 'activesupport'
6
- ActiveSupport::JSON.backend = :JSONGem
7
-
8
- class PlainParent
9
- class_inheritable_accessor :foo
10
- self.foo = :bar
11
- end
12
-
13
- class PlainChild < PlainParent
14
- end
15
-
16
- class ExtendedParent < CouchRest::ExtendedDocument
17
- class_inheritable_accessor :foo
18
- self.foo = :bar
19
- end
20
-
21
- class ExtendedChild < ExtendedParent
22
- end
23
-
24
- describe "Using chained inheritance without CouchRest::ExtendedDocument" do
25
- it "should preserve inheritable attributes" do
26
- PlainParent.foo.should == :bar
27
- PlainChild.foo.should == :bar
28
- end
29
- end
30
-
31
- describe "Using chained inheritance with CouchRest::ExtendedDocument" do
32
- it "should preserve inheritable attributes" do
33
- ExtendedParent.foo.should == :bar
34
- ExtendedChild.foo.should == :bar
35
- end
36
- end
37
-
38
- rescue LoadError
39
- puts "This spec requires 'active_support' to be loaded"
40
- end
@@ -1,807 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.expand_path("../../../spec_helper", __FILE__)
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, 'more', 'cat')
8
-
9
- describe "ExtendedDocument" do
10
-
11
- class WithDefaultValues < CouchRest::ExtendedDocument
12
- use_database TEST_SERVER.default_database
13
- property :preset, :type => 'Object', :default => {:right => 10, :top_align => false}
14
- property :set_by_proc, :default => Proc.new{Time.now}, :cast_as => 'Time'
15
- property :tags, :type => ['String'], :default => []
16
- property :read_only_with_default, :default => 'generic', :read_only => true
17
- property :default_false, :type => 'Boolean', :default => false
18
- property :name
19
- timestamps!
20
- end
21
-
22
- class WithCallBacks < CouchRest::ExtendedDocument
23
- include ::CouchRest::Validation
24
- use_database TEST_SERVER.default_database
25
- property :name
26
- property :run_before_validate
27
- property :run_after_validate
28
- property :run_before_save
29
- property :run_after_save
30
- property :run_before_create
31
- property :run_after_create
32
- property :run_before_update
33
- property :run_after_update
34
-
35
- before_validate do |object|
36
- object.run_before_validate = true
37
- end
38
- after_validate do |object|
39
- object.run_after_validate = true
40
- end
41
- before_save do |object|
42
- object.run_before_save = true
43
- end
44
- after_save do |object|
45
- object.run_after_save = true
46
- end
47
- before_create do |object|
48
- object.run_before_create = true
49
- end
50
- after_create do |object|
51
- object.run_after_create = true
52
- end
53
- before_update do |object|
54
- object.run_before_update = true
55
- end
56
- after_update do |object|
57
- object.run_after_update = true
58
- end
59
-
60
- property :run_one
61
- property :run_two
62
- property :run_three
63
-
64
- before_save :run_one_method, :run_two_method do |object|
65
- object.run_three = true
66
- end
67
- def run_one_method
68
- self.run_one = true
69
- end
70
- def run_two_method
71
- self.run_two = true
72
- end
73
-
74
- attr_accessor :run_it
75
- property :conditional_one
76
- property :conditional_two
77
-
78
- before_save :conditional_one_method, :conditional_two_method, :if => proc { self.run_it }
79
- def conditional_one_method
80
- self.conditional_one = true
81
- end
82
- def conditional_two_method
83
- self.conditional_two = true
84
- end
85
- end
86
-
87
- class WithTemplateAndUniqueID < CouchRest::ExtendedDocument
88
- use_database TEST_SERVER.default_database
89
- unique_id do |model|
90
- model['important-field']
91
- end
92
- property :preset, :default => 'value'
93
- property :has_no_default
94
- end
95
-
96
- class WithGetterAndSetterMethods < CouchRest::ExtendedDocument
97
- use_database TEST_SERVER.default_database
98
-
99
- property :other_arg
100
- def arg
101
- other_arg
102
- end
103
-
104
- def arg=(value)
105
- self.other_arg = "foo-#{value}"
106
- end
107
- end
108
-
109
- class WithAfterInitializeMethod < CouchRest::ExtendedDocument
110
- use_database TEST_SERVER.default_database
111
-
112
- property :some_value
113
-
114
- def after_initialize
115
- self.some_value ||= "value"
116
- end
117
-
118
- end
119
-
120
-
121
- before(:each) do
122
- @obj = WithDefaultValues.new
123
- end
124
-
125
- describe "instance database connection" do
126
- it "should use the default database" do
127
- @obj.database.name.should == 'couchrest-test'
128
- end
129
-
130
- it "should override the default db" do
131
- @obj.database = TEST_SERVER.database!('couchrest-extendedmodel-test')
132
- @obj.database.name.should == 'couchrest-extendedmodel-test'
133
- @obj.database.delete!
134
- end
135
- end
136
-
137
- describe "a new model" do
138
- it "should be a new document" do
139
- @obj = Basic.new
140
- @obj.rev.should be_nil
141
- @obj.should be_new
142
- @obj.should be_new_document
143
- @obj.should be_new_record
144
- end
145
-
146
- it "should not failed on a nil value in argument" do
147
- @obj = Basic.new(nil)
148
- @obj.should == { 'couchrest-type' => 'Basic' }
149
- end
150
- end
151
-
152
- describe "creating a new document" do
153
- it "should instantialize and save a document" do
154
- article = Article.create(:title => 'my test')
155
- article.title.should == 'my test'
156
- article.should_not be_new
157
- end
158
-
159
- it "should trigger the create callbacks" do
160
- doc = WithCallBacks.create(:name => 'my other test')
161
- doc.run_before_create.should be_true
162
- doc.run_after_create.should be_true
163
- doc.run_before_save.should be_true
164
- doc.run_after_save.should be_true
165
- end
166
- end
167
-
168
- describe "update attributes without saving" do
169
- before(:each) do
170
- a = Article.get "big-bad-danger" rescue nil
171
- a.destroy if a
172
- @art = Article.new(:title => "big bad danger")
173
- @art.save
174
- end
175
- it "should work for attribute= methods" do
176
- @art['title'].should == "big bad danger"
177
- @art.update_attributes_without_saving('date' => Time.now, :title => "super danger")
178
- @art['title'].should == "super danger"
179
- end
180
- it "should silently ignore _id" do
181
- @art.update_attributes_without_saving('_id' => 'foobar')
182
- @art['_id'].should_not == 'foobar'
183
- end
184
- it "should silently ignore _rev" do
185
- @art.update_attributes_without_saving('_rev' => 'foobar')
186
- @art['_rev'].should_not == 'foobar'
187
- end
188
- it "should silently ignore created_at" do
189
- @art.update_attributes_without_saving('created_at' => 'foobar')
190
- @art['created_at'].should_not == 'foobar'
191
- end
192
- it "should silently ignore updated_at" do
193
- @art.update_attributes_without_saving('updated_at' => 'foobar')
194
- @art['updated_at'].should_not == 'foobar'
195
- end
196
- it "should also work using attributes= alias" do
197
- @art.respond_to?(:attributes=).should be_true
198
- @art.attributes = {'date' => Time.now, :title => "something else"}
199
- @art['title'].should == "something else"
200
- end
201
-
202
- it "should flip out if an attribute= method is missing" do
203
- lambda {
204
- @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
205
- }.should raise_error
206
- end
207
-
208
- it "should not change other attributes if there is an error" do
209
- lambda {
210
- @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
211
- }.should raise_error
212
- @art['title'].should == "big bad danger"
213
- end
214
- end
215
-
216
- describe "update attributes" do
217
- before(:each) do
218
- a = Article.get "big-bad-danger" rescue nil
219
- a.destroy if a
220
- @art = Article.new(:title => "big bad danger")
221
- @art.save
222
- end
223
- it "should save" do
224
- @art['title'].should == "big bad danger"
225
- @art.update_attributes('date' => Time.now, :title => "super danger")
226
- loaded = Article.get(@art.id)
227
- loaded['title'].should == "super danger"
228
- end
229
- end
230
-
231
- describe "with default" do
232
- it "should have the default value set at initalization" do
233
- @obj.preset.should == {:right => 10, :top_align => false}
234
- end
235
-
236
- it "should have the default false value explicitly assigned" do
237
- @obj.default_false.should == false
238
- end
239
-
240
- it "should automatically call a proc default at initialization" do
241
- @obj.set_by_proc.should be_an_instance_of(Time)
242
- @obj.set_by_proc.should == @obj.set_by_proc
243
- @obj.set_by_proc.should < Time.now
244
- end
245
-
246
- it "should let you overwrite the default values" do
247
- obj = WithDefaultValues.new(:preset => 'test')
248
- obj.preset = 'test'
249
- end
250
-
251
- it "should work with a default empty array" do
252
- obj = WithDefaultValues.new(:tags => ['spec'])
253
- obj.tags.should == ['spec']
254
- end
255
-
256
- it "should set default value of read-only property" do
257
- obj = WithDefaultValues.new
258
- obj.read_only_with_default.should == 'generic'
259
- end
260
- end
261
-
262
- describe "a doc with template values (CR::Model spec)" do
263
- before(:all) do
264
- WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
265
- WithTemplateAndUniqueID.database.bulk_delete
266
- @tmpl = WithTemplateAndUniqueID.new
267
- @tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'important-field' => '1')
268
- end
269
- it "should have fields set when new" do
270
- @tmpl.preset.should == 'value'
271
- end
272
- it "shouldn't override explicitly set values" do
273
- @tmpl2.preset.should == 'not_value'
274
- end
275
- it "shouldn't override existing documents" do
276
- @tmpl2.save
277
- tmpl2_reloaded = WithTemplateAndUniqueID.get(@tmpl2.id)
278
- @tmpl2.preset.should == 'not_value'
279
- tmpl2_reloaded.preset.should == 'not_value'
280
- end
281
- end
282
-
283
- describe "getting a model" do
284
- before(:all) do
285
- @art = Article.new(:title => 'All About Getting')
286
- @art.save
287
- end
288
- it "should load and instantiate it" do
289
- foundart = Article.get @art.id
290
- foundart.title.should == "All About Getting"
291
- end
292
-
293
- it "should return nil if `get` is used and the document doesn't exist" do
294
- foundart = Article.get 'matt aimonetti'
295
- foundart.should be_nil
296
- end
297
-
298
- it "should raise an error if `get!` is used and the document doesn't exist" do
299
- lambda{foundart = Article.get!('matt aimonetti')}.should raise_error
300
- end
301
- end
302
-
303
- describe "getting a model with a subobjects array" do
304
- before(:all) do
305
- course_doc = {
306
- "title" => "Metaphysics 200",
307
- "questions" => [
308
- {
309
- "q" => "Carve the ___ of reality at the ___.",
310
- "a" => ["beast","joints"]
311
- },{
312
- "q" => "Who layed the smack down on Leibniz's Law?",
313
- "a" => "Willard Van Orman Quine"
314
- }
315
- ]
316
- }
317
- r = Course.database.save_doc course_doc
318
- @course = Course.get r['id']
319
- end
320
- it "should load the course" do
321
- @course.title.should == "Metaphysics 200"
322
- end
323
- it "should instantiate them as such" do
324
- @course["questions"][0].a[0].should == "beast"
325
- end
326
- end
327
-
328
- describe "finding all instances of a model" do
329
- before(:all) do
330
- WithTemplateAndUniqueID.design_doc_fresh = false
331
- WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
332
- WithTemplateAndUniqueID.database.bulk_delete
333
- WithTemplateAndUniqueID.new('important-field' => '1').save
334
- WithTemplateAndUniqueID.new('important-field' => '2').save
335
- WithTemplateAndUniqueID.new('important-field' => '3').save
336
- WithTemplateAndUniqueID.new('important-field' => '4').save
337
- end
338
- it "should make the design doc" do
339
- WithTemplateAndUniqueID.all
340
- d = WithTemplateAndUniqueID.design_doc
341
- d['views']['all']['map'].should include('WithTemplateAndUniqueID')
342
- end
343
- it "should find all" do
344
- rs = WithTemplateAndUniqueID.all
345
- rs.length.should == 4
346
- end
347
- end
348
-
349
- describe "counting all instances of a model" do
350
- before(:each) do
351
- @db = reset_test_db!
352
- WithTemplateAndUniqueID.design_doc_fresh = false
353
- end
354
-
355
- it ".count should return 0 if there are no docuemtns" do
356
- WithTemplateAndUniqueID.count.should == 0
357
- end
358
-
359
- it ".count should return the number of documents" do
360
- WithTemplateAndUniqueID.new('important-field' => '1').save
361
- WithTemplateAndUniqueID.new('important-field' => '2').save
362
- WithTemplateAndUniqueID.new('important-field' => '3').save
363
-
364
- WithTemplateAndUniqueID.count.should == 3
365
- end
366
- end
367
-
368
- describe "finding the first instance of a model" do
369
- before(:each) do
370
- @db = reset_test_db!
371
- WithTemplateAndUniqueID.design_doc_fresh = false
372
- WithTemplateAndUniqueID.new('important-field' => '1').save
373
- WithTemplateAndUniqueID.new('important-field' => '2').save
374
- WithTemplateAndUniqueID.new('important-field' => '3').save
375
- WithTemplateAndUniqueID.new('important-field' => '4').save
376
- end
377
- it "should make the design doc" do
378
- WithTemplateAndUniqueID.all
379
- d = WithTemplateAndUniqueID.design_doc
380
- d['views']['all']['map'].should include('WithTemplateAndUniqueID')
381
- end
382
- it "should find first" do
383
- rs = WithTemplateAndUniqueID.first
384
- rs['important-field'].should == "1"
385
- end
386
- it "should return nil if no instances are found" do
387
- WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
388
- WithTemplateAndUniqueID.first.should be_nil
389
- end
390
- end
391
-
392
- describe "getting a model with a subobject field" do
393
- before(:all) do
394
- course_doc = {
395
- "title" => "Metaphysics 410",
396
- "professor" => {
397
- "name" => ["Mark", "Hinchliff"]
398
- },
399
- "ends_at" => "2008/12/19 13:00:00 +0800"
400
- }
401
- r = Course.database.save_doc course_doc
402
- @course = Course.get r['id']
403
- end
404
- it "should load the course" do
405
- @course["professor"]["name"][1].should == "Hinchliff"
406
- end
407
- it "should instantiate the professor as a person" do
408
- @course['professor'].last_name.should == "Hinchliff"
409
- end
410
- it "should instantiate the ends_at as a Time" do
411
- @course['ends_at'].should == Time.parse("2008/12/19 13:00:00 +0800")
412
- end
413
- end
414
-
415
- describe "timestamping" do
416
- before(:each) do
417
- oldart = Article.get "saving-this" rescue nil
418
- oldart.destroy if oldart
419
- @art = Article.new(:title => "Saving this")
420
- @art.save
421
- end
422
-
423
- it "should define the updated_at and created_at getters and set the values" do
424
- @obj.save
425
- obj = WithDefaultValues.get(@obj.id)
426
- obj.should be_an_instance_of(WithDefaultValues)
427
- obj.created_at.should be_an_instance_of(Time)
428
- obj.updated_at.should be_an_instance_of(Time)
429
- obj.created_at.to_s.should == @obj.updated_at.to_s
430
- end
431
-
432
- it "should not change created_at on update" do
433
- 2.times do
434
- lambda do
435
- @art.save
436
- end.should_not change(@art, :created_at)
437
- end
438
- end
439
-
440
- it "should set the time on create" do
441
- (Time.now - @art.created_at).should < 2
442
- foundart = Article.get @art.id
443
- foundart.created_at.should == foundart.updated_at
444
- end
445
- it "should set the time on update" do
446
- @art.save
447
- @art.created_at.should < @art.updated_at
448
- end
449
- end
450
-
451
- describe "basic saving and retrieving" do
452
- it "should work fine" do
453
- @obj.name = "should be easily saved and retrieved"
454
- @obj.save
455
- saved_obj = WithDefaultValues.get(@obj.id)
456
- saved_obj.should_not be_nil
457
- end
458
-
459
- it "should parse the Time attributes automatically" do
460
- @obj.name = "should parse the Time attributes automatically"
461
- @obj.set_by_proc.should be_an_instance_of(Time)
462
- @obj.save
463
- @obj.set_by_proc.should be_an_instance_of(Time)
464
- saved_obj = WithDefaultValues.get(@obj.id)
465
- saved_obj.set_by_proc.should be_an_instance_of(Time)
466
- end
467
- end
468
-
469
- describe "saving a model" do
470
- before(:all) do
471
- @sobj = Basic.new
472
- @sobj.save.should == true
473
- end
474
-
475
- it "should save the doc" do
476
- doc = Basic.get(@sobj.id)
477
- doc['_id'].should == @sobj.id
478
- end
479
-
480
- it "should be set for resaving" do
481
- rev = @obj.rev
482
- @sobj['another-key'] = "some value"
483
- @sobj.save
484
- @sobj.rev.should_not == rev
485
- end
486
-
487
- it "should set the id" do
488
- @sobj.id.should be_an_instance_of(String)
489
- end
490
-
491
- it "should set the type" do
492
- @sobj['couchrest-type'].should == 'Basic'
493
- end
494
-
495
- describe "save!" do
496
-
497
- before(:each) do
498
- @sobj = Card.new(:first_name => "Marcos", :last_name => "Tapajós")
499
- end
500
-
501
- it "should return true if save the document" do
502
- @sobj.save!.should == true
503
- end
504
-
505
- it "should raise error if don't save the document" do
506
- @sobj.first_name = nil
507
- lambda { @sobj.save!.should == true }.should raise_error(RuntimeError)
508
- end
509
-
510
- end
511
-
512
-
513
- end
514
-
515
- describe "saving a model with a unique_id configured" do
516
- before(:each) do
517
- @art = Article.new
518
- @old = Article.database.get('this-is-the-title') rescue nil
519
- Article.database.delete_doc(@old) if @old
520
- end
521
-
522
- it "should be a new document" do
523
- @art.should be_new
524
- @art.title.should be_nil
525
- end
526
-
527
- it "should require the title" do
528
- lambda{@art.save}.should raise_error
529
- @art.title = 'This is the title'
530
- @art.save.should == true
531
- end
532
-
533
- it "should not change the slug on update" do
534
- @art.title = 'This is the title'
535
- @art.save.should == true
536
- @art.title = 'new title'
537
- @art.save.should == true
538
- @art.slug.should == 'this-is-the-title'
539
- end
540
-
541
- it "should raise an error when the slug is taken" do
542
- @art.title = 'This is the title'
543
- @art.save.should == true
544
- @art2 = Article.new(:title => 'This is the title!')
545
- lambda{@art2.save}.should raise_error
546
- end
547
-
548
- it "should set the slug" do
549
- @art.title = 'This is the title'
550
- @art.save.should == true
551
- @art.slug.should == 'this-is-the-title'
552
- end
553
-
554
- it "should set the id" do
555
- @art.title = 'This is the title'
556
- @art.save.should == true
557
- @art.id.should == 'this-is-the-title'
558
- end
559
- end
560
-
561
- describe "saving a model with a unique_id lambda" do
562
- before(:each) do
563
- @templated = WithTemplateAndUniqueID.new
564
- @old = WithTemplateAndUniqueID.get('very-important') rescue nil
565
- @old.destroy if @old
566
- end
567
-
568
- it "should require the field" do
569
- lambda{@templated.save}.should raise_error
570
- @templated['important-field'] = 'very-important'
571
- @templated.save.should == true
572
- end
573
-
574
- it "should save with the id" do
575
- @templated['important-field'] = 'very-important'
576
- @templated.save.should == true
577
- t = WithTemplateAndUniqueID.get('very-important')
578
- t.should == @templated
579
- end
580
-
581
- it "should not change the id on update" do
582
- @templated['important-field'] = 'very-important'
583
- @templated.save.should == true
584
- @templated['important-field'] = 'not-important'
585
- @templated.save.should == true
586
- t = WithTemplateAndUniqueID.get('very-important')
587
- t.should == @templated
588
- end
589
-
590
- it "should raise an error when the id is taken" do
591
- @templated['important-field'] = 'very-important'
592
- @templated.save.should == true
593
- lambda{WithTemplateAndUniqueID.new('important-field' => 'very-important').save}.should raise_error
594
- end
595
-
596
- it "should set the id" do
597
- @templated['important-field'] = 'very-important'
598
- @templated.save.should == true
599
- @templated.id.should == 'very-important'
600
- end
601
- end
602
-
603
- describe "destroying an instance" do
604
- before(:each) do
605
- @dobj = Basic.new
606
- @dobj.save.should == true
607
- end
608
- it "should return true" do
609
- result = @dobj.destroy
610
- result.should == true
611
- end
612
- it "should be resavable" do
613
- @dobj.destroy
614
- @dobj.rev.should be_nil
615
- @dobj.id.should be_nil
616
- @dobj.save.should == true
617
- end
618
- it "should make it go away" do
619
- @dobj.destroy
620
- lambda{Basic.get!(@dobj.id)}.should raise_error
621
- end
622
- end
623
-
624
-
625
- describe "callbacks" do
626
-
627
- before(:each) do
628
- @doc = WithCallBacks.new
629
- end
630
-
631
-
632
- describe "validate" do
633
- it "should run before_validate before validating" do
634
- @doc.run_before_validate.should be_nil
635
- @doc.should be_valid
636
- @doc.run_before_validate.should be_true
637
- end
638
- it "should run after_validate after validating" do
639
- @doc.run_after_validate.should be_nil
640
- @doc.should be_valid
641
- @doc.run_after_validate.should be_true
642
- end
643
- end
644
- describe "save" do
645
- it "should run the after filter after saving" do
646
- @doc.run_after_save.should be_nil
647
- @doc.save.should be_true
648
- @doc.run_after_save.should be_true
649
- end
650
- it "should run the grouped callbacks before saving" do
651
- @doc.run_one.should be_nil
652
- @doc.run_two.should be_nil
653
- @doc.run_three.should be_nil
654
- @doc.save.should be_true
655
- @doc.run_one.should be_true
656
- @doc.run_two.should be_true
657
- @doc.run_three.should be_true
658
- end
659
- it "should not run conditional callbacks" do
660
- @doc.run_it = false
661
- @doc.save.should be_true
662
- @doc.conditional_one.should be_nil
663
- @doc.conditional_two.should be_nil
664
- end
665
- it "should run conditional callbacks" do
666
- @doc.run_it = true
667
- @doc.save.should be_true
668
- @doc.conditional_one.should be_true
669
- @doc.conditional_two.should be_true
670
- end
671
- end
672
- describe "create" do
673
- it "should run the before save filter when creating" do
674
- @doc.run_before_save.should be_nil
675
- @doc.create.should_not be_nil
676
- @doc.run_before_save.should be_true
677
- end
678
- it "should run the before create filter" do
679
- @doc.run_before_create.should be_nil
680
- @doc.create.should_not be_nil
681
- @doc.create
682
- @doc.run_before_create.should be_true
683
- end
684
- it "should run the after create filter" do
685
- @doc.run_after_create.should be_nil
686
- @doc.create.should_not be_nil
687
- @doc.create
688
- @doc.run_after_create.should be_true
689
- end
690
- end
691
- describe "update" do
692
-
693
- before(:each) do
694
- @doc.save
695
- end
696
- it "should run the before update filter when updating an existing document" do
697
- @doc.run_before_update.should be_nil
698
- @doc.update
699
- @doc.run_before_update.should be_true
700
- end
701
- it "should run the after update filter when updating an existing document" do
702
- @doc.run_after_update.should be_nil
703
- @doc.update
704
- @doc.run_after_update.should be_true
705
- end
706
- it "should run the before update filter when saving an existing document" do
707
- @doc.run_before_update.should be_nil
708
- @doc.save
709
- @doc.run_before_update.should be_true
710
- end
711
-
712
- end
713
- end
714
-
715
- describe "getter and setter methods" do
716
- it "should try to call the arg= method before setting :arg in the hash" do
717
- @doc = WithGetterAndSetterMethods.new(:arg => "foo")
718
- @doc['arg'].should be_nil
719
- @doc[:arg].should be_nil
720
- @doc.other_arg.should == "foo-foo"
721
- end
722
- end
723
-
724
- describe "initialization" do
725
- it "should call after_initialize method if available" do
726
- @doc = WithAfterInitializeMethod.new
727
- @doc['some_value'].should eql('value')
728
- end
729
- end
730
-
731
- describe "recursive validation on an extended document" do
732
- before :each do
733
- reset_test_db!
734
- @cat = Cat.new(:name => 'Sockington')
735
- end
736
-
737
- it "should not save if a nested casted model is invalid" do
738
- @cat.favorite_toy = CatToy.new
739
- @cat.should_not be_valid
740
- @cat.save.should be_false
741
- lambda{@cat.save!}.should raise_error
742
- end
743
-
744
- it "should save when nested casted model is valid" do
745
- @cat.favorite_toy = CatToy.new(:name => 'Squeaky')
746
- @cat.should be_valid
747
- @cat.save.should be_true
748
- lambda{@cat.save!}.should_not raise_error
749
- end
750
-
751
- it "should not save when nested collection contains an invalid casted model" do
752
- @cat.toys = [CatToy.new(:name => 'Feather'), CatToy.new]
753
- @cat.should_not be_valid
754
- @cat.save.should be_false
755
- lambda{@cat.save!}.should raise_error
756
- end
757
-
758
- it "should save when nested collection contains valid casted models" do
759
- @cat.toys = [CatToy.new(:name => 'feather'), CatToy.new(:name => 'ball-o-twine')]
760
- @cat.should be_valid
761
- @cat.save.should be_true
762
- lambda{@cat.save!}.should_not raise_error
763
- end
764
-
765
- it "should not fail if the nested casted model doesn't have validation" do
766
- Cat.property :trainer, :cast_as => 'Person'
767
- Cat.validates_presence_of :name
768
- cat = Cat.new(:name => 'Mr Bigglesworth')
769
- cat.trainer = Person.new
770
- cat.trainer.validatable?.should be_false
771
- cat.should be_valid
772
- cat.save.should be_true
773
- end
774
- end
775
-
776
- describe "searching the contents of an extended document" do
777
- before :each do
778
- @db = reset_test_db!
779
-
780
- names = ["Fuzzy", "Whiskers", "Mr Bigglesworth", "Sockington", "Smitty", "Sammy", "Samson", "Simon"]
781
- names.each { |name| Cat.create(:name => name) }
782
-
783
- search_function = { 'defaults' => {'store' => 'no', 'index' => 'analyzed_no_norms'},
784
- 'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); return ret; }" }
785
- @db.save_doc({'_id' => '_design/search', 'fulltext' => {'cats' => search_function}})
786
- end
787
-
788
- it "should be able to paginate through a large set of search results" do
789
- if couchdb_lucene_available?
790
- names = []
791
- Cat.paginated_each(:design_doc => "search", :view_name => "cats",
792
- :q => 'name:S*', :search => true, :include_docs => true, :per_page => 3) do |cat|
793
- cat.should_not be_nil
794
- names << cat.name
795
- end
796
-
797
- names.size.should == 5
798
- names.should include('Sockington')
799
- names.should include('Smitty')
800
- names.should include('Sammy')
801
- names.should include('Samson')
802
- names.should include('Simon')
803
- end
804
- end
805
- end
806
-
807
- end