riak-client 0.7.1 → 0.8.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.
- data/Gemfile +13 -0
- data/Gemfile.lock +33 -0
- data/Rakefile +3 -2
- data/lib/riak.rb +7 -2
- data/lib/riak/bucket.rb +45 -14
- data/lib/riak/cache_store.rb +38 -40
- data/lib/riak/client.rb +1 -1
- data/lib/riak/i18n.rb +2 -2
- data/lib/riak/link.rb +2 -2
- data/lib/riak/locale/en.yml +16 -16
- data/lib/riak/map_reduce.rb +7 -4
- data/lib/riak/robject.rb +72 -20
- data/lib/riak/util/escape.rb +2 -2
- data/spec/integration/riak/cache_store_spec.rb +36 -14
- data/spec/riak/bucket_spec.rb +24 -6
- data/spec/riak/client_spec.rb +5 -5
- data/spec/riak/escape_spec.rb +1 -0
- data/spec/riak/map_reduce_spec.rb +29 -0
- data/spec/riak/object_spec.rb +112 -27
- metadata +38 -11
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (2.3.8)
|
5
|
+
curb (0.7.8)
|
6
|
+
diff-lcs (1.1.2)
|
7
|
+
fakeweb (1.3.0)
|
8
|
+
i18n (0.4.1)
|
9
|
+
rack (1.2.1)
|
10
|
+
rake (0.8.7)
|
11
|
+
rspec (2.0.0.beta.20)
|
12
|
+
rspec-core (= 2.0.0.beta.20)
|
13
|
+
rspec-expectations (= 2.0.0.beta.20)
|
14
|
+
rspec-mocks (= 2.0.0.beta.20)
|
15
|
+
rspec-core (2.0.0.beta.20)
|
16
|
+
rspec-expectations (2.0.0.beta.20)
|
17
|
+
diff-lcs (>= 1.1.2)
|
18
|
+
rspec-mocks (2.0.0.beta.20)
|
19
|
+
yajl-ruby (0.7.7)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
activesupport (~> 2.3.5)
|
26
|
+
bundler
|
27
|
+
curb (>= 0.6)
|
28
|
+
fakeweb (>= 1.2)
|
29
|
+
i18n
|
30
|
+
rack (>= 1.0)
|
31
|
+
rake
|
32
|
+
rspec (~> 2.0.0.beta.18)
|
33
|
+
yajl-ruby
|
data/Rakefile
CHANGED
@@ -9,11 +9,12 @@ gemspec = Gem::Specification.new do |gem|
|
|
9
9
|
gem.email = "seancribbs@gmail.com"
|
10
10
|
gem.homepage = "http://seancribbs.github.com/ripple"
|
11
11
|
gem.authors = ["Sean Cribbs"]
|
12
|
-
gem.add_development_dependency "rspec", "~>2.0.0.beta.
|
12
|
+
gem.add_development_dependency "rspec", "~>2.0.0.beta.11"
|
13
13
|
gem.add_development_dependency "fakeweb", ">=1.2"
|
14
14
|
gem.add_development_dependency "rack", ">=1.0"
|
15
15
|
gem.add_development_dependency "curb", ">=0.6"
|
16
16
|
gem.add_dependency "activesupport", ">= 2.3.5"
|
17
|
+
gem.add_dependency "i18n", "~>0.4.0"
|
17
18
|
gem.requirements << "`gem install curb` for better HTTP performance"
|
18
19
|
|
19
20
|
files = FileList["**/*"]
|
@@ -48,7 +49,7 @@ end
|
|
48
49
|
|
49
50
|
desc %{Release the gem to RubyGems.org}
|
50
51
|
task :release => :gem do
|
51
|
-
"gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
52
|
+
system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
52
53
|
end
|
53
54
|
|
54
55
|
require 'rspec/core'
|
data/lib/riak.rb
CHANGED
@@ -15,8 +15,10 @@ $KCODE = "UTF8" if RUBY_VERSION < "1.9"
|
|
15
15
|
|
16
16
|
require 'active_support/all'
|
17
17
|
require 'active_support/json'
|
18
|
+
require 'active_support/version'
|
18
19
|
require 'base64'
|
19
20
|
require 'uri'
|
21
|
+
require 'cgi'
|
20
22
|
require 'net/http'
|
21
23
|
require 'yaml'
|
22
24
|
require 'riak/i18n'
|
@@ -32,8 +34,11 @@ module Riak
|
|
32
34
|
autoload :RObject, "riak/robject"
|
33
35
|
autoload :MapReduce, "riak/map_reduce"
|
34
36
|
|
35
|
-
# Cache store
|
36
|
-
|
37
|
+
# Cache store - only supports Rails 3 style
|
38
|
+
if ActiveSupport::VERSION::STRING >= "3.0.0"
|
39
|
+
autoload :CacheStore, "riak/cache_store"
|
40
|
+
::ActiveSupport::Cache.autoload :RiakStore, "riak/cache_store"
|
41
|
+
end
|
37
42
|
|
38
43
|
# Exceptions
|
39
44
|
autoload :FailedRequest, "riak/failed_request"
|
data/lib/riak/bucket.rb
CHANGED
@@ -26,10 +26,6 @@ module Riak
|
|
26
26
|
# @return [String] the bucket name
|
27
27
|
attr_reader :name
|
28
28
|
|
29
|
-
# @return [Hash] Internal Riak bucket properties.
|
30
|
-
attr_reader :props
|
31
|
-
alias_attribute :properties, :props
|
32
|
-
|
33
29
|
# Create a Riak bucket manually.
|
34
30
|
# @param [Client] client the {Riak::Client} for this bucket
|
35
31
|
# @param [String] name the name of the bucket
|
@@ -49,7 +45,7 @@ module Riak
|
|
49
45
|
raise Riak::InvalidResponse.new({"content-type" => ["application/json"]}, response[:headers], t("loading_bucket", :name => name))
|
50
46
|
end
|
51
47
|
payload = ActiveSupport::JSON.decode(response[:body])
|
52
|
-
@keys = payload['keys'].map {|k|
|
48
|
+
@keys = payload['keys'].map {|k| CGI.unescape(k) } if payload['keys']
|
53
49
|
@props = payload['props'] if payload['props']
|
54
50
|
self
|
55
51
|
end
|
@@ -66,26 +62,48 @@ module Riak
|
|
66
62
|
if block_given?
|
67
63
|
@client.http.get(200, @client.prefix, escape(name), {:props => false, :keys => 'stream'}, {}) do |chunk|
|
68
64
|
obj = ActiveSupport::JSON.decode(chunk) rescue {}
|
69
|
-
yield obj['keys'].map {|k|
|
65
|
+
yield obj['keys'].map {|k| CGI.unescape(k) } if obj['keys']
|
70
66
|
end
|
71
67
|
elsif @keys.nil? || options[:reload]
|
72
|
-
response = @client.http.get(200, @client.prefix, escape(name), {:props => false}, {})
|
68
|
+
response = @client.http.get(200, @client.prefix, escape(name), {:props => false, :keys => true}, {})
|
73
69
|
load(response)
|
74
70
|
end
|
75
71
|
@keys
|
76
72
|
end
|
77
73
|
|
74
|
+
|
78
75
|
# Sets internal properties on the bucket
|
79
76
|
# Note: this results in a request to the Riak server!
|
80
77
|
# @param [Hash] properties new properties for the bucket
|
81
|
-
# @
|
82
|
-
# @
|
78
|
+
# @option properties [Fixnum] :n_val (3) The N value (replication factor)
|
79
|
+
# @option properties [true,false] :allow_mult (false) Whether to permit object siblings
|
80
|
+
# @option properties [true,false] :last_write_wins (false) Whether to ignore vclocks
|
81
|
+
# @option properties [Array<Hash>] :precommit ([]) precommit hooks
|
82
|
+
# @option properties [Array<Hash>] :postcommit ([])postcommit hooks
|
83
|
+
# @option properties [Fixnum,String] :r ("quorum") read quorum (numeric or
|
84
|
+
# symbolic)
|
85
|
+
# @option properties [Fixnum,String] :w ("quorum") write quorum (numeric or
|
86
|
+
# symbolic)
|
87
|
+
# @option properties [Fixnum,String] :dw ("quorum") durable write quorum
|
88
|
+
# (numeric or symbolic)
|
89
|
+
# @option properties [Fixnum,String] :rw ("quorum") delete quorum (numeric or
|
90
|
+
# symbolic)
|
91
|
+
# @return [Hash] the merged bucket properties
|
92
|
+
# @raise [FailedRequest] if the new properties were not accepted by the Riakserver
|
93
|
+
# @see #n_value, #allow_mult, #r, #w, #dw, #rw
|
83
94
|
def props=(properties)
|
84
95
|
raise ArgumentError, t("hash_type", :hash => properties.inspect) unless Hash === properties
|
85
96
|
body = {'props' => properties}.to_json
|
86
97
|
@client.http.put(204, @client.prefix, escape(name), body, {"Content-Type" => "application/json"})
|
87
|
-
@props
|
98
|
+
@props.merge!(properties)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [Hash] Internal Riak bucket properties.
|
102
|
+
# @see #props=
|
103
|
+
def props
|
104
|
+
@props
|
88
105
|
end
|
106
|
+
alias_attribute :properties, :props
|
89
107
|
|
90
108
|
# Retrieve an object from within the bucket.
|
91
109
|
# @param [String] key the key of the object to retrieve
|
@@ -168,9 +186,22 @@ module Riak
|
|
168
186
|
value
|
169
187
|
end
|
170
188
|
|
171
|
-
|
172
|
-
|
173
|
-
|
189
|
+
[:r,:w,:dw,:rw].each do |q|
|
190
|
+
class_eval <<-CODE
|
191
|
+
def #{q}
|
192
|
+
props["#{q}"]
|
193
|
+
end
|
194
|
+
|
195
|
+
def #{q}=(value)
|
196
|
+
self.props = {"#{q}" => value}
|
197
|
+
value
|
198
|
+
end
|
199
|
+
CODE
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [String] a representation suitable for IRB and debugging output
|
203
|
+
def inspect
|
204
|
+
"#<Riak::Bucket #{client.http.path(client.prefix, escape(name)).to_s}#{" keys=[#{keys.join(',')}]" if defined?(@keys)}>"
|
205
|
+
end
|
174
206
|
end
|
175
207
|
end
|
176
|
-
end
|
data/lib/riak/cache_store.rb
CHANGED
@@ -19,63 +19,61 @@ module Riak
|
|
19
19
|
def initialize(options = {})
|
20
20
|
@bucket_name = options.delete(:bucket) || '_cache'
|
21
21
|
@n_value = options.delete(:n_value) || 2
|
22
|
-
@r =
|
23
|
-
@w =
|
24
|
-
@dw =
|
25
|
-
@rw =
|
22
|
+
@r = options.delete(:r) || 1
|
23
|
+
@w = options.delete(:w) || 1
|
24
|
+
@dw = options.delete(:dw) || 0
|
25
|
+
@rw = options.delete(:rw) || "quorum"
|
26
26
|
@client = Riak::Client.new(options)
|
27
|
+
set_bucket_defaults
|
27
28
|
end
|
28
29
|
|
29
30
|
def bucket
|
30
|
-
@bucket ||= @client.bucket(@bucket_name, :keys => false)
|
31
|
-
begin
|
32
|
-
b.n_value = @n_value unless b.n_value == @n_value
|
33
|
-
rescue
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def write(key, value, options={})
|
39
|
-
super do
|
40
|
-
object = bucket.get_or_new(key, :r => @r)
|
41
|
-
object.content_type = 'application/yaml'
|
42
|
-
object.data = value
|
43
|
-
object.store(:r => @r, :w => @w, :dw => @dw)
|
44
|
-
end
|
31
|
+
@bucket ||= @client.bucket(@bucket_name, :keys => false)
|
45
32
|
end
|
46
33
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
nil
|
34
|
+
def delete_matched(matcher, options={})
|
35
|
+
instrument(:delete_matched, matcher) do
|
36
|
+
bucket.keys do |keys|
|
37
|
+
keys.grep(matcher).each do |k|
|
38
|
+
bucket.delete(k)
|
39
|
+
end
|
54
40
|
end
|
55
41
|
end
|
56
42
|
end
|
57
43
|
|
58
|
-
|
59
|
-
|
60
|
-
|
44
|
+
protected
|
45
|
+
def set_bucket_defaults
|
46
|
+
begin
|
47
|
+
new_values = {}
|
48
|
+
new_values['n_val'] = @n_value unless bucket.n_value == @n_value
|
49
|
+
new_values['r'] = @r unless bucket.r == @r
|
50
|
+
new_values['w'] = @w unless bucket.w == @w
|
51
|
+
new_values['dw'] = @dw unless bucket.dw == @dw
|
52
|
+
new_values['rw'] = @rw unless bucket.rw == @rw
|
53
|
+
bucket.props = new_values unless new_values.empty?
|
54
|
+
rescue
|
61
55
|
end
|
62
56
|
end
|
63
57
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
58
|
+
def write_entry(key, value, options={})
|
59
|
+
object = bucket.get_or_new(key)
|
60
|
+
object.content_type = 'application/yaml'
|
61
|
+
object.data = value
|
62
|
+
object.store
|
72
63
|
end
|
73
64
|
|
74
|
-
def
|
75
|
-
|
76
|
-
bucket.
|
65
|
+
def read_entry(key, options={})
|
66
|
+
begin
|
67
|
+
bucket.get(key).data
|
68
|
+
rescue Riak::FailedRequest => fr
|
69
|
+
raise fr unless fr.code == 404
|
70
|
+
nil
|
77
71
|
end
|
78
72
|
end
|
73
|
+
|
74
|
+
def delete_entry(key, options={})
|
75
|
+
bucket.delete(key)
|
76
|
+
end
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
data/lib/riak/client.rb
CHANGED
@@ -117,7 +117,7 @@ module Riak
|
|
117
117
|
# @return [Bucket] the requested bucket
|
118
118
|
def bucket(name, options={})
|
119
119
|
options.assert_valid_keys(:keys, :props)
|
120
|
-
response = http.get(200, prefix, escape(name), options, {})
|
120
|
+
response = http.get(200, prefix, escape(name), {:keys => false}.merge(options), {})
|
121
121
|
Bucket.new(self, name).load(response)
|
122
122
|
end
|
123
123
|
alias :[] :bucket
|
data/lib/riak/i18n.rb
CHANGED
@@ -11,9 +11,9 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
|
14
|
+
if ActiveSupport::VERSION::STRING >= "3.0"
|
15
15
|
require 'active_support/i18n'
|
16
|
-
|
16
|
+
else
|
17
17
|
require 'i18n' # support ActiveSupport < 3
|
18
18
|
end
|
19
19
|
|
data/lib/riak/link.rb
CHANGED
@@ -39,12 +39,12 @@ module Riak
|
|
39
39
|
|
40
40
|
# @return [String] bucket_name, if the Link url is a known Riak link ("/riak/<bucket>/<key>")
|
41
41
|
def bucket
|
42
|
-
|
42
|
+
CGI.unescape($1) if url =~ %r{^/[^/]+/([^/]+)/?}
|
43
43
|
end
|
44
44
|
|
45
45
|
# @return [String] key, if the Link url is a known Riak link ("/riak/<bucket>/<key>")
|
46
46
|
def key
|
47
|
-
|
47
|
+
CGI.unescape($1) if url =~ %r{^/[^/]+/[^/]+/([^/]+)/?}
|
48
48
|
end
|
49
49
|
|
50
50
|
def inspect; to_s; end
|
data/lib/riak/locale/en.yml
CHANGED
@@ -13,25 +13,25 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
en:
|
15
15
|
riak:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
failed_request: "Expected {
|
20
|
-
hash_type: "invalid argument {
|
21
|
-
path_and_body_required: "You must supply both a resource path and a body."
|
22
|
-
request_body_type: "Request body must be a string or IO."
|
23
|
-
resource_path_short: "Resource path too short"
|
24
|
-
missing_host_and_port: "You must specify a host and port, or use the defaults of 127.0.0.1:8098"
|
25
|
-
invalid_client_id: "Invalid client ID, must be a string or between 0 and {{max_id}}"
|
16
|
+
bucket_link_conversion: "Can't convert a bucket link to a walk spec"
|
17
|
+
client_type: "invalid argument %{client} is not a Riak::Client"
|
18
|
+
content_type_undefined: "content_type is not defined!"
|
19
|
+
failed_request: "Expected %{expected} from Riak but received %{code}. %{body}"
|
20
|
+
hash_type: "invalid argument %{hash} is not a Hash"
|
26
21
|
hostname_invalid: "host must be a valid hostname"
|
27
|
-
port_invalid: "port must be an integer between 0 and 65535"
|
28
22
|
install_curb: "curb library not found! Please `gem install curb` for better performance."
|
29
|
-
|
23
|
+
invalid_client_id: "Invalid client ID, must be a string or between 0 and %{max_id}"
|
24
|
+
invalid_function_value: "invalid value for function: %{value}"
|
30
25
|
invalid_phase_type: "type must be :map, :reduce, or :link"
|
26
|
+
loading_bucket: "while loading bucket '%{name}'"
|
27
|
+
missing_host_and_port: "You must specify a host and port, or use the defaults of 127.0.0.1:8098"
|
31
28
|
module_function_pair_required: "function must have two elements when an array"
|
29
|
+
path_and_body_required: "You must supply both a resource path and a body."
|
30
|
+
port_invalid: "port must be an integer between 0 and 65535"
|
31
|
+
request_body_type: "Request body must be a string or IO."
|
32
|
+
resource_path_short: "Resource path too short"
|
32
33
|
stored_function_invalid: "function must have :bucket and :key when a hash"
|
34
|
+
string_type: "invalid_argument %{string} is not a String"
|
35
|
+
too_few_arguments: "too few arguments: %{params}"
|
33
36
|
walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
|
34
|
-
|
35
|
-
content_type_undefined: "content_type is not defined!"
|
36
|
-
too_few_arguments: "too few arguments: {{params}}"
|
37
|
-
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|
37
|
+
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|
data/lib/riak/map_reduce.rb
CHANGED
@@ -17,6 +17,8 @@ module Riak
|
|
17
17
|
# Class for invoking map-reduce jobs using the HTTP interface.
|
18
18
|
class MapReduce
|
19
19
|
include Util::Translation
|
20
|
+
include Util::Escape
|
21
|
+
|
20
22
|
# @return [Array<[bucket,key]>,String] The bucket/keys for input to the job, or the bucket (all keys).
|
21
23
|
# @see #add
|
22
24
|
attr_accessor :inputs
|
@@ -58,16 +60,17 @@ module Riak
|
|
58
60
|
p = params.first
|
59
61
|
case p
|
60
62
|
when Bucket
|
61
|
-
@inputs = p.name
|
63
|
+
@inputs = escape(p.name)
|
62
64
|
when RObject
|
63
|
-
@inputs << [p.bucket.name, p.key]
|
65
|
+
@inputs << [escape(p.bucket.name), escape(p.key)]
|
64
66
|
when String
|
65
|
-
@inputs = p
|
67
|
+
@inputs = escape(p)
|
66
68
|
end
|
67
69
|
when 2..3
|
68
70
|
bucket = params.shift
|
69
71
|
bucket = bucket.name if Bucket === bucket
|
70
|
-
|
72
|
+
key = params.shift
|
73
|
+
@inputs << params.unshift(escape(key)).unshift(escape(bucket))
|
71
74
|
end
|
72
75
|
self
|
73
76
|
end
|
data/lib/riak/robject.rb
CHANGED
@@ -38,7 +38,7 @@ module Riak
|
|
38
38
|
# @return [Object] the data stored in Riak at this object's key. Varies in format by content-type, defaulting to String from the response body.
|
39
39
|
attr_accessor :data
|
40
40
|
|
41
|
-
# @return [Set<Link>]
|
41
|
+
# @return [Set<Link>] a Set of {Riak::Link} objects for relationships between this object and other resources
|
42
42
|
attr_accessor :links
|
43
43
|
|
44
44
|
# @return [String] the ETag header from the most recent HTTP response, useful for caching and reloading
|
@@ -50,6 +50,19 @@ module Riak
|
|
50
50
|
# @return [Hash] a hash of any X-Riak-Meta-* headers that were in the HTTP response, keyed on the trailing portion
|
51
51
|
attr_accessor :meta
|
52
52
|
|
53
|
+
# Loads a list of RObjects that were emitted from a MapReduce
|
54
|
+
# query.
|
55
|
+
# @param [Client] client A Riak::Client with which the results will be
|
56
|
+
# associated
|
57
|
+
# @param [Array<Hash>] response A list of results a MapReduce job. Each
|
58
|
+
# entry should contain these keys: bucket, key, vclock, values
|
59
|
+
# @return [Array<RObject>] An array of RObject instances
|
60
|
+
def self.load_from_mapreduce(client, response)
|
61
|
+
response.map do |item|
|
62
|
+
RObject.new(client[CGI.unescape(item['bucket'])], CGI.unescape(item['key'])).load_from_mapreduce(item)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
53
66
|
# Create a new object manually
|
54
67
|
# @param [Bucket] bucket the bucket in which the object exists
|
55
68
|
# @param [String] key the key at which the object resides. If nil, a key will be assigned when the object is saved.
|
@@ -81,6 +94,28 @@ module Riak
|
|
81
94
|
self
|
82
95
|
end
|
83
96
|
|
97
|
+
# Load object data from a map/reduce response item.
|
98
|
+
# This method is used by RObject::load_from_mapreduce to instantiate the necessary
|
99
|
+
# objects.
|
100
|
+
# @param [Hash] response a response from {Riak::MapReduce}
|
101
|
+
# @return [RObject] self
|
102
|
+
def load_from_mapreduce(response)
|
103
|
+
self.vclock = response['vclock']
|
104
|
+
if response['values'].size == 1
|
105
|
+
value = response['values'].first
|
106
|
+
load_map_reduce_value(value)
|
107
|
+
else
|
108
|
+
@conflict = true
|
109
|
+
@siblings = response['values'].map do |v|
|
110
|
+
RObject.new(self.bucket, self.key) do |robj|
|
111
|
+
robj.vclock = self.vclock
|
112
|
+
robj.load_map_reduce_value(v)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
84
119
|
# HTTP header hash that will be sent along when storing the object
|
85
120
|
# @return [Hash] hash of HTTP Headers
|
86
121
|
def store_headers
|
@@ -141,9 +176,9 @@ module Riak
|
|
141
176
|
|
142
177
|
# Delete the object from Riak and freeze this instance. Will work whether or not the object actually
|
143
178
|
# exists in the Riak database.
|
144
|
-
def delete
|
179
|
+
def delete(options={})
|
145
180
|
return if key.blank?
|
146
|
-
@bucket.delete(key)
|
181
|
+
@bucket.delete(key, options)
|
147
182
|
freeze
|
148
183
|
end
|
149
184
|
|
@@ -179,12 +214,8 @@ module Riak
|
|
179
214
|
ActiveSupport::JSON.encode(payload)
|
180
215
|
when /yaml/
|
181
216
|
YAML.dump(payload)
|
182
|
-
when "application/
|
183
|
-
|
184
|
-
Marshal.dump(payload)
|
185
|
-
else
|
186
|
-
payload.to_s
|
187
|
-
end
|
217
|
+
when "application/x-ruby-marshal"
|
218
|
+
Marshal.dump(payload)
|
188
219
|
else
|
189
220
|
payload.to_s
|
190
221
|
end
|
@@ -203,12 +234,8 @@ module Riak
|
|
203
234
|
ActiveSupport::JSON.decode(body)
|
204
235
|
when /yaml/
|
205
236
|
YAML.load(body)
|
206
|
-
when "application/
|
207
|
-
|
208
|
-
Marshal.load(body)
|
209
|
-
else
|
210
|
-
body
|
211
|
-
end
|
237
|
+
when "application/x-ruby-marshal"
|
238
|
+
Marshal.load(body)
|
212
239
|
else
|
213
240
|
body
|
214
241
|
end
|
@@ -246,12 +273,37 @@ module Riak
|
|
246
273
|
@bucket.client.http.path(*segments).to_s
|
247
274
|
end
|
248
275
|
|
276
|
+
protected
|
277
|
+
def load_map_reduce_value(hash)
|
278
|
+
metadata = hash['metadata']
|
279
|
+
extract_if_present(metadata, 'X-Riak-VTag', :etag)
|
280
|
+
extract_if_present(metadata, 'content-type', :content_type)
|
281
|
+
extract_if_present(metadata, 'X-Riak-Last-Modified', :last_modified) { |v| Time.httpdate( v ) }
|
282
|
+
extract_if_present(metadata, 'Links', :links) do |links|
|
283
|
+
Set.new( links.map { |l| Link.new("#{@bucket.client.prefix}#{l[0]}/#{l[1]}", l[2]) } )
|
284
|
+
end
|
285
|
+
extract_if_present(metadata, 'X-Riak-Meta', :meta) do |meta|
|
286
|
+
Hash[
|
287
|
+
meta.map do |k,v|
|
288
|
+
[k.sub(%r{^x-riak-meta-}i, ''), [v]]
|
289
|
+
end
|
290
|
+
]
|
291
|
+
end
|
292
|
+
extract_if_present(hash, 'data', :data) { |v| deserialize(v) }
|
293
|
+
end
|
294
|
+
|
249
295
|
private
|
250
|
-
def
|
251
|
-
if
|
252
|
-
|
253
|
-
value = yield
|
254
|
-
send("#{attribute}=", value)
|
296
|
+
def extract_if_present(hash, key, attribute=nil)
|
297
|
+
if hash[key].present?
|
298
|
+
attribute ||= key
|
299
|
+
value = block_given? ? yield(hash[key]) : hash[key]
|
300
|
+
send("#{attribute}=", value)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def extract_header(response, name, attribute=nil, &block)
|
305
|
+
extract_if_present(response[:headers], name, attribute) do |value|
|
306
|
+
block ? block.call(value[0]) : value[0]
|
255
307
|
end
|
256
308
|
end
|
257
309
|
|
data/lib/riak/util/escape.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Riak
|
2
2
|
module Util
|
3
3
|
module Escape
|
4
|
-
#
|
4
|
+
# CGI-escapes bucket or key names that may contain slashes for use in URLs.
|
5
5
|
# @param [String] bucket_or_key the bucket or key name
|
6
6
|
# @return [String] the escaped path segment
|
7
7
|
def escape(bucket_or_key)
|
8
|
-
|
8
|
+
CGI.escape(bucket_or_key.to_s).gsub("+", "%20")
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
@@ -57,6 +57,42 @@ describe Riak::CacheStore do
|
|
57
57
|
@cache = ActiveSupport::Cache.lookup_store(:riak_store, :n_value => 1)
|
58
58
|
@cache.bucket.n_value.should == 1
|
59
59
|
end
|
60
|
+
|
61
|
+
it "should set the bucket R value to 1 by default" do
|
62
|
+
@cache.bucket.r.should == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should set the bucket R default to the specified value" do
|
66
|
+
@cache = ActiveSupport::Cache.lookup_store(:riak_store, :r => "quorum")
|
67
|
+
@cache.bucket.r.should == "quorum"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should set the bucket W value to 1 by default" do
|
71
|
+
@cache.bucket.w.should == 1
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should set the bucket W default to the specified value" do
|
75
|
+
@cache = ActiveSupport::Cache.lookup_store(:riak_store, :w => "all")
|
76
|
+
@cache.bucket.w.should == "all"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should set the bucket DW value to 0 by default" do
|
80
|
+
@cache.bucket.dw.should == 0
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should set the bucket DW default to the specified value" do
|
84
|
+
@cache = ActiveSupport::Cache.lookup_store(:riak_store, :dw => "quorum")
|
85
|
+
@cache.bucket.dw.should == "quorum"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set the bucket RW value to quorum by default" do
|
89
|
+
@cache.bucket.rw.should == "quorum"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should set the bucket RW default to the specified value" do
|
93
|
+
@cache = ActiveSupport::Cache.lookup_store(:riak_store, :rw => "all")
|
94
|
+
@cache.bucket.rw.should == "all"
|
95
|
+
end
|
60
96
|
end
|
61
97
|
|
62
98
|
|
@@ -93,20 +129,6 @@ describe Riak::CacheStore do
|
|
93
129
|
@cache.fetch('foo', :force => true){'bar'}.should == 'bar'
|
94
130
|
end
|
95
131
|
|
96
|
-
it "should increment an integer value in the cache" do
|
97
|
-
@cache.write('foo', 1, :raw => true)
|
98
|
-
@cache.read('foo', :raw => true).to_i.should == 1
|
99
|
-
@cache.increment('foo')
|
100
|
-
@cache.read('foo', :raw => true).to_i.should == 2
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should decrement an integer value in the cache" do
|
104
|
-
@cache.write('foo', 1, :raw => true)
|
105
|
-
@cache.read('foo', :raw => true).to_i.should == 1
|
106
|
-
@cache.decrement('foo')
|
107
|
-
@cache.read('foo', :raw => true).to_i.should == 0
|
108
|
-
end
|
109
|
-
|
110
132
|
it "should detect if a value exists in the cache" do
|
111
133
|
@cache.write('foo', 'bar')
|
112
134
|
@cache.exist?('foo').should be_true
|
data/spec/riak/bucket_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe Riak::Bucket do
|
|
21
21
|
|
22
22
|
def do_load(overrides={})
|
23
23
|
@bucket.load({
|
24
|
-
:body => '{"props":{"name":"foo","allow_mult":false,"
|
24
|
+
:body => '{"props":{"name":"foo","n_val":3,"allow_mult":false,"last_write_wins":false,"precommit":[],"postcommit":[],"chash_keyfun":{"mod":"riak_core_util","fun":"chash_std_keyfun"},"linkfun":{"mod":"riak_kv_wm_link_walker","fun":"mapreduce_linkfun"},"old_vclock":86400,"young_vclock":20,"big_vclock":50,"small_vclock":10,"r":"quorum","w":"quorum","dw":"quorum","rw":"quorum"},"keys":["bar"]}',
|
25
25
|
:headers => {
|
26
26
|
"vary" => ["Accept-Encoding"],
|
27
27
|
"server" => ["MochiWeb/1.1 WebMachine/1.5.1 (hack the charles gibson)"],
|
@@ -53,7 +53,7 @@ describe Riak::Bucket do
|
|
53
53
|
describe "when loading data from an HTTP response" do
|
54
54
|
it "should load the bucket properties from the response body" do
|
55
55
|
do_load
|
56
|
-
@bucket.props.should == {"name"=>"foo","allow_mult" =>
|
56
|
+
@bucket.props.should == {"name"=>"foo", "n_val"=>3, "allow_mult"=>false, "last_write_wins"=>false, "precommit"=>[], "postcommit"=>[], "chash_keyfun"=>{"mod"=>"riak_core_util", "fun"=>"chash_std_keyfun"}, "linkfun"=>{"mod"=>"riak_kv_wm_link_walker", "fun"=>"mapreduce_linkfun"}, "old_vclock"=>86400, "young_vclock"=>20, "big_vclock"=>50, "small_vclock"=>10, "r"=>"quorum", "w"=>"quorum", "dw"=>"quorum", "rw"=>"quorum"}
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should load the keys from the response body" do
|
@@ -80,12 +80,12 @@ describe Riak::Bucket do
|
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should load the keys if not present" do
|
83
|
-
@http.should_receive(:get).with(200, "/riak/", "foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
83
|
+
@http.should_receive(:get).with(200, "/riak/", "foo", {:props => false, :keys => true}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
84
84
|
@bucket.keys.should == ["bar"]
|
85
85
|
end
|
86
86
|
|
87
87
|
it "should allow reloading of the keys" do
|
88
|
-
@http.should_receive(:get).with(200, "/riak/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
88
|
+
@http.should_receive(:get).with(200, "/riak/","foo", {:props => false, :keys => true}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
89
89
|
do_load # Ensures they're already loaded
|
90
90
|
@bucket.keys(:reload => true).should == ["bar"]
|
91
91
|
end
|
@@ -101,13 +101,13 @@ describe Riak::Bucket do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should unescape key names" do
|
104
|
-
@http.should_receive(:get).with(200, "/riak/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
|
104
|
+
@http.should_receive(:get).with(200, "/riak/","foo", {:props => false, :keys => true}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
|
105
105
|
@bucket.keys.should == ["bar baz"]
|
106
106
|
end
|
107
107
|
|
108
108
|
it "should escape the bucket name" do
|
109
109
|
@bucket.instance_variable_set :@name, "unescaped "
|
110
|
-
@http.should_receive(:get).with(200, "/riak/","unescaped%20", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
110
|
+
@http.should_receive(:get).with(200, "/riak/","unescaped%20", {:props => false, :keys => true}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
111
111
|
@bucket.keys.should == ["bar"]
|
112
112
|
end
|
113
113
|
end
|
@@ -228,6 +228,24 @@ describe Riak::Bucket do
|
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
231
|
+
[:r, :w, :dw, :rw].each do |q|
|
232
|
+
describe "get/set the default #{q} quorum" do
|
233
|
+
before :each do
|
234
|
+
do_load
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should extract the default #{q} quorum" do
|
238
|
+
@bucket.send(q).should == "quorum"
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should set the #{q} quorum" do
|
242
|
+
@bucket.should_receive(:props=).with(hash_including("#{q}" => 1))
|
243
|
+
@bucket.send("#{q}=",1)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
|
231
249
|
describe "checking whether a key exists" do
|
232
250
|
it "should return true if the object does exist" do
|
233
251
|
@client.http.should_receive(:head).and_return(:code => 200)
|
data/spec/riak/client_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
1
|
+
60# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -157,13 +157,13 @@ describe Riak::Client do
|
|
157
157
|
end
|
158
158
|
|
159
159
|
it "should send a GET request to the bucket name and return a Riak::Bucket" do
|
160
|
-
@http.should_receive(:get).with(200, "/riak/", "foo", {}, {}).and_return(@payload)
|
160
|
+
@http.should_receive(:get).with(200, "/riak/", "foo", {:keys => false}, {}).and_return(@payload)
|
161
161
|
@client.bucket("foo").should be_kind_of(Riak::Bucket)
|
162
162
|
end
|
163
163
|
|
164
|
-
it "should allow requesting bucket properties
|
165
|
-
@http.should_receive(:get).with(200, "/riak/", "foo", {:keys =>
|
166
|
-
@client.bucket("foo", :keys =>
|
164
|
+
it "should allow requesting bucket properties with the keys" do
|
165
|
+
@http.should_receive(:get).with(200, "/riak/", "foo", {:keys => true}, {}).and_return(@payload)
|
166
|
+
@client.bucket("foo", :keys => true)
|
167
167
|
end
|
168
168
|
|
169
169
|
it "should escape bucket names with invalid characters" do
|
data/spec/riak/escape_spec.rb
CHANGED
@@ -9,6 +9,7 @@ describe Riak::Util::Escape do
|
|
9
9
|
it "should escape standard non-safe characters" do
|
10
10
|
@object.escape("some string").should == "some%20string"
|
11
11
|
@object.escape("another^one").should == "another%5Eone"
|
12
|
+
@object.escape("bracket[one").should == "bracket%5Bone"
|
12
13
|
end
|
13
14
|
|
14
15
|
it "should escape slashes" do
|
@@ -49,11 +49,21 @@ describe Riak::MapReduce do
|
|
49
49
|
@mr.inputs.should == [["foo","bar"]]
|
50
50
|
end
|
51
51
|
|
52
|
+
it "should add bucket/key pairs to the inputs" do
|
53
|
+
@mr.add("[foo]","(bar)")
|
54
|
+
@mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
|
55
|
+
end
|
56
|
+
|
52
57
|
it "should add an array containing a bucket/key pair to the inputs" do
|
53
58
|
@mr.add(["foo","bar"])
|
54
59
|
@mr.inputs.should == [["foo","bar"]]
|
55
60
|
end
|
56
61
|
|
62
|
+
it "should add an escaped array containing a bucket/key pair to the inputs" do
|
63
|
+
@mr.add(["[foo]","(bar)"])
|
64
|
+
@mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
|
65
|
+
end
|
66
|
+
|
57
67
|
it "should add an object to the inputs by its bucket and key" do
|
58
68
|
bucket = Riak::Bucket.new(@client, "foo")
|
59
69
|
obj = Riak::RObject.new(bucket, "bar")
|
@@ -61,17 +71,36 @@ describe Riak::MapReduce do
|
|
61
71
|
@mr.inputs.should == [["foo", "bar"]]
|
62
72
|
end
|
63
73
|
|
74
|
+
it "should add an object to the inputs by its escaped bucket and key" do
|
75
|
+
bucket = Riak::Bucket.new(@client, "[foo]")
|
76
|
+
obj = Riak::RObject.new(bucket, "(bar)")
|
77
|
+
@mr.add(obj)
|
78
|
+
@mr.inputs.should == [["%5Bfoo%5D", "%28bar%29"]]
|
79
|
+
end
|
80
|
+
|
64
81
|
it "should add an array containing a bucket/key/key-data triple to the inputs" do
|
65
82
|
@mr.add(["foo","bar",1000])
|
66
83
|
@mr.inputs.should == [["foo","bar",1000]]
|
67
84
|
end
|
68
85
|
|
86
|
+
it "should add an escaped array containing a bucket/key/key-data triple to the inputs" do
|
87
|
+
@mr.add(["[foo]","(bar)","[]()"])
|
88
|
+
@mr.inputs.should == [["%5Bfoo%5D", "%28bar%29","[]()"]]
|
89
|
+
end
|
90
|
+
|
69
91
|
it "should use a bucket name as the single input" do
|
70
92
|
@mr.add(Riak::Bucket.new(@client, "foo"))
|
71
93
|
@mr.inputs.should == "foo"
|
72
94
|
@mr.add("docs")
|
73
95
|
@mr.inputs.should == "docs"
|
74
96
|
end
|
97
|
+
|
98
|
+
it "should use an escaped bucket name as the single input" do
|
99
|
+
@mr.add(Riak::Bucket.new(@client, "[foo]"))
|
100
|
+
@mr.inputs.should == "%5Bfoo%5D"
|
101
|
+
@mr.add("docs")
|
102
|
+
@mr.inputs.should == "docs"
|
103
|
+
end
|
75
104
|
end
|
76
105
|
|
77
106
|
[:map, :reduce].each do |type|
|
data/spec/riak/object_spec.rb
CHANGED
@@ -101,39 +101,19 @@ describe Riak::RObject do
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
describe "when the content type is
|
104
|
+
describe "when the content type is application/x-ruby-marshal" do
|
105
105
|
before :each do
|
106
|
-
@object.content_type = "application/
|
106
|
+
@object.content_type = "application/x-ruby-marshal"
|
107
|
+
@payload = Marshal.dump({"foo" => "bar"})
|
107
108
|
end
|
108
109
|
|
109
|
-
describe "if the ruby-serialization meta field is set to Marshal" do
|
110
|
-
before :each do
|
111
|
-
@object.meta['ruby-serialization'] = "Marshal"
|
112
|
-
@payload = Marshal.dump({"foo" => "bar"})
|
113
|
-
end
|
114
110
|
|
115
|
-
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
it "should load from Marshal" do
|
120
|
-
@object.deserialize(@payload).should == {"foo" => "bar"}
|
121
|
-
end
|
111
|
+
it "should dump via Marshal" do
|
112
|
+
@object.serialize({"foo" => "bar"}).should == @payload
|
122
113
|
end
|
123
114
|
|
124
|
-
|
125
|
-
|
126
|
-
@object.meta.delete("ruby-serialization")
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should dump to a string" do
|
130
|
-
@object.serialize(2).should == "2"
|
131
|
-
@object.serialize("foo").should == "foo"
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should load the body unmodified" do
|
135
|
-
@object.deserialize("foo").should == "foo"
|
136
|
-
end
|
115
|
+
it "should load from Marshal" do
|
116
|
+
@object.deserialize(@payload).should == {"foo" => "bar"}
|
137
117
|
end
|
138
118
|
end
|
139
119
|
end
|
@@ -198,6 +178,11 @@ describe Riak::RObject do
|
|
198
178
|
@object.key.should == "baz"
|
199
179
|
end
|
200
180
|
|
181
|
+
it "should parse and escape the location header into the key when present" do
|
182
|
+
@object.load({:headers => {"content-type" => ["application/json"], "location" => ["/riak/foo/%5Bbaz%5D"]}})
|
183
|
+
@object.key.should == "[baz]"
|
184
|
+
end
|
185
|
+
|
201
186
|
it "should be in conflict when the response code is 300 and the content-type is multipart/mixed" do
|
202
187
|
@object.load({:headers => {"content-type" => ["multipart/mixed; boundary=foo"]}, :code => 300 })
|
203
188
|
@object.should be_conflict
|
@@ -209,6 +194,106 @@ describe Riak::RObject do
|
|
209
194
|
end
|
210
195
|
end
|
211
196
|
|
197
|
+
describe "instantiating new object from a map reduce operation" do
|
198
|
+
before :each do
|
199
|
+
@client.stub!(:[]).and_return(@bucket)
|
200
|
+
|
201
|
+
@sample_response = [
|
202
|
+
{"bucket"=>"users",
|
203
|
+
"key"=>"A2IbUQ2KEMbe4WGtdL97LoTi1DN%5B%28%5C%2F%29%5D",
|
204
|
+
"vclock"=> "a85hYGBgzmDKBVIsCfs+fc9gSN9wlA8q/hKosDpIOAsA",
|
205
|
+
"values"=> [
|
206
|
+
{"metadata"=>
|
207
|
+
{"Links"=>[["addresses", "A2cbUQ2KEMbeyWGtdz97LoTi1DN", "home_address"]],
|
208
|
+
"X-Riak-VTag"=>"5bnavU3rrubcxLI8EvFXhB",
|
209
|
+
"content-type"=>"application/json",
|
210
|
+
"X-Riak-Last-Modified"=>"Mon, 12 Jul 2010 21:37:43 GMT",
|
211
|
+
"X-Riak-Meta"=>{"X-Riak-Meta-King-Of-Robots"=>"I"}},
|
212
|
+
"data"=>
|
213
|
+
"{\"email\":\"mail@test.com\",\"_type\":\"User\"}"
|
214
|
+
}
|
215
|
+
]
|
216
|
+
}
|
217
|
+
]
|
218
|
+
@object = Riak::RObject.load_from_mapreduce(@client,@sample_response).first
|
219
|
+
@object.should be_kind_of(Riak::RObject)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should load the content type" do
|
223
|
+
@object.content_type.should == "application/json"
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should load the body data" do
|
227
|
+
@object.data.should be_present
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should deserialize the body data" do
|
231
|
+
@object.data.should == {"email" => "mail@test.com", "_type" => "User"}
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should set the vclock" do
|
235
|
+
@object.vclock.should == "a85hYGBgzmDKBVIsCfs+fc9gSN9wlA8q/hKosDpIOAsA"
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should load and parse links" do
|
239
|
+
@object.links.should have(1).item
|
240
|
+
@object.links.first.url.should == "/riak/addresses/A2cbUQ2KEMbeyWGtdz97LoTi1DN"
|
241
|
+
@object.links.first.rel.should == "home_address"
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should set the ETag" do
|
245
|
+
@object.etag.should == "5bnavU3rrubcxLI8EvFXhB"
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should set modified date" do
|
249
|
+
@object.last_modified.to_i.should == Time.httpdate("Mon, 12 Jul 2010 21:37:43 GMT").to_i
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should load meta information" do
|
253
|
+
@object.meta["King-Of-Robots"].should == ["I"]
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should set the key" do
|
257
|
+
@object.key.should == "A2IbUQ2KEMbe4WGtdL97LoTi1DN[(\\/)]"
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should not set conflict when there is none" do
|
261
|
+
@object.conflict?.should be_false
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "when there are multiple values in an object" do
|
265
|
+
before :each do
|
266
|
+
response = @sample_response.dup
|
267
|
+
response[0]['values'] << {
|
268
|
+
"metadata"=> {
|
269
|
+
"Links"=>[],
|
270
|
+
"X-Riak-VTag"=>"7jDZLdu0fIj2iRsjGD8qq8",
|
271
|
+
"content-type"=>"application/json",
|
272
|
+
"X-Riak-Last-Modified"=>"Mon, 14 Jul 2010 19:28:27 GMT",
|
273
|
+
"X-Riak-Meta"=>[]
|
274
|
+
},
|
275
|
+
"data"=> "{\"email\":\"mail@domain.com\",\"_type\":\"User\"}"
|
276
|
+
}
|
277
|
+
@object = Riak::RObject.load_from_mapreduce( @client, response ).first
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should expose siblings" do
|
281
|
+
@object.should have(2).siblings
|
282
|
+
@object.siblings[0].etag.should == "5bnavU3rrubcxLI8EvFXhB"
|
283
|
+
@object.siblings[1].etag.should == "7jDZLdu0fIj2iRsjGD8qq8"
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should be in conflict" do
|
287
|
+
@object.data.should_not be_present
|
288
|
+
@object.should be_conflict
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should assign the same vclock to all the siblings" do
|
292
|
+
@object.siblings.should be_all {|s| s.vclock == @object.vclock }
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
212
297
|
describe "extracting siblings" do
|
213
298
|
before :each do
|
214
299
|
@object = Riak::RObject.new(@bucket, "bar").load({:headers => {"x-riak-vclock" => ["merged"], "content-type" => ["multipart/mixed; boundary=foo"]}, :code => 300, :body => "\n--foo\nContent-Type: text/plain\n\nbar\n--foo\nContent-Type: text/plain\n\nbaz\n--foo--\n"})
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riak-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: true
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
|
7
|
+
- 8
|
8
|
+
- 0
|
9
|
+
- beta
|
10
|
+
version: 0.8.0.beta
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Sean Cribbs
|
@@ -14,13 +15,14 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-08-24 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ~>
|
26
28
|
- !ruby/object:Gem::Version
|
@@ -29,14 +31,15 @@ dependencies:
|
|
29
31
|
- 0
|
30
32
|
- 0
|
31
33
|
- beta
|
32
|
-
-
|
33
|
-
version: 2.0.0.beta.
|
34
|
+
- 11
|
35
|
+
version: 2.0.0.beta.11
|
34
36
|
type: :development
|
35
37
|
version_requirements: *id001
|
36
38
|
- !ruby/object:Gem::Dependency
|
37
39
|
name: fakeweb
|
38
40
|
prerelease: false
|
39
41
|
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
40
43
|
requirements:
|
41
44
|
- - ">="
|
42
45
|
- !ruby/object:Gem::Version
|
@@ -50,6 +53,7 @@ dependencies:
|
|
50
53
|
name: rack
|
51
54
|
prerelease: false
|
52
55
|
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
53
57
|
requirements:
|
54
58
|
- - ">="
|
55
59
|
- !ruby/object:Gem::Version
|
@@ -63,6 +67,7 @@ dependencies:
|
|
63
67
|
name: curb
|
64
68
|
prerelease: false
|
65
69
|
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
66
71
|
requirements:
|
67
72
|
- - ">="
|
68
73
|
- !ruby/object:Gem::Version
|
@@ -76,6 +81,7 @@ dependencies:
|
|
76
81
|
name: activesupport
|
77
82
|
prerelease: false
|
78
83
|
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
79
85
|
requirements:
|
80
86
|
- - ">="
|
81
87
|
- !ruby/object:Gem::Version
|
@@ -86,6 +92,21 @@ dependencies:
|
|
86
92
|
version: 2.3.5
|
87
93
|
type: :runtime
|
88
94
|
version_requirements: *id005
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: i18n
|
97
|
+
prerelease: false
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
- 4
|
106
|
+
- 0
|
107
|
+
version: 0.4.0
|
108
|
+
type: :runtime
|
109
|
+
version_requirements: *id006
|
89
110
|
description: riak-client is a rich client for Riak, the distributed database by Basho. It supports the full HTTP interface including storage operations, bucket configuration, link-walking and map-reduce.
|
90
111
|
email: seancribbs@gmail.com
|
91
112
|
executables: []
|
@@ -95,6 +116,8 @@ extensions: []
|
|
95
116
|
extra_rdoc_files: []
|
96
117
|
|
97
118
|
files:
|
119
|
+
- Gemfile
|
120
|
+
- Gemfile.lock
|
98
121
|
- lib/riak/bucket.rb
|
99
122
|
- lib/riak/cache_store.rb
|
100
123
|
- lib/riak/client/curb_backend.rb
|
@@ -147,6 +170,7 @@ rdoc_options: []
|
|
147
170
|
require_paths:
|
148
171
|
- lib
|
149
172
|
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
none: false
|
150
174
|
requirements:
|
151
175
|
- - ">="
|
152
176
|
- !ruby/object:Gem::Version
|
@@ -154,16 +178,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
178
|
- 0
|
155
179
|
version: "0"
|
156
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
none: false
|
157
182
|
requirements:
|
158
|
-
- - "
|
183
|
+
- - ">"
|
159
184
|
- !ruby/object:Gem::Version
|
160
185
|
segments:
|
161
|
-
-
|
162
|
-
|
186
|
+
- 1
|
187
|
+
- 3
|
188
|
+
- 1
|
189
|
+
version: 1.3.1
|
163
190
|
requirements:
|
164
191
|
- `gem install curb` for better HTTP performance
|
165
192
|
rubyforge_project:
|
166
|
-
rubygems_version: 1.3.
|
193
|
+
rubygems_version: 1.3.7
|
167
194
|
signing_key:
|
168
195
|
specification_version: 3
|
169
196
|
summary: riak-client is a rich client for Riak, the distributed database by Basho.
|