couchrest 0.12.4 → 0.23
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -8
- data/Rakefile +11 -2
- data/examples/model/example.rb +19 -13
- data/lib/couchrest.rb +70 -11
- data/lib/couchrest/core/database.rb +121 -62
- data/lib/couchrest/core/design.rb +7 -17
- data/lib/couchrest/core/document.rb +42 -30
- data/lib/couchrest/core/response.rb +16 -0
- data/lib/couchrest/core/server.rb +47 -10
- data/lib/couchrest/helper/upgrade.rb +51 -0
- data/lib/couchrest/mixins.rb +4 -0
- data/lib/couchrest/mixins/attachments.rb +31 -0
- data/lib/couchrest/mixins/callbacks.rb +483 -0
- data/lib/couchrest/mixins/class_proxy.rb +108 -0
- data/lib/couchrest/mixins/design_doc.rb +90 -0
- data/lib/couchrest/mixins/document_queries.rb +44 -0
- data/lib/couchrest/mixins/extended_attachments.rb +68 -0
- data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
- data/lib/couchrest/mixins/properties.rb +129 -0
- data/lib/couchrest/mixins/validation.rb +242 -0
- data/lib/couchrest/mixins/views.rb +169 -0
- data/lib/couchrest/monkeypatches.rb +81 -6
- data/lib/couchrest/more/casted_model.rb +28 -0
- data/lib/couchrest/more/extended_document.rb +215 -0
- data/lib/couchrest/more/property.rb +40 -0
- data/lib/couchrest/support/blank.rb +42 -0
- data/lib/couchrest/support/class.rb +176 -0
- data/lib/couchrest/validation/auto_validate.rb +163 -0
- data/lib/couchrest/validation/contextual_validators.rb +78 -0
- data/lib/couchrest/validation/validation_errors.rb +118 -0
- data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
- data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
- data/lib/couchrest/validation/validators/format_validator.rb +117 -0
- data/lib/couchrest/validation/validators/formats/email.rb +66 -0
- data/lib/couchrest/validation/validators/formats/url.rb +43 -0
- data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
- data/lib/couchrest/validation/validators/length_validator.rb +134 -0
- data/lib/couchrest/validation/validators/method_validator.rb +89 -0
- data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
- data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
- data/spec/couchrest/core/database_spec.rb +189 -124
- data/spec/couchrest/core/design_spec.rb +13 -6
- data/spec/couchrest/core/document_spec.rb +231 -177
- data/spec/couchrest/core/server_spec.rb +35 -0
- data/spec/couchrest/helpers/pager_spec.rb +1 -1
- data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
- data/spec/couchrest/more/casted_model_spec.rb +98 -0
- data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
- data/spec/couchrest/more/extended_doc_spec.rb +509 -0
- data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
- data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
- data/spec/couchrest/more/property_spec.rb +136 -0
- data/spec/fixtures/more/article.rb +34 -0
- data/spec/fixtures/more/card.rb +20 -0
- data/spec/fixtures/more/course.rb +14 -0
- data/spec/fixtures/more/event.rb +6 -0
- data/spec/fixtures/more/invoice.rb +17 -0
- data/spec/fixtures/more/person.rb +8 -0
- data/spec/fixtures/more/question.rb +6 -0
- data/spec/fixtures/more/service.rb +12 -0
- data/spec/spec_helper.rb +13 -7
- metadata +58 -4
- data/lib/couchrest/core/model.rb +0 -613
- 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.
|
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.
|
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.
|
140
|
+
@r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
|
133
141
|
@docid = "http://example.com/stuff.cgi?things=and%20stuff"
|
134
|
-
@db.
|
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
|
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
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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.
|
282
|
+
@db.save_doc(doc)
|
283
|
+
@doc = @db.get("mydocwithattachment")
|
264
284
|
end
|
265
285
|
it "should save and be indicated" do
|
266
|
-
doc
|
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(
|
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.
|
288
|
-
doc
|
306
|
+
@db.save_doc(doc)
|
307
|
+
doc['_rev'].should_not be_nil
|
289
308
|
doc['field'] << 'another value'
|
290
|
-
@db.
|
309
|
+
@db.save_doc(doc)["ok"].should be_true
|
291
310
|
end
|
292
311
|
|
293
312
|
it 'should be there' do
|
294
|
-
|
295
|
-
attachment
|
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.
|
337
|
+
@db.save_doc(@doc)
|
338
|
+
@doc = @db.get("mydocwithattachment")
|
318
339
|
end
|
319
340
|
it "should save and be indicated" do
|
320
|
-
doc
|
321
|
-
doc['_attachments']['
|
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(
|
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(
|
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.
|
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
|
-
|
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.
|
362
|
-
lambda{@db.
|
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.
|
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.
|
379
|
-
lambda{@db.
|
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.
|
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.
|
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.
|
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.
|
404
|
-
lambda {@db.
|
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.
|
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.
|
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.
|
427
|
-
@db.
|
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.
|
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.
|
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.
|
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.
|
499
|
+
@r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
|
458
500
|
@docid = "http://example.com/stuff.cgi?things=and%20stuff"
|
459
|
-
@db.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
545
|
+
@db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
|
504
546
|
end
|
505
547
|
it "should fail without a rev" do
|
506
|
-
lambda{@db.
|
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.
|
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.
|
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.
|
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.
|
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
|