couchrest 0.12.4 → 0.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README.md +33 -8
  2. data/Rakefile +11 -2
  3. data/examples/model/example.rb +19 -13
  4. data/lib/couchrest.rb +70 -11
  5. data/lib/couchrest/core/database.rb +121 -62
  6. data/lib/couchrest/core/design.rb +7 -17
  7. data/lib/couchrest/core/document.rb +42 -30
  8. data/lib/couchrest/core/response.rb +16 -0
  9. data/lib/couchrest/core/server.rb +47 -10
  10. data/lib/couchrest/helper/upgrade.rb +51 -0
  11. data/lib/couchrest/mixins.rb +4 -0
  12. data/lib/couchrest/mixins/attachments.rb +31 -0
  13. data/lib/couchrest/mixins/callbacks.rb +483 -0
  14. data/lib/couchrest/mixins/class_proxy.rb +108 -0
  15. data/lib/couchrest/mixins/design_doc.rb +90 -0
  16. data/lib/couchrest/mixins/document_queries.rb +44 -0
  17. data/lib/couchrest/mixins/extended_attachments.rb +68 -0
  18. data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
  19. data/lib/couchrest/mixins/properties.rb +129 -0
  20. data/lib/couchrest/mixins/validation.rb +242 -0
  21. data/lib/couchrest/mixins/views.rb +169 -0
  22. data/lib/couchrest/monkeypatches.rb +81 -6
  23. data/lib/couchrest/more/casted_model.rb +28 -0
  24. data/lib/couchrest/more/extended_document.rb +215 -0
  25. data/lib/couchrest/more/property.rb +40 -0
  26. data/lib/couchrest/support/blank.rb +42 -0
  27. data/lib/couchrest/support/class.rb +176 -0
  28. data/lib/couchrest/validation/auto_validate.rb +163 -0
  29. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  30. data/lib/couchrest/validation/validation_errors.rb +118 -0
  31. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  32. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  33. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  34. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  35. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  36. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  37. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  38. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  39. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  40. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  41. data/spec/couchrest/core/database_spec.rb +189 -124
  42. data/spec/couchrest/core/design_spec.rb +13 -6
  43. data/spec/couchrest/core/document_spec.rb +231 -177
  44. data/spec/couchrest/core/server_spec.rb +35 -0
  45. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  46. data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
  47. data/spec/couchrest/more/casted_model_spec.rb +98 -0
  48. data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
  49. data/spec/couchrest/more/extended_doc_spec.rb +509 -0
  50. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  51. data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
  52. data/spec/couchrest/more/property_spec.rb +136 -0
  53. data/spec/fixtures/more/article.rb +34 -0
  54. data/spec/fixtures/more/card.rb +20 -0
  55. data/spec/fixtures/more/course.rb +14 -0
  56. data/spec/fixtures/more/event.rb +6 -0
  57. data/spec/fixtures/more/invoice.rb +17 -0
  58. data/spec/fixtures/more/person.rb +8 -0
  59. data/spec/fixtures/more/question.rb +6 -0
  60. data/spec/fixtures/more/service.rb +12 -0
  61. data/spec/spec_helper.rb +13 -7
  62. metadata +58 -4
  63. data/lib/couchrest/core/model.rb +0 -613
  64. data/spec/couchrest/core/model_spec.rb +0 -855
@@ -0,0 +1,89 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ # @since 0.9
31
+ class MethodValidator < GenericValidator
32
+
33
+ def initialize(field_name, options={})
34
+ super
35
+ @field_name, @options = field_name, options.clone
36
+ @options[:method] = @field_name unless @options.has_key?(:method)
37
+ end
38
+
39
+ def call(target)
40
+ result, message = target.send(@options[:method])
41
+ add_error(target, message, field_name) unless result
42
+ result
43
+ end
44
+
45
+ def ==(other)
46
+ @options[:method] == other.instance_variable_get(:@options)[:method] && super
47
+ end
48
+ end # class MethodValidator
49
+
50
+ module ValidatesWithMethod
51
+
52
+ ##
53
+ # Validate using the given method. The method given needs to return:
54
+ # [result::<Boolean>, Error Message::<String>]
55
+ #
56
+ # @example [Usage]
57
+ #
58
+ # class Page
59
+ #
60
+ # property :zip_code, String
61
+ #
62
+ # validates_with_method :in_the_right_location?
63
+ #
64
+ # def in_the_right_location?
65
+ # if @zip_code == "94301"
66
+ # return true
67
+ # else
68
+ # return [false, "You're in the wrong zip code"]
69
+ # end
70
+ # end
71
+ #
72
+ # # A call to valid? will return false and
73
+ # # populate the object's errors with "You're in the
74
+ # # wrong zip code" unless zip_code == "94301"
75
+ #
76
+ # # You can also specify field:
77
+ #
78
+ # validates_with_method :zip_code, :in_the_right_location?
79
+ #
80
+ # # it will add returned error message to :zip_code field
81
+ #
82
+ def validates_with_method(*fields)
83
+ opts = opts_from_validator_args(fields)
84
+ add_validator_to_context(opts, fields, CouchRest::Validation::MethodValidator)
85
+ end
86
+
87
+ end # module ValidatesWithMethod
88
+ end # module Validation
89
+ end # module CouchRest
@@ -0,0 +1,104 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ # @since 0.9
31
+ class NumericValidator < GenericValidator
32
+
33
+ def initialize(field_name, options={})
34
+ super
35
+ @field_name, @options = field_name, options
36
+ @options[:integer_only] = false unless @options.has_key?(:integer_only)
37
+ end
38
+
39
+ def call(target)
40
+ value = target.send(field_name)
41
+ return true if @options[:allow_nil] && value.nil?
42
+
43
+ value = value.kind_of?(Float) ? value.to_s('F') : value.to_s
44
+
45
+ error_message = @options[:message]
46
+ precision = @options[:precision]
47
+ scale = @options[:scale]
48
+
49
+ if @options[:integer_only]
50
+ return true if value =~ /\A[+-]?\d+\z/
51
+ error_message ||= ValidationErrors.default_error_message(:not_an_integer, field_name)
52
+ else
53
+ # FIXME: if precision and scale are not specified, can we assume that it is an integer?
54
+ # probably not, as floating point numbers don't have hard
55
+ # defined scale. the scale floats with the length of the
56
+ # integral and precision. Ie. if precision = 10 and integral
57
+ # portion of the number is 9834 (4 digits), the max scale will
58
+ # be 6 (10 - 4). But if the integral length is 1, max scale
59
+ # will be (10 - 1) = 9, so 1.234567890.
60
+ if precision && scale
61
+ #handles both Float when it has scale specified and BigDecimal
62
+ if precision > scale && scale > 0
63
+ return true if value =~ /\A[+-]?(?:\d{1,#{precision - scale}}|\d{0,#{precision - scale}}\.\d{1,#{scale}})\z/
64
+ elsif precision > scale && scale == 0
65
+ return true if value =~ /\A[+-]?(?:\d{1,#{precision}}(?:\.0)?)\z/
66
+ elsif precision == scale
67
+ return true if value =~ /\A[+-]?(?:0(?:\.\d{1,#{scale}})?)\z/
68
+ else
69
+ raise ArgumentError, "Invalid precision #{precision.inspect} and scale #{scale.inspect} for #{field_name} (value: #{value.inspect} #{value.class})"
70
+ end
71
+ elsif precision && scale.nil?
72
+ # for floats, if scale is not set
73
+
74
+ #total number of digits is less or equal precision
75
+ return true if value.gsub(/[^\d]/, '').length <= precision
76
+
77
+ #number of digits before decimal == precision, and the number is x.0. same as scale = 0
78
+ return true if value =~ /\A[+-]?(?:\d{1,#{precision}}(?:\.0)?)\z/
79
+ else
80
+ return true if value =~ /\A[+-]?(?:\d+|\d*\.\d+)\z/
81
+ end
82
+ error_message ||= ValidationErrors.default_error_message(:not_a_number, field_name)
83
+ end
84
+
85
+ add_error(target, error_message, field_name)
86
+
87
+ # TODO: check the gt, gte, lt, lte, and eq options
88
+
89
+ return false
90
+ end
91
+ end # class NumericValidator
92
+
93
+ module ValidatesIsNumber
94
+
95
+ # Validate whether a field is numeric
96
+ #
97
+ def validates_is_number(*fields)
98
+ opts = opts_from_validator_args(fields)
99
+ add_validator_to_context(opts, fields, CouchRest::Validation::NumericValidator)
100
+ end
101
+
102
+ end # module ValidatesIsNumber
103
+ end # module Validation
104
+ end # module CouchRest
@@ -0,0 +1,109 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ # @since 0.9
31
+ class RequiredFieldValidator < GenericValidator
32
+
33
+ def initialize(field_name, options={})
34
+ super
35
+ @field_name, @options = field_name, options
36
+ end
37
+
38
+ def call(target)
39
+ value = target.validation_property_value(field_name)
40
+ property = target.validation_property(field_name)
41
+ return true if present?(value, property)
42
+
43
+ error_message = @options[:message] || default_error(property)
44
+ add_error(target, error_message, field_name)
45
+
46
+ false
47
+ end
48
+
49
+ protected
50
+
51
+ # Boolean property types are considered present if non-nil.
52
+ # Other property types are considered present if non-blank.
53
+ # Non-properties are considered present if non-blank.
54
+ def present?(value, property)
55
+ boolean_type?(property) ? !value.nil? : !value.blank?
56
+ end
57
+
58
+ def default_error(property)
59
+ actual = boolean_type?(property) ? :nil : :blank
60
+ ValidationErrors.default_error_message(actual, field_name)
61
+ end
62
+
63
+ # Is +property+ a boolean property?
64
+ #
65
+ # Returns true for Boolean, ParanoidBoolean, TrueClass, etc. properties.
66
+ # Returns false for other property types.
67
+ # Returns false for non-properties.
68
+ def boolean_type?(property)
69
+ property ? property.type == TrueClass : false
70
+ end
71
+
72
+ end # class RequiredFieldValidator
73
+
74
+ module ValidatesPresent
75
+
76
+ ##
77
+ # Validates that the specified attribute is present.
78
+ #
79
+ # For most property types "being present" is the same as being "not
80
+ # blank" as determined by the attribute's #blank? method. However, in
81
+ # the case of Boolean, "being present" means not nil; i.e. true or
82
+ # false.
83
+ #
84
+ # @note
85
+ # dm-core's support lib adds the blank? method to many classes,
86
+ # @see lib/dm-core/support/blank.rb (dm-core) for more information.
87
+ #
88
+ # @example [Usage]
89
+ #
90
+ # class Page
91
+ #
92
+ # property :required_attribute, String
93
+ # property :another_required, String
94
+ # property :yet_again, String
95
+ #
96
+ # validates_present :required_attribute
97
+ # validates_present :another_required, :yet_again
98
+ #
99
+ # # a call to valid? will return false unless
100
+ # # all three attributes are !blank?
101
+ # end
102
+ def validates_present(*fields)
103
+ opts = opts_from_validator_args(fields)
104
+ add_validator_to_context(opts, fields, CouchRest::Validation::RequiredFieldValidator)
105
+ end
106
+
107
+ end # module ValidatesPresent
108
+ end # module Validation
109
+ end # module CouchRest
@@ -7,7 +7,15 @@ describe CouchRest::Database do
7
7
  @db.delete! rescue nil
8
8
  @db = @cr.create_db(TESTDB) rescue nil
9
9
  end
10
-
10
+
11
+ describe "database name including slash" do
12
+ it "should escape the name in the URI" do
13
+ db = @cr.database("foo/bar")
14
+ db.name.should == "foo/bar"
15
+ db.uri.should == "#{COUCHHOST}/foo%2Fbar"
16
+ end
17
+ end
18
+
11
19
  describe "map query with _temp_view in Javascript" do
12
20
  before(:each) do
13
21
  @db.bulk_save([
@@ -61,7 +69,7 @@ describe CouchRest::Database do
61
69
  emit(doc.word,null);
62
70
  }
63
71
  }'}}
64
- @db.save({
72
+ @db.save_doc({
65
73
  "_id" => "_design/test",
66
74
  :views => @view
67
75
  })
@@ -80,7 +88,7 @@ describe CouchRest::Database do
80
88
 
81
89
  describe "select from an existing view" do
82
90
  before(:each) do
83
- r = @db.save({
91
+ r = @db.save_doc({
84
92
  "_id" => "_design/first",
85
93
  :views => {
86
94
  :test => {
@@ -129,9 +137,9 @@ describe CouchRest::Database do
129
137
 
130
138
  describe "GET (document by id) when the doc exists" do
131
139
  before(:each) do
132
- @r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
140
+ @r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
133
141
  @docid = "http://example.com/stuff.cgi?things=and%20stuff"
134
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
142
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
135
143
  end
136
144
  it "should get the document" do
137
145
  doc = @db.get(@r['id'])
@@ -149,8 +157,8 @@ describe CouchRest::Database do
149
157
  {"mild" => "yet local"},
150
158
  {"another" => ["set","of","keys"]}
151
159
  ])
152
- rs['new_revs'].each do |r|
153
- @db.get(r['id'])
160
+ rs.each do |r|
161
+ @db.get(r['id']).rev.should == r["rev"]
154
162
  end
155
163
  end
156
164
 
@@ -170,29 +178,13 @@ describe CouchRest::Database do
170
178
  {"_id" => "twoB", "mild" => "yet local"},
171
179
  {"another" => ["set","of","keys"]}
172
180
  ])
173
- rs['new_revs'].each do |r|
174
- @db.get(r['id'])
181
+ rs.each do |r|
182
+ @db.get(r['id']).rev.should == r["rev"]
175
183
  end
176
184
  end
177
-
178
- it "in the case of an id conflict should not insert anything" do
179
- @r = @db.save({'lemons' => 'from texas', 'and' => 'how', "_id" => "oneB"})
180
-
181
- lambda do
182
- rs = @db.bulk_save([
183
- {"_id" => "oneB", "wild" => "and random"},
184
- {"_id" => "twoB", "mild" => "yet local"},
185
- {"another" => ["set","of","keys"]}
186
- ])
187
- end.should raise_error(RestClient::RequestFailed)
188
-
189
- lambda do
190
- @db.get('twoB')
191
- end.should raise_error(RestClient::ResourceNotFound)
192
- end
193
185
 
194
186
  it "should empty the bulk save cache if no documents are given" do
195
- @db.save({"_id" => "bulk_cache_1", "val" => "test"}, true)
187
+ @db.save_doc({"_id" => "bulk_cache_1", "val" => "test"}, true)
196
188
  lambda do
197
189
  @db.get('bulk_cache_1')
198
190
  end.should raise_error(RestClient::ResourceNotFound)
@@ -201,7 +193,7 @@ describe CouchRest::Database do
201
193
  end
202
194
 
203
195
  it "should raise an error that is useful for recovery" do
204
- @r = @db.save({"_id" => "taken", "field" => "stuff"})
196
+ @r = @db.save_doc({"_id" => "taken", "field" => "stuff"})
205
197
  begin
206
198
  rs = @db.bulk_save([
207
199
  {"_id" => "taken", "wild" => "and random"},
@@ -220,17 +212,43 @@ describe CouchRest::Database do
220
212
  @db.documents["total_rows"].should == 0
221
213
  end
222
214
  it "should create the document and return the id" do
223
- r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
215
+ r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
224
216
  r2 = @db.get(r['id'])
225
217
  r2["lemons"].should == "from texas"
226
218
  end
227
219
  it "should use PUT with UUIDs" do
228
220
  CouchRest.should_receive(:put).and_return({"ok" => true, "id" => "100", "rev" => "55"})
229
- r = @db.save({'just' => ['another document']})
221
+ r = @db.save_doc({'just' => ['another document']})
230
222
  end
231
223
 
232
224
  end
233
-
225
+
226
+ describe "fetch_attachment" do
227
+ before do
228
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
229
+ @doc = {
230
+ "_id" => "mydocwithattachment",
231
+ "field" => ["some value"],
232
+ "_attachments" => {
233
+ "test.html" => {
234
+ "type" => "text/html",
235
+ "data" => @attach
236
+ }
237
+ }
238
+ }
239
+ @db.save_doc(@doc)
240
+ end
241
+
242
+ # Depreacated
243
+ # it "should get the attachment with the doc's _id" do
244
+ # @db.fetch_attachment("mydocwithattachment", "test.html").should == @attach
245
+ # end
246
+
247
+ it "should get the attachment with the doc itself" do
248
+ @db.fetch_attachment(@db.get('mydocwithattachment'), 'test.html').should == @attach
249
+ end
250
+ end
251
+
234
252
  describe "PUT attachment from file" do
235
253
  before(:each) do
236
254
  filename = FIXTURE_PATH + '/attachments/couchdb.png'
@@ -242,7 +260,8 @@ describe CouchRest::Database do
242
260
  it "should save the attachment to a new doc" do
243
261
  r = @db.put_attachment({'_id' => 'attach-this'}, 'couchdb.png', image = @file.read, {:content_type => 'image/png'})
244
262
  r['ok'].should == true
245
- attachment = @db.fetch_attachment("attach-this","couchdb.png")
263
+ doc = @db.get("attach-this")
264
+ attachment = @db.fetch_attachment(doc,"couchdb.png")
246
265
  attachment.should == image
247
266
  end
248
267
  end
@@ -250,7 +269,7 @@ describe CouchRest::Database do
250
269
  describe "PUT document with attachment" do
251
270
  before(:each) do
252
271
  @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
253
- @doc = {
272
+ doc = {
254
273
  "_id" => "mydocwithattachment",
255
274
  "field" => ["some value"],
256
275
  "_attachments" => {
@@ -260,14 +279,14 @@ describe CouchRest::Database do
260
279
  }
261
280
  }
262
281
  }
263
- @db.save(@doc)
282
+ @db.save_doc(doc)
283
+ @doc = @db.get("mydocwithattachment")
264
284
  end
265
285
  it "should save and be indicated" do
266
- doc = @db.get("mydocwithattachment")
267
- doc['_attachments']['test.html']['length'].should == @attach.length
286
+ @doc['_attachments']['test.html']['length'].should == @attach.length
268
287
  end
269
288
  it "should be there" do
270
- attachment = @db.fetch_attachment("mydocwithattachment","test.html")
289
+ attachment = @db.fetch_attachment(@doc,"test.html")
271
290
  attachment.should == @attach
272
291
  end
273
292
  end
@@ -284,15 +303,16 @@ describe CouchRest::Database do
284
303
  }
285
304
  }
286
305
  }
287
- @db.save(doc)
288
- doc = @db.get('mydocwithattachment')
306
+ @db.save_doc(doc)
307
+ doc['_rev'].should_not be_nil
289
308
  doc['field'] << 'another value'
290
- @db.save(doc)
309
+ @db.save_doc(doc)["ok"].should be_true
291
310
  end
292
311
 
293
312
  it 'should be there' do
294
- attachment = @db.fetch_attachment('mydocwithattachment', 'test.html')
295
- attachment.should == @attach
313
+ doc = @db.get('mydocwithattachment')
314
+ attachment = @db.fetch_attachment(doc, 'test.html')
315
+ Base64.decode64(attachment).should == @attach
296
316
  end
297
317
  end
298
318
 
@@ -314,22 +334,43 @@ describe CouchRest::Database do
314
334
  }
315
335
  }
316
336
  }
317
- @db.save(@doc)
337
+ @db.save_doc(@doc)
338
+ @doc = @db.get("mydocwithattachment")
318
339
  end
319
340
  it "should save and be indicated" do
320
- doc = @db.get("mydocwithattachment")
321
- doc['_attachments']['test.html']['length'].should == @attach.length
322
- doc['_attachments']['other.html']['length'].should == @attach2.length
341
+ @doc['_attachments']['test.html']['length'].should == @attach.length
342
+ @doc['_attachments']['other.html']['length'].should == @attach2.length
323
343
  end
324
344
  it "should be there" do
325
- attachment = @db.fetch_attachment("mydocwithattachment","test.html")
345
+ attachment = @db.fetch_attachment(@doc,"test.html")
326
346
  attachment.should == @attach
327
347
  end
328
348
  it "should be there" do
329
- attachment = @db.fetch_attachment("mydocwithattachment","other.html")
349
+ attachment = @db.fetch_attachment(@doc,"other.html")
330
350
  attachment.should == @attach2
331
351
  end
332
352
  end
353
+
354
+ describe "DELETE an attachment directly from the database" do
355
+ before(:each) do
356
+ doc = {
357
+ '_id' => 'mydocwithattachment',
358
+ '_attachments' => {
359
+ 'test.html' => {
360
+ 'type' => 'text/html',
361
+ 'data' => "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
362
+ }
363
+ }
364
+ }
365
+ @db.save_doc(doc)
366
+ @doc = @db.get('mydocwithattachment')
367
+ end
368
+ it "should delete the attachment" do
369
+ lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
370
+ @db.delete_attachment(@doc, "test.html")
371
+ lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound)
372
+ end
373
+ end
333
374
 
334
375
  describe "POST document with attachment (with funky name)" do
335
376
  before(:each) do
@@ -343,14 +384,15 @@ describe CouchRest::Database do
343
384
  }
344
385
  }
345
386
  }
346
- @docid = @db.save(@doc)['id']
387
+ @docid = @db.save_doc(@doc)['id']
347
388
  end
348
389
  it "should save and be indicated" do
349
390
  doc = @db.get(@docid)
350
391
  doc['_attachments']['http://example.com/stuff.cgi?things=and%20stuff']['length'].should == @attach.length
351
392
  end
352
393
  it "should be there" do
353
- attachment = @db.fetch_attachment(@docid,"http://example.com/stuff.cgi?things=and%20stuff")
394
+ doc = @db.get(@docid)
395
+ attachment = @db.fetch_attachment(doc,"http://example.com/stuff.cgi?things=and%20stuff")
354
396
  attachment.should == @attach
355
397
  end
356
398
  end
@@ -358,15 +400,15 @@ describe CouchRest::Database do
358
400
  describe "PUT (new document with url id)" do
359
401
  it "should create the document" do
360
402
  @docid = "http://example.com/stuff.cgi?things=and%20stuff"
361
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
362
- lambda{@db.save({'_id' => @docid})}.should raise_error(RestClient::Request::RequestFailed)
403
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
404
+ lambda{@db.save_doc({'_id' => @docid})}.should raise_error(RestClient::Request::RequestFailed)
363
405
  @db.get(@docid)['will-exist'].should == 'here'
364
406
  end
365
407
  end
366
408
 
367
409
  describe "PUT (new document with id)" do
368
410
  it "should start without the document" do
369
- # r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
411
+ # r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
370
412
  @db.documents['rows'].each do |doc|
371
413
  doc['id'].should_not == 'my-doc'
372
414
  end
@@ -375,17 +417,17 @@ describe CouchRest::Database do
375
417
  # or instead make it return something with a fancy <=> method
376
418
  end
377
419
  it "should create the document" do
378
- @db.save({'_id' => 'my-doc', 'will-exist' => 'here'})
379
- lambda{@db.save({'_id' => 'my-doc'})}.should raise_error(RestClient::Request::RequestFailed)
420
+ @db.save_doc({'_id' => 'my-doc', 'will-exist' => 'here'})
421
+ lambda{@db.save_doc({'_id' => 'my-doc'})}.should raise_error(RestClient::Request::RequestFailed)
380
422
  end
381
423
  end
382
424
 
383
425
  describe "PUT (existing document with rev)" do
384
426
  before(:each) do
385
- @db.save({'_id' => 'my-doc', 'will-exist' => 'here'})
427
+ @db.save_doc({'_id' => 'my-doc', 'will-exist' => 'here'})
386
428
  @doc = @db.get('my-doc')
387
429
  @docid = "http://example.com/stuff.cgi?things=and%20stuff"
388
- @db.save({'_id' => @docid, 'now' => 'save'})
430
+ @db.save_doc({'_id' => @docid, 'now' => 'save'})
389
431
  end
390
432
  it "should start with the document" do
391
433
  @doc['will-exist'].should == 'here'
@@ -394,18 +436,18 @@ describe CouchRest::Database do
394
436
  it "should save with url id" do
395
437
  doc = @db.get(@docid)
396
438
  doc['yaml'] = ['json', 'word.']
397
- @db.save doc
439
+ @db.save_doc doc
398
440
  @db.get(@docid)['yaml'].should == ['json', 'word.']
399
441
  end
400
442
  it "should fail to resave without the rev" do
401
443
  @doc['them-keys'] = 'huge'
402
444
  @doc['_rev'] = 'wrong'
403
- # @db.save(@doc)
404
- lambda {@db.save(@doc)}.should raise_error
445
+ # @db.save_doc(@doc)
446
+ lambda {@db.save_doc(@doc)}.should raise_error
405
447
  end
406
448
  it "should update the document" do
407
449
  @doc['them-keys'] = 'huge'
408
- @db.save(@doc)
450
+ @db.save_doc(@doc)
409
451
  now = @db.get('my-doc')
410
452
  now['them-keys'].should == 'huge'
411
453
  end
@@ -414,7 +456,7 @@ describe CouchRest::Database do
414
456
  describe "cached bulk save" do
415
457
  it "stores documents in a database-specific cache" do
416
458
  td = {"_id" => "btd1", "val" => "test"}
417
- @db.save(td, true)
459
+ @db.save_doc(td, true)
418
460
  @db.instance_variable_get("@bulk_save_cache").should == [td]
419
461
 
420
462
  end
@@ -423,8 +465,8 @@ describe CouchRest::Database do
423
465
  @db.bulk_save_cache_limit = 3
424
466
  td1 = {"_id" => "td1", "val" => true}
425
467
  td2 = {"_id" => "td2", "val" => 4}
426
- @db.save(td1, true)
427
- @db.save(td2, true)
468
+ @db.save_doc(td1, true)
469
+ @db.save_doc(td2, true)
428
470
  lambda do
429
471
  @db.get(td1["_id"])
430
472
  end.should raise_error(RestClient::ResourceNotFound)
@@ -432,7 +474,7 @@ describe CouchRest::Database do
432
474
  @db.get(td2["_id"])
433
475
  end.should raise_error(RestClient::ResourceNotFound)
434
476
  td3 = {"_id" => "td3", "val" => "foo"}
435
- @db.save(td3, true)
477
+ @db.save_doc(td3, true)
436
478
  @db.get(td1["_id"])["val"].should == td1["val"]
437
479
  @db.get(td2["_id"])["val"].should == td2["val"]
438
480
  @db.get(td3["_id"])["val"].should == td3["val"]
@@ -442,11 +484,11 @@ describe CouchRest::Database do
442
484
  td1 = {"_id" => "blah", "val" => true}
443
485
  td2 = {"_id" => "steve", "val" => 3}
444
486
  @db.bulk_save_cache_limit = 50
445
- @db.save(td1, true)
487
+ @db.save_doc(td1, true)
446
488
  lambda do
447
489
  @db.get(td1["_id"])
448
490
  end.should raise_error(RestClient::ResourceNotFound)
449
- @db.save(td2)
491
+ @db.save_doc(td2)
450
492
  @db.get(td1["_id"])["val"].should == td1["val"]
451
493
  @db.get(td2["_id"])["val"].should == td2["val"]
452
494
  end
@@ -454,27 +496,27 @@ describe CouchRest::Database do
454
496
 
455
497
  describe "DELETE existing document" do
456
498
  before(:each) do
457
- @r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
499
+ @r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
458
500
  @docid = "http://example.com/stuff.cgi?things=and%20stuff"
459
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
501
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
460
502
  end
461
503
  it "should work" do
462
504
  doc = @db.get(@r['id'])
463
505
  doc['and'].should == 'spain'
464
- @db.delete doc
506
+ @db.delete_doc doc
465
507
  lambda{@db.get @r['id']}.should raise_error
466
508
  end
467
509
  it "should work with uri id" do
468
510
  doc = @db.get(@docid)
469
- @db.delete doc
511
+ @db.delete_doc doc
470
512
  lambda{@db.get @docid}.should raise_error
471
513
  end
472
514
  it "should fail without an _id" do
473
- lambda{@db.delete({"not"=>"a real doc"})}.should raise_error(ArgumentError)
515
+ lambda{@db.delete_doc({"not"=>"a real doc"})}.should raise_error(ArgumentError)
474
516
  end
475
517
  it "should defer actual deletion when using bulk save" do
476
518
  doc = @db.get(@docid)
477
- @db.delete doc, true
519
+ @db.delete_doc doc, true
478
520
  lambda{@db.get @docid}.should_not raise_error
479
521
  @db.bulk_save
480
522
  lambda{@db.get @docid}.should raise_error
@@ -484,13 +526,13 @@ describe CouchRest::Database do
484
526
 
485
527
  describe "COPY existing document" do
486
528
  before :each do
487
- @r = @db.save({'artist' => 'Zappa', 'title' => 'Muffin Man'})
529
+ @r = @db.save_doc({'artist' => 'Zappa', 'title' => 'Muffin Man'})
488
530
  @docid = 'tracks/zappa/muffin-man'
489
531
  @doc = @db.get(@r['id'])
490
532
  end
491
533
  describe "to a new location" do
492
534
  it "should work" do
493
- @db.copy @doc, @docid
535
+ @db.copy_doc @doc, @docid
494
536
  newdoc = @db.get(@docid)
495
537
  newdoc['artist'].should == 'Zappa'
496
538
  end
@@ -500,73 +542,30 @@ describe CouchRest::Database do
500
542
  end
501
543
  describe "to an existing location" do
502
544
  before :each do
503
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
545
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
504
546
  end
505
547
  it "should fail without a rev" do
506
- lambda{@db.copy @doc, @docid}.should raise_error(RestClient::RequestFailed)
548
+ lambda{@db.copy_doc @doc, @docid}.should raise_error(RestClient::RequestFailed)
507
549
  end
508
550
  it "should succeed with a rev" do
509
551
  @to_be_overwritten = @db.get(@docid)
510
- @db.copy @doc, "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
552
+ @db.copy_doc @doc, "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
511
553
  newdoc = @db.get(@docid)
512
554
  newdoc['artist'].should == 'Zappa'
513
555
  end
514
556
  it "should succeed given the doc to overwrite" do
515
557
  @to_be_overwritten = @db.get(@docid)
516
- @db.copy @doc, @to_be_overwritten
558
+ @db.copy_doc @doc, @to_be_overwritten
517
559
  newdoc = @db.get(@docid)
518
560
  newdoc['artist'].should == 'Zappa'
519
561
  end
520
562
  end
521
563
  end
522
564
 
523
- describe "MOVE existing document" do
524
- before :each do
525
- @r = @db.save({'artist' => 'Zappa', 'title' => 'Muffin Man'})
526
- @docid = 'tracks/zappa/muffin-man'
527
- @doc = @db.get(@r['id'])
528
- end
529
- describe "to a new location" do
530
- it "should work" do
531
- @db.move @doc, @docid
532
- newdoc = @db.get(@docid)
533
- newdoc['artist'].should == 'Zappa'
534
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
535
- end
536
- it "should fail without an _id or _rev" do
537
- lambda{@db.move({"not"=>"a real doc"})}.should raise_error(ArgumentError)
538
- lambda{@db.move({"_id"=>"not a real doc"})}.should raise_error(ArgumentError)
539
- end
540
- end
541
- describe "to an existing location" do
542
- before :each do
543
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
544
- end
545
- it "should fail without a rev" do
546
- lambda{@db.move @doc, @docid}.should raise_error(RestClient::RequestFailed)
547
- lambda{@db.get(@r['id'])}.should_not raise_error
548
- end
549
- it "should succeed with a rev" do
550
- @to_be_overwritten = @db.get(@docid)
551
- @db.move @doc, "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
552
- newdoc = @db.get(@docid)
553
- newdoc['artist'].should == 'Zappa'
554
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
555
- end
556
- it "should succeed given the doc to overwrite" do
557
- @to_be_overwritten = @db.get(@docid)
558
- @db.move @doc, @to_be_overwritten
559
- newdoc = @db.get(@docid)
560
- newdoc['artist'].should == 'Zappa'
561
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
562
- end
563
- end
564
- end
565
-
566
565
 
567
566
  it "should list documents" do
568
567
  5.times do
569
- @db.save({'another' => 'doc', 'will-exist' => 'anywhere'})
568
+ @db.save_doc({'another' => 'doc', 'will-exist' => 'anywhere'})
570
569
  end
571
570
  ds = @db.documents
572
571
  ds['rows'].should be_an_instance_of(Array)
@@ -577,7 +576,7 @@ describe CouchRest::Database do
577
576
  describe "documents / _all_docs" do
578
577
  before(:each) do
579
578
  9.times do |i|
580
- @db.save({'_id' => "doc#{i}",'another' => 'doc', 'will-exist' => 'here'})
579
+ @db.save_doc({'_id' => "doc#{i}",'another' => 'doc', 'will-exist' => 'here'})
581
580
  end
582
581
  end
583
582
  it "should list documents with keys and such" do
@@ -624,6 +623,72 @@ describe CouchRest::Database do
624
623
  @cr.databases.should_not include('couchrest-test')
625
624
  end
626
625
  end
626
+
627
+ describe "replicating a database" do
628
+ before do
629
+ @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
630
+ @other_db = @cr.database 'couchrest-test-replication'
631
+ @other_db.delete! rescue nil
632
+ @other_db = @cr.create_db 'couchrest-test-replication'
633
+ end
634
+
635
+ describe "via pulling" do
636
+ before do
637
+ @other_db.replicate_from @db
638
+ end
639
+
640
+ it "contains the document from the original database" do
641
+ doc = @other_db.get('test_doc')
642
+ doc['some-value'].should == 'foo'
643
+ end
644
+ end
645
+
646
+ describe "via pushing" do
647
+ before do
648
+ @db.replicate_to @other_db
649
+ end
650
+
651
+ it "copies the document to the other database" do
652
+ doc = @other_db.get('test_doc')
653
+ doc['some-value'].should == 'foo'
654
+ end
655
+ end
656
+ end
657
+
658
+ describe "creating a database" do
659
+ before(:each) do
660
+ @db = @cr.database('couchrest-test-db_to_create')
661
+ @db.delete! if @cr.databases.include?('couchrest-test-db_to_create')
662
+ end
663
+
664
+ it "should just work fine" do
665
+ @cr.databases.should_not include('couchrest-test-db_to_create')
666
+ @db.create!
667
+ @cr.databases.should include('couchrest-test-db_to_create')
668
+ end
669
+ end
670
+
671
+ describe "recreating a database" do
672
+ before(:each) do
673
+ @db = @cr.database('couchrest-test-db_to_create')
674
+ @db2 = @cr.database('couchrest-test-db_to_recreate')
675
+ @cr.databases.include?(@db.name) ? nil : @db.create!
676
+ @cr.databases.include?(@db2.name) ? @db2.delete! : nil
677
+ end
678
+
679
+ it "should drop and recreate a database" do
680
+ @cr.databases.should include(@db.name)
681
+ @db.recreate!
682
+ @cr.databases.should include(@db.name)
683
+ end
684
+
685
+ it "should recreate a db even tho it doesn't exist" do
686
+ @cr.databases.should_not include(@db2.name)
687
+ @db2.recreate!
688
+ @cr.databases.should include(@db2.name)
689
+ end
690
+
691
+ end
627
692
 
628
693
 
629
- end
694
+ end