riak-client 2.1.0 → 2.2.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Guardfile +15 -9
- data/README.markdown +118 -9
- data/lib/riak/bucket.rb +16 -1
- data/lib/riak/bucket_properties.rb +67 -0
- data/lib/riak/bucket_type.rb +48 -0
- data/lib/riak/bucket_typed/bucket.rb +113 -0
- data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
- data/lib/riak/client/beefcake/message_overlay.rb +42 -20
- data/lib/riak/client/beefcake/object_methods.rb +1 -1
- data/lib/riak/client/beefcake/socket.rb +6 -6
- data/lib/riak/client/beefcake_protobuffs_backend.rb +44 -60
- data/lib/riak/client/protobuffs_backend.rb +8 -8
- data/lib/riak/client.rb +7 -2
- data/lib/riak/crdt/base.rb +29 -1
- data/lib/riak/crdt/counter.rb +7 -3
- data/lib/riak/crdt/inner_flag.rb +1 -1
- data/lib/riak/crdt/map.rb +7 -3
- data/lib/riak/crdt/set.rb +7 -4
- data/lib/riak/errors/failed_request.rb +2 -0
- data/lib/riak/errors/search_error.rb +29 -0
- data/lib/riak/locale/en.yml +7 -0
- data/lib/riak/map_reduce.rb +70 -6
- data/lib/riak/robject.rb +19 -3
- data/lib/riak/search/index.rb +73 -0
- data/lib/riak/search/query.rb +133 -0
- data/lib/riak/search/result_collection.rb +91 -0
- data/lib/riak/search/result_document.rb +59 -0
- data/lib/riak/search/schema.rb +65 -0
- data/lib/riak/search.rb +10 -0
- data/lib/riak/secondary_index.rb +6 -0
- data/lib/riak/version.rb +1 -1
- data/spec/fixtures/yz_schema_template.xml +18 -0
- data/spec/integration/riak/bucket_types_spec.rb +218 -39
- data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
- data/spec/integration/riak/crdt_spec.rb +30 -2
- data/spec/integration/riak/properties_spec.rb +69 -0
- data/spec/integration/riak/search_spec.rb +104 -0
- data/spec/integration/riak/secondary_index_spec.rb +18 -0
- data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
- data/spec/riak/bucket_properties_spec.rb +114 -0
- data/spec/riak/bucket_type_spec.rb +34 -0
- data/spec/riak/bucket_typed/bucket.rb +43 -0
- data/spec/riak/client_spec.rb +16 -8
- data/spec/riak/crdt/counter_spec.rb +2 -1
- data/spec/riak/crdt/map_spec.rb +2 -1
- data/spec/riak/crdt/set_spec.rb +2 -1
- data/spec/riak/map_reduce_spec.rb +169 -124
- data/spec/riak/search/index_spec.rb +62 -0
- data/spec/riak/search/query_spec.rb +88 -0
- data/spec/riak/search/result_collection_spec.rb +87 -0
- data/spec/riak/search/result_document_spec.rb +63 -0
- data/spec/riak/search/schema_spec.rb +63 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/search_config.rb +81 -0
- data/spec/support/test_client.yml +14 -7
- metadata +44 -5
@@ -10,26 +10,6 @@ module Riak
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class RpbBucketProps
|
13
|
-
def clean_hook(newval)
|
14
|
-
if newval.is_a? Array
|
15
|
-
return newval.map{|v| clean_hook v}
|
16
|
-
end
|
17
|
-
|
18
|
-
newval = newval.symbolize_keys if newval.is_a? Hash
|
19
|
-
if newval.is_a?(Hash) && newval[:module] && newval[:function]
|
20
|
-
modfun = RpbModFun.new newval
|
21
|
-
hook = RpbCommitHook.new modfun: modfun
|
22
|
-
newval = hook
|
23
|
-
elsif newval.is_a?(Hash) && newval[:name]
|
24
|
-
hook = RpbCommitHook.new newval
|
25
|
-
newval = hook
|
26
|
-
elsif newval.is_a? String
|
27
|
-
hook = RpbCommitHook.new name: newval
|
28
|
-
newval = hook
|
29
|
-
end
|
30
|
-
|
31
|
-
return newval
|
32
|
-
end
|
33
13
|
|
34
14
|
# "repeated" elements with zero items are indistinguishable
|
35
15
|
# from a nil, so we have to manage has_precommit/has_postcommit
|
@@ -55,6 +35,48 @@ module Riak
|
|
55
35
|
@has_postcommit = newval
|
56
36
|
@postcommit ||= [] if newval
|
57
37
|
end
|
38
|
+
|
39
|
+
def chash_keyfun=(newval)
|
40
|
+
@chash_keyfun = clean_modfun newval
|
41
|
+
end
|
42
|
+
|
43
|
+
def linkfun=(newval)
|
44
|
+
@linkfun = clean_modfun newval
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def clean_hook(newval)
|
50
|
+
if newval.is_a? Array
|
51
|
+
return newval.map{|v| clean_hook v}
|
52
|
+
end
|
53
|
+
|
54
|
+
newval = newval.symbolize_keys if newval.is_a? Hash
|
55
|
+
if newval.is_a?(Hash) && newval[:module] && newval[:function]
|
56
|
+
modfun = RpbModFun.new newval
|
57
|
+
hook = RpbCommitHook.new modfun: modfun
|
58
|
+
newval = hook
|
59
|
+
elsif newval.is_a?(Hash) && newval[:name]
|
60
|
+
hook = RpbCommitHook.new newval
|
61
|
+
newval = hook
|
62
|
+
elsif newval.is_a? String
|
63
|
+
hook = RpbCommitHook.new name: newval
|
64
|
+
newval = hook
|
65
|
+
end
|
66
|
+
|
67
|
+
return newval
|
68
|
+
end
|
69
|
+
|
70
|
+
def clean_modfun(newval)
|
71
|
+
return newval unless newval.is_a? Hash
|
72
|
+
|
73
|
+
newval = newval.symbolize_keys
|
74
|
+
if newval[:mod] && newval[:fun]
|
75
|
+
modfun = RpbModFun.new :'module' => newval[:mod], function: newval[:fun]
|
76
|
+
end
|
77
|
+
|
78
|
+
return modfun
|
79
|
+
end
|
58
80
|
end
|
59
81
|
end
|
60
82
|
end
|
@@ -30,7 +30,7 @@ module Riak
|
|
30
30
|
tcp = start_tcp_socket(host, port)
|
31
31
|
TlsInitiator.new(tcp, host, authentication).tls_socket
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Wrap up the logic to turn a TCP socket into a TLS socket.
|
35
35
|
# Depends on Beefcake, which should be relatively safe.
|
36
36
|
class TlsInitiator
|
@@ -104,7 +104,7 @@ module Riak
|
|
104
104
|
candidate = @auth[k.to_sym]
|
105
105
|
next if candidate.nil?
|
106
106
|
next if candidate.is_a? OpenSSL::X509::Certificate
|
107
|
-
|
107
|
+
|
108
108
|
@auth[k.to_sym] = OpenSSL::X509::Certificate.new try_load candidate
|
109
109
|
end
|
110
110
|
end
|
@@ -144,7 +144,7 @@ module Riak
|
|
144
144
|
# couldn't read the file, it might be a string containing
|
145
145
|
# a key
|
146
146
|
rescue Errno::ENAMETOOLONG
|
147
|
-
# the filename is too long, it's almost certainly a string
|
147
|
+
# the filename is too long, it's almost certainly a string
|
148
148
|
# containing a key
|
149
149
|
rescue => e
|
150
150
|
raise TlsError::ReadDataError.new e, data_or_path
|
@@ -192,7 +192,7 @@ module Riak
|
|
192
192
|
ocsp: !!@auth[:ocsp],
|
193
193
|
crl: !!@auth[:crl]
|
194
194
|
}
|
195
|
-
|
195
|
+
|
196
196
|
if @auth[:crl_file]
|
197
197
|
o[:crl_file] = @auth[:crl_file]
|
198
198
|
o[:crl] = true
|
@@ -232,7 +232,7 @@ module Riak
|
|
232
232
|
len, code = header.unpack 'NC'
|
233
233
|
decode = BeefcakeMessageCodes[code]
|
234
234
|
return decode, '' if len == 1
|
235
|
-
|
235
|
+
|
236
236
|
message = @sock.read(len - 1)
|
237
237
|
return decode, message
|
238
238
|
end
|
@@ -250,7 +250,7 @@ module Riak
|
|
250
250
|
actual: candidate_code.inspect,
|
251
251
|
body: message.inspect
|
252
252
|
))
|
253
|
-
|
253
|
+
|
254
254
|
end
|
255
255
|
end
|
256
256
|
end
|
@@ -13,12 +13,14 @@ module Riak
|
|
13
13
|
require 'riak/client/beefcake/messages'
|
14
14
|
require 'riak/client/beefcake/message_overlay'
|
15
15
|
require 'riak/client/beefcake/object_methods'
|
16
|
+
require 'riak/client/beefcake/bucket_properties_operator'
|
16
17
|
require 'riak/client/beefcake/crdt_operator'
|
17
18
|
require 'riak/client/beefcake/crdt_loader'
|
18
19
|
require 'riak/client/beefcake/protocol'
|
19
20
|
require 'riak/client/beefcake/socket'
|
20
21
|
true
|
21
|
-
rescue LoadError, NameError
|
22
|
+
rescue LoadError, NameError => e
|
23
|
+
# put exception into a variable for debugging
|
22
24
|
false
|
23
25
|
end
|
24
26
|
end
|
@@ -202,37 +204,17 @@ module Riak
|
|
202
204
|
end
|
203
205
|
|
204
206
|
def get_bucket_props(bucket, options = { })
|
205
|
-
|
206
|
-
|
207
|
-
req = RpbGetBucketReq.new(:bucket => maybe_encode(bucket))
|
208
|
-
req.type = options[:type] if options[:type]
|
209
|
-
|
210
|
-
resp_message = protocol do |p|
|
211
|
-
p.write :GetBucketReq, req
|
212
|
-
p.expect :GetBucketResp, RpbGetBucketResp
|
213
|
-
end
|
214
|
-
|
215
|
-
resp = normalize_quorums resp_message.props.to_hash.stringify_keys
|
216
|
-
normalized = normalize_hooks resp
|
217
|
-
normalized.stringify_keys
|
207
|
+
bucket_properties_operator.get bucket, options
|
218
208
|
end
|
219
209
|
|
220
210
|
def set_bucket_props(bucket, props, type=nil)
|
221
|
-
|
222
|
-
req = RpbSetBucketReq.new(
|
223
|
-
bucket: maybe_encode(bucket),
|
224
|
-
props: RpbBucketProps.new(props.symbolize_keys),
|
225
|
-
type: type)
|
226
|
-
|
227
|
-
protocol do |p|
|
228
|
-
p.write :SetBucketReq, req
|
229
|
-
p.expect :SetBucketResp
|
230
|
-
end
|
211
|
+
bucket_properties_operator.put bucket, props, type: type
|
231
212
|
end
|
232
213
|
|
233
|
-
def reset_bucket_props(bucket)
|
214
|
+
def reset_bucket_props(bucket, options)
|
234
215
|
bucket = bucket.name if Bucket === bucket
|
235
|
-
req = RpbResetBucketReq.new(:
|
216
|
+
req = RpbResetBucketReq.new(bucket: maybe_encode(bucket),
|
217
|
+
type: options[:type])
|
236
218
|
|
237
219
|
protocol do |p|
|
238
220
|
p.write :ResetBucketReq, req
|
@@ -240,6 +222,18 @@ module Riak
|
|
240
222
|
end
|
241
223
|
end
|
242
224
|
|
225
|
+
def get_bucket_type_props(bucket_type)
|
226
|
+
bucket_type = bucket_type.name if bucket_type.is_a? BucketType
|
227
|
+
req = RpbGetBucketTypeReq.new type: bucket_type
|
228
|
+
|
229
|
+
resp = protocol do |p|
|
230
|
+
p.write :GetBucketTypeReq, req
|
231
|
+
p.expect(:GetBucketResp, RpbGetBucketResp)
|
232
|
+
end
|
233
|
+
|
234
|
+
resp.props.to_hash
|
235
|
+
end
|
236
|
+
|
243
237
|
def list_keys(bucket, options={}, &block)
|
244
238
|
bucket = bucket.name if Bucket === bucket
|
245
239
|
req = RpbListKeysReq.new(options.merge(:bucket => maybe_encode(bucket)))
|
@@ -322,7 +316,7 @@ module Riak
|
|
322
316
|
}
|
323
317
|
end
|
324
318
|
|
325
|
-
options.merge!(:bucket => bucket, :index => index)
|
319
|
+
options.merge!(:bucket => bucket, :index => index.to_s)
|
326
320
|
options.merge!(query_options)
|
327
321
|
options[:stream] = block_given?
|
328
322
|
|
@@ -365,20 +359,20 @@ module Riak
|
|
365
359
|
|
366
360
|
def get_search_index(name)
|
367
361
|
req = RpbYokozunaIndexGetReq.new(:name => name)
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
362
|
+
begin
|
363
|
+
resp = protocol do |p|
|
364
|
+
p.write :YokozunaIndexGetReq, req
|
365
|
+
p.expect :YokozunaIndexGetResp, RpbYokozunaIndexGetResp, empty_body_acceptable: true
|
366
|
+
end
|
367
|
+
rescue ProtobuffsErrorResponse => e
|
368
|
+
if e.code == 0 && e.original_message =~ /notfound/
|
369
|
+
raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
|
370
|
+
end
|
376
371
|
|
377
|
-
|
378
|
-
resp.index.map{|index| {:name => index.name, :schema => index.schema, :n_val => index.n_val} }
|
379
|
-
else
|
380
|
-
resp
|
372
|
+
raise e
|
381
373
|
end
|
374
|
+
|
375
|
+
resp
|
382
376
|
end
|
383
377
|
|
384
378
|
def delete_search_index(name)
|
@@ -404,9 +398,17 @@ module Riak
|
|
404
398
|
def get_search_schema(name)
|
405
399
|
req = RpbYokozunaSchemaGetReq.new(:name => name)
|
406
400
|
|
407
|
-
|
408
|
-
|
409
|
-
|
401
|
+
begin
|
402
|
+
resp = protocol do |p|
|
403
|
+
p.write :YokozunaSchemaGetReq, req
|
404
|
+
p.expect :YokozunaSchemaGetResp, RpbYokozunaSchemaGetResp
|
405
|
+
end
|
406
|
+
rescue ProtobuffsErrorResponse => e
|
407
|
+
if e.code == 0 && e.original_message =~ /notfound/
|
408
|
+
raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
|
409
|
+
end
|
410
|
+
|
411
|
+
raise e
|
410
412
|
end
|
411
413
|
|
412
414
|
resp.schema ? resp.schema : resp
|
@@ -506,24 +508,6 @@ module Riak
|
|
506
508
|
# Search returns strings that should always be valid UTF-8
|
507
509
|
ObjectMethods::ENCODING ? str.force_encoding('UTF-8') : str
|
508
510
|
end
|
509
|
-
|
510
|
-
def normalize_hooks(message)
|
511
|
-
message.dup.tap do |o|
|
512
|
-
%w{chash_keyfun linkfun}.each do |k|
|
513
|
-
o[k] = {'mod' => message[k].module, 'fun' => message[k].function}
|
514
|
-
end
|
515
|
-
%w{precommit postcommit}.each do |k|
|
516
|
-
orig = message[k]
|
517
|
-
o[k] = orig.map do |hook|
|
518
|
-
if hook.modfun
|
519
|
-
{'mod' => hook.modfun.module, 'fun' => hook.modfun.function}
|
520
|
-
else
|
521
|
-
hook.name
|
522
|
-
end
|
523
|
-
end
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
527
511
|
end
|
528
512
|
end
|
529
513
|
end
|
@@ -15,6 +15,14 @@ module Riak
|
|
15
15
|
|
16
16
|
MESSAGE_CODES = BeefcakeMessageCodes
|
17
17
|
|
18
|
+
UINTMAX = 0xffffffff
|
19
|
+
QUORUMS = {
|
20
|
+
"one" => UINTMAX - 1,
|
21
|
+
"quorum" => UINTMAX - 2,
|
22
|
+
"all" => UINTMAX - 3,
|
23
|
+
"default" => UINTMAX - 4
|
24
|
+
}.freeze
|
25
|
+
|
18
26
|
def self.simple(method, code)
|
19
27
|
define_method method do
|
20
28
|
socket.write([1, MESSAGE_CODES.index(code)].pack('NC'))
|
@@ -93,14 +101,6 @@ module Riak
|
|
93
101
|
@socket = nil
|
94
102
|
end
|
95
103
|
|
96
|
-
UINTMAX = 0xffffffff
|
97
|
-
QUORUMS = {
|
98
|
-
"one" => UINTMAX - 1,
|
99
|
-
"quorum" => UINTMAX - 2,
|
100
|
-
"all" => UINTMAX - 3,
|
101
|
-
"default" => UINTMAX - 4
|
102
|
-
}.freeze
|
103
|
-
|
104
104
|
def prune_unsupported_options(req,options={})
|
105
105
|
unless quorum_controls?
|
106
106
|
[:notfound_ok, :basic_quorum, :pr, :pw].each {|k| options.delete k }
|
data/lib/riak/client.rb
CHANGED
@@ -14,6 +14,7 @@ require 'riak/client/yokozuna'
|
|
14
14
|
require 'riak/client/protobuffs_backend'
|
15
15
|
require 'riak/client/beefcake_protobuffs_backend'
|
16
16
|
require 'riak/bucket'
|
17
|
+
require 'riak/bucket_type'
|
17
18
|
require 'riak/multiget'
|
18
19
|
require 'riak/secondary_index'
|
19
20
|
require 'riak/stamp'
|
@@ -131,6 +132,10 @@ module Riak
|
|
131
132
|
end
|
132
133
|
alias :[] :bucket
|
133
134
|
|
135
|
+
def bucket_type(name)
|
136
|
+
BucketType.new self, name
|
137
|
+
end
|
138
|
+
|
134
139
|
# Lists buckets which have keys stored in them.
|
135
140
|
# @note This is an expensive operation and should be used only
|
136
141
|
# in development.
|
@@ -369,9 +374,9 @@ module Riak
|
|
369
374
|
end
|
370
375
|
|
371
376
|
# Clears the properties on a bucket. See Bucket#clear_props
|
372
|
-
def clear_bucket_props(bucket)
|
377
|
+
def clear_bucket_props(bucket, options={ })
|
373
378
|
backend do |b|
|
374
|
-
b.reset_bucket_props(bucket)
|
379
|
+
b.reset_bucket_props(bucket, options)
|
375
380
|
end
|
376
381
|
end
|
377
382
|
|
data/lib/riak/crdt/base.rb
CHANGED
@@ -16,6 +16,22 @@ module Riak
|
|
16
16
|
# Riak-assigned key.
|
17
17
|
attr_reader :key
|
18
18
|
|
19
|
+
|
20
|
+
# Base CRDT initialization The bucket type is determined by the first of
|
21
|
+
# these sources:
|
22
|
+
#
|
23
|
+
# 1. The `bucket_type` String argument
|
24
|
+
# 2. A {BucketTyped::Bucket} as the `bucket` argument
|
25
|
+
# 3. A `bucket_type` Symbol argument is looked up in the
|
26
|
+
# `Crdt::Base::DEFAULT_BUCKET_TYPES` hash
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
# @param [Bucket] bucket the {Riak::Bucket} for this counter
|
30
|
+
# @param [String, nil] key The name of the counter. A nil key makes
|
31
|
+
# Riak assign a key.
|
32
|
+
# @param [String] bucket_type The optional bucket type for this counter.
|
33
|
+
# The default is in `Crdt::Base::DEFAULT_BUCKET_TYPES[:counter]`.
|
34
|
+
# @param [Hash] options
|
19
35
|
def initialize(bucket, key, bucket_type, options={})
|
20
36
|
raise ArgumentError, t("bucket_type", bucket: bucket.inspect) unless bucket.is_a? Bucket
|
21
37
|
|
@@ -25,7 +41,7 @@ module Riak
|
|
25
41
|
|
26
42
|
@bucket = bucket
|
27
43
|
@key = key
|
28
|
-
|
44
|
+
set_bucket_type bucket_type
|
29
45
|
@options = options
|
30
46
|
|
31
47
|
@dirty = true
|
@@ -132,6 +148,18 @@ module Riak
|
|
132
148
|
@dirty = false
|
133
149
|
end
|
134
150
|
end
|
151
|
+
|
152
|
+
def set_bucket_type(constructor_type)
|
153
|
+
@bucket_type = if constructor_type.is_a? String
|
154
|
+
constructor_type
|
155
|
+
elsif constructor_type.is_a? BucketType
|
156
|
+
constructor_type.name
|
157
|
+
elsif @bucket.is_a? BucketTyped::Bucket
|
158
|
+
@bucket.type.name
|
159
|
+
elsif constructor_type.is_a? Symbol
|
160
|
+
DEFAULT_BUCKET_TYPES[constructor_type]
|
161
|
+
end
|
162
|
+
end
|
135
163
|
end
|
136
164
|
end
|
137
165
|
end
|
data/lib/riak/crdt/counter.rb
CHANGED
@@ -6,8 +6,12 @@ module Riak
|
|
6
6
|
# Riak 1.4 Counters, see {Riak::Counter}.
|
7
7
|
class Counter < Base
|
8
8
|
|
9
|
-
# Create a counter instance.
|
10
|
-
#
|
9
|
+
# Create a counter instance. The bucket type is determined by the first of
|
10
|
+
# these sources:
|
11
|
+
#
|
12
|
+
# 1. The `bucket_type` String argument
|
13
|
+
# 2. A {BucketTyped::Bucket} as the `bucket` argument
|
14
|
+
# 3. The `Crdt::Base::DEFAULT_BUCKET_TYPES[:counter]` entry
|
11
15
|
#
|
12
16
|
# @param [Bucket] bucket the {Riak::Bucket} for this counter
|
13
17
|
# @param [String, nil] key The name of the counter. A nil key makes
|
@@ -16,7 +20,7 @@ module Riak
|
|
16
20
|
# The default is in `Crdt::Base::DEFAULT_BUCKET_TYPES[:counter]`.
|
17
21
|
# @param [Hash] options
|
18
22
|
def initialize(bucket, key, bucket_type=nil, options={})
|
19
|
-
super(bucket, key, bucket_type ||
|
23
|
+
super(bucket, key, bucket_type || :counter, options)
|
20
24
|
end
|
21
25
|
|
22
26
|
# The current value of the counter; hits the server if the value has
|
data/lib/riak/crdt/inner_flag.rb
CHANGED
data/lib/riak/crdt/map.rb
CHANGED
@@ -20,8 +20,12 @@ module Riak
|
|
20
20
|
class Map < Base
|
21
21
|
attr_reader :counters, :flags, :maps, :registers, :sets
|
22
22
|
|
23
|
-
# Create a map instance.
|
24
|
-
#
|
23
|
+
# Create a map instance. The bucket type is determined by the first of
|
24
|
+
# these sources:
|
25
|
+
#
|
26
|
+
# 1. The `bucket_type` String argument
|
27
|
+
# 2. A {BucketTyped::Bucket} as the `bucket` argument
|
28
|
+
# 3. The `Crdt::Base::DEFAULT_BUCKET_TYPES[:map]` entry
|
25
29
|
#
|
26
30
|
# @param bucket [Bucket] the {Riak::Bucket} for this map
|
27
31
|
# @param [String, nil] key The name of the map. A nil key makes
|
@@ -30,7 +34,7 @@ module Riak
|
|
30
34
|
# The default is in `Crdt::Base::DEFAULT_BUCKET_TYPES[:map]`.
|
31
35
|
# @param options [Hash]
|
32
36
|
def initialize(bucket, key, bucket_type=nil, options={})
|
33
|
-
super(bucket, key, bucket_type ||
|
37
|
+
super(bucket, key, bucket_type || :map, options)
|
34
38
|
|
35
39
|
if key
|
36
40
|
initialize_collections
|
data/lib/riak/crdt/set.rb
CHANGED
@@ -7,17 +7,20 @@ module Riak
|
|
7
7
|
# be used frequently.
|
8
8
|
class Set < Base
|
9
9
|
|
10
|
-
# Create a set instance.
|
11
|
-
#
|
10
|
+
# Create a set instance. The bucket type is determined by the first of
|
11
|
+
# these sources:
|
12
|
+
#
|
13
|
+
# 1. The `bucket_type` String argument
|
14
|
+
# 2. A {BucketTyped::Bucket} as the `bucket` argument
|
15
|
+
# 3. The `Crdt::Base::DEFAULT_BUCKET_TYPES[:set]` entry
|
12
16
|
#
|
13
17
|
# @param bucket [Bucket] the {Riak::Bucket} for this set
|
14
18
|
# @param [String, nil] key The name of the set. A nil key makes
|
15
19
|
# Riak assign a key.
|
16
20
|
# @param [String] bucket_type The optional bucket type for this set.
|
17
|
-
# The default is in `Crdt::Base::DEFAULT_BUCKET_TYPES[:set]`.
|
18
21
|
# @param options [Hash]
|
19
22
|
def initialize(bucket, key, bucket_type=nil, options={})
|
20
|
-
super(bucket, key, bucket_type ||
|
23
|
+
super(bucket, key, bucket_type || :set, options)
|
21
24
|
end
|
22
25
|
|
23
26
|
# Yields a `BatchSet` to proxy multiple set operations into a single
|
@@ -9,9 +9,11 @@ module Riak
|
|
9
9
|
|
10
10
|
# Exception raised when receiving an unexpected Protocol Buffers response from Riak
|
11
11
|
class ProtobuffsFailedRequest < FailedRequest
|
12
|
+
attr_reader :code, :original_message
|
12
13
|
def initialize(code, message)
|
13
14
|
super t('protobuffs_failed_request', :code => code, :body => message)
|
14
15
|
@original_message = message
|
16
|
+
@code = code
|
15
17
|
@not_found = code == :not_found
|
16
18
|
@server_error = code == :server_error
|
17
19
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'riak/errors/base'
|
2
|
+
|
3
|
+
module Riak
|
4
|
+
class SearchError < Error
|
5
|
+
class IndexExistsError < SearchError
|
6
|
+
def initialize(name)
|
7
|
+
super t('search.index_exists', name: name)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class SchemaExistsError < SearchError
|
12
|
+
def initialize(name)
|
13
|
+
super t('search.schema_exists', name: name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class IndexArgumentError < SearchError
|
18
|
+
def initialize(index)
|
19
|
+
super t('search.index_argument_error', index: index)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class IndexNonExistError < SearchError
|
24
|
+
def initialize(index)
|
25
|
+
super t('search.index_non_exist', index: index)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/riak/locale/en.yml
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
en:
|
2
2
|
riak:
|
3
|
+
argument_error:
|
4
|
+
bucket_type: "invalid argument %{bucket_type} is not a Riak::BucketType or a String"
|
3
5
|
backwards_clock: "System clock moved backwards, ID generation will fail for %{delay} more milliseconds."
|
4
6
|
bucket_link_conversion: "Can't convert a bucket link to a walk spec"
|
5
7
|
bucket_type: "invalid argument %{bucket} is not a Riak::Bucket"
|
@@ -68,6 +70,11 @@ en:
|
|
68
70
|
protobuffs_failed_request: "Expected success from Riak but received %{code}. %{body}"
|
69
71
|
protobuffs_configuration: "The %{backend} Protobuffs backend cannot be used. Please check its requirements."
|
70
72
|
request_body_type: "Request body must be a String or respond to :read."
|
73
|
+
search:
|
74
|
+
index_exists: "The index %{name} already exists."
|
75
|
+
index_non_exist: "The index %{index} doesn't exist."
|
76
|
+
index_argument_error: "invalid argument %{index} is not a Riak::Search::Index or a String"
|
77
|
+
schema_exists: "The schema %{name} already exists."
|
71
78
|
search_unsupported: "Riak server does not support search."
|
72
79
|
search_docs_require_id: "Search index documents must include the 'id' field."
|
73
80
|
search_remove_requires_id_or_query: "Search index documents to be removed must have 'id' or 'query' keys."
|
data/lib/riak/map_reduce.rb
CHANGED
@@ -4,6 +4,7 @@ require 'riak/json'
|
|
4
4
|
require 'riak/client'
|
5
5
|
require 'riak/bucket'
|
6
6
|
require 'riak/robject'
|
7
|
+
require 'riak/bucket_typed/bucket'
|
7
8
|
require 'riak/walk_spec'
|
8
9
|
require 'riak/errors/failed_request'
|
9
10
|
require 'riak/map_reduce_error'
|
@@ -68,23 +69,29 @@ module Riak
|
|
68
69
|
p = params.first
|
69
70
|
case p
|
70
71
|
when Bucket
|
71
|
-
|
72
|
-
@inputs = maybe_escape(p.name)
|
72
|
+
@inputs = bucket_input(p)
|
73
73
|
when RObject
|
74
|
-
@inputs <<
|
74
|
+
@inputs << robject_input(p)
|
75
75
|
when String
|
76
76
|
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
77
77
|
@inputs = maybe_escape(p)
|
78
78
|
end
|
79
79
|
when 2..3
|
80
80
|
bucket = params.shift
|
81
|
-
|
81
|
+
|
82
82
|
if Array === params.first
|
83
|
+
if bucket.is_a? Bucket
|
84
|
+
bucket = bucket_input(bucket)
|
85
|
+
else
|
86
|
+
bucket = maybe_escape(bucket)
|
87
|
+
end
|
88
|
+
|
83
89
|
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
84
|
-
@inputs = {:bucket =>
|
90
|
+
@inputs = {:bucket => bucket, :key_filters => params.first }
|
85
91
|
else
|
86
92
|
key = params.shift
|
87
|
-
|
93
|
+
key_data = params.shift || ''
|
94
|
+
@inputs << key_input(key, bucket, key_data)
|
88
95
|
end
|
89
96
|
end
|
90
97
|
self
|
@@ -222,5 +229,62 @@ module Riak
|
|
222
229
|
raise fr
|
223
230
|
end
|
224
231
|
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
# Processes a {Bucket} or {BucketTyped::Bucket} into a whole-bucket
|
236
|
+
# {MapReduce} input.
|
237
|
+
def bucket_input(bucket)
|
238
|
+
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
239
|
+
|
240
|
+
if bucket.needs_type?
|
241
|
+
return [maybe_escape(bucket.type.name), maybe_escape(bucket.name)]
|
242
|
+
end
|
243
|
+
|
244
|
+
maybe_escape(bucket.name)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Processes a {RObject} into a single-object {MapReduce} input, whether it
|
248
|
+
# has a bucket type or not.
|
249
|
+
def robject_input(obj, key_data='')
|
250
|
+
bucket = obj.bucket
|
251
|
+
if bucket.needs_type?
|
252
|
+
return [
|
253
|
+
maybe_escape(bucket.name),
|
254
|
+
maybe_escape(obj.key),
|
255
|
+
key_data,
|
256
|
+
maybe_escape(bucket.type.name)
|
257
|
+
]
|
258
|
+
end
|
259
|
+
|
260
|
+
[maybe_escape(obj.bucket.name), maybe_escape(obj.key)]
|
261
|
+
end
|
262
|
+
|
263
|
+
# Processes a key into a single-object {MapReduce} input, doing the correct
|
264
|
+
# thing if the bucket argument is a {String}, {Bucket}, or a
|
265
|
+
# {BucketTyped::Bucket}.
|
266
|
+
def key_input(key, bucket, key_data='')
|
267
|
+
kd = []
|
268
|
+
kd << key_data unless key_data.blank?
|
269
|
+
|
270
|
+
if bucket.is_a? String
|
271
|
+
return [
|
272
|
+
maybe_escape(bucket),
|
273
|
+
maybe_escape(key)
|
274
|
+
] + kd
|
275
|
+
elsif bucket.needs_type?
|
276
|
+
return [
|
277
|
+
maybe_escape(bucket.name),
|
278
|
+
maybe_escape(key),
|
279
|
+
key_data,
|
280
|
+
maybe_escape(bucket.type.name)
|
281
|
+
]
|
282
|
+
else
|
283
|
+
return [
|
284
|
+
maybe_escape(bucket.name),
|
285
|
+
maybe_escape(key)
|
286
|
+
] + kd
|
287
|
+
end
|
288
|
+
end
|
225
289
|
end
|
226
290
|
end
|