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.
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