riak-client 2.1.0 → 2.2.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Guardfile +15 -9
  4. data/README.markdown +118 -9
  5. data/lib/riak/bucket.rb +16 -1
  6. data/lib/riak/bucket_properties.rb +67 -0
  7. data/lib/riak/bucket_type.rb +48 -0
  8. data/lib/riak/bucket_typed/bucket.rb +113 -0
  9. data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
  10. data/lib/riak/client/beefcake/message_overlay.rb +42 -20
  11. data/lib/riak/client/beefcake/object_methods.rb +1 -1
  12. data/lib/riak/client/beefcake/socket.rb +6 -6
  13. data/lib/riak/client/beefcake_protobuffs_backend.rb +44 -60
  14. data/lib/riak/client/protobuffs_backend.rb +8 -8
  15. data/lib/riak/client.rb +7 -2
  16. data/lib/riak/crdt/base.rb +29 -1
  17. data/lib/riak/crdt/counter.rb +7 -3
  18. data/lib/riak/crdt/inner_flag.rb +1 -1
  19. data/lib/riak/crdt/map.rb +7 -3
  20. data/lib/riak/crdt/set.rb +7 -4
  21. data/lib/riak/errors/failed_request.rb +2 -0
  22. data/lib/riak/errors/search_error.rb +29 -0
  23. data/lib/riak/locale/en.yml +7 -0
  24. data/lib/riak/map_reduce.rb +70 -6
  25. data/lib/riak/robject.rb +19 -3
  26. data/lib/riak/search/index.rb +73 -0
  27. data/lib/riak/search/query.rb +133 -0
  28. data/lib/riak/search/result_collection.rb +91 -0
  29. data/lib/riak/search/result_document.rb +59 -0
  30. data/lib/riak/search/schema.rb +65 -0
  31. data/lib/riak/search.rb +10 -0
  32. data/lib/riak/secondary_index.rb +6 -0
  33. data/lib/riak/version.rb +1 -1
  34. data/spec/fixtures/yz_schema_template.xml +18 -0
  35. data/spec/integration/riak/bucket_types_spec.rb +218 -39
  36. data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
  37. data/spec/integration/riak/crdt_spec.rb +30 -2
  38. data/spec/integration/riak/properties_spec.rb +69 -0
  39. data/spec/integration/riak/search_spec.rb +104 -0
  40. data/spec/integration/riak/secondary_index_spec.rb +18 -0
  41. data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
  42. data/spec/riak/bucket_properties_spec.rb +114 -0
  43. data/spec/riak/bucket_type_spec.rb +34 -0
  44. data/spec/riak/bucket_typed/bucket.rb +43 -0
  45. data/spec/riak/client_spec.rb +16 -8
  46. data/spec/riak/crdt/counter_spec.rb +2 -1
  47. data/spec/riak/crdt/map_spec.rb +2 -1
  48. data/spec/riak/crdt/set_spec.rb +2 -1
  49. data/spec/riak/map_reduce_spec.rb +169 -124
  50. data/spec/riak/search/index_spec.rb +62 -0
  51. data/spec/riak/search/query_spec.rb +88 -0
  52. data/spec/riak/search/result_collection_spec.rb +87 -0
  53. data/spec/riak/search/result_document_spec.rb +63 -0
  54. data/spec/riak/search/schema_spec.rb +63 -0
  55. data/spec/spec_helper.rb +2 -1
  56. data/spec/support/search_config.rb +81 -0
  57. data/spec/support/test_client.yml +14 -7
  58. 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
@@ -88,7 +88,7 @@ module Riak
88
88
 
89
89
  def encode_index(key, set)
90
90
  set.map do |v|
91
- RpbPair.new(:key => maybe_encode(key),
91
+ RpbPair.new(:key => maybe_encode(key.to_s),
92
92
  :value => maybe_encode(v.to_s))
93
93
  end
94
94
  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
- bucket = bucket.name if Bucket === bucket
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
- bucket = bucket.name if Bucket === bucket
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(:bucket => maybe_encode(bucket))
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
- resp = protocol do |p|
369
- p.write :YokozunaIndexGetReq, req
370
- p.expect :YokozunaIndexGetResp, RpbYokozunaIndexGetResp, empty_body_acceptable: true
371
- end
372
-
373
- if :empty == resp
374
- raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
375
- end
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
- if resp.index && Array === resp
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
- resp = protocol do |p|
408
- p.write :YokozunaSchemaGetReq, req
409
- p.expect :YokozunaSchemaGetResp, RpbYokozunaSchemaGetResp
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
 
@@ -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
- @bucket_type = bucket_type
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
@@ -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. If not provided, the default bucket type
10
- # from {Riak::Crdt} will be used.
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 || DEFAULT_BUCKET_TYPES[:counter], options)
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
@@ -6,7 +6,7 @@ module Riak
6
6
  #
7
7
  # @api private
8
8
  class InnerFlag
9
- def self.new(parent, value)
9
+ def self.new(parent, value=false)
10
10
  ensure_boolean value
11
11
 
12
12
  return value
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. If not provided, the default bucket type
24
- # from {Riak::Crdt} will be used.
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 || DEFAULT_BUCKET_TYPES[:map], options)
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. If not provided, the default bucket type from
11
- # {Riak::Crdt} will be used.
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 || DEFAULT_BUCKET_TYPES[:set], options)
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
@@ -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."
@@ -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
- warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
72
- @inputs = maybe_escape(p.name)
72
+ @inputs = bucket_input(p)
73
73
  when RObject
74
- @inputs << [maybe_escape(p.bucket.name), maybe_escape(p.key)]
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
- bucket = bucket.name if Bucket === bucket
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 => maybe_escape(bucket), :key_filters => params.first }
90
+ @inputs = {:bucket => bucket, :key_filters => params.first }
85
91
  else
86
92
  key = params.shift
87
- @inputs << params.unshift(maybe_escape(key)).unshift(maybe_escape(bucket))
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