riak-client 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
  gem 'bundler'
@@ -9,7 +9,7 @@ group :guard do
9
9
  gem 'rb-fsevent'
10
10
  gem 'growl'
11
11
  end
12
-
12
+
13
13
  platforms :mri do
14
14
  gem 'yajl-ruby'
15
15
  end
@@ -1,5 +1,27 @@
1
1
  # Riak Ruby Client Release Notes
2
2
 
3
+ ## 1.2.0 Feature Release - 2013-05-15
4
+
5
+ Release 1.2.0 adds support for Riak 1.3 and fixes a number of bugs.
6
+
7
+ Features:
8
+
9
+ * The "clear bucket properties" feature has been added. This resets
10
+ modified bucket properties to the defaults on Riak 1.3+ clusters.
11
+ * Anonymous "strfun" MapReduce functions written in Erlang can now be
12
+ sent from the client, if they are enabled on the server-side.
13
+
14
+ Bugfixes:
15
+
16
+ * The WalkSpec class now properly includes the Translation module.
17
+ * The Protocol Buffers transport now extracts the bucket name before
18
+ submitting secondary index queries.
19
+ * Search query results returned over PBC are assumed to be UTF-8
20
+ encoded.
21
+ * The newer Excon API is now supported (>= 0.19.0).
22
+ * When enabling the search commit hook, the 'precommit' property will
23
+ now be checked more safely.
24
+
3
25
  ## 1.1.1 Patch/Bugfix Release - 2013-01-10
4
26
 
5
27
  Release 1.1.1 fixes a minor bug with Net::HTTP on Ruby 1.8.7 with
@@ -78,6 +78,15 @@ module Riak
78
78
  end
79
79
  alias :properties :props
80
80
 
81
+ # Clears bucket properties, reverting them to the defaults.
82
+ # @return [true, false] whether the properties were cleared
83
+ # @since Riak 1.3
84
+ def clear_props
85
+ @props = nil
86
+ @client.clear_bucket_props(self)
87
+ end
88
+ alias :clear_properties :clear_props
89
+
81
90
  # Retrieve an object from within the bucket.
82
91
  # @param [String] key the key of the object to retrieve
83
92
  # @param [Hash] options query parameters for the request
@@ -205,7 +214,7 @@ module Riak
205
214
  # riak_search.
206
215
  # @return [true,false] whether the bucket includes the search indexing hook
207
216
  def is_indexed?
208
- props['search'] == true || props['precommit'].include?(SEARCH_PRECOMMIT_HOOK)
217
+ props['search'] == true || (props.has_key?('precommit') && props['precommit'].include?(SEARCH_PRECOMMIT_HOOK))
209
218
  end
210
219
 
211
220
  # @return [String] a representation suitable for IRB and debugging output
@@ -469,6 +469,13 @@ module Riak
469
469
  end
470
470
  end
471
471
 
472
+ # Clears the properties on a bucket. See Bucket#clear_props
473
+ def clear_bucket_props(bucket)
474
+ http do |b|
475
+ b.clear_bucket_props(bucket)
476
+ end
477
+ end
478
+
472
479
  # Enables or disables SSL on all nodes, for HTTP backends.
473
480
  def ssl=(value)
474
481
  @nodes.each do |node|
@@ -126,6 +126,7 @@ module Riak
126
126
 
127
127
  def get_index(bucket, index, query)
128
128
  return super unless pb_indexes?
129
+ bucket = bucket.name if Bucket === bucket
129
130
  if Range === query
130
131
  options = {
131
132
  :qtype => RpbIndexReq::IndexQueryType::RANGE,
@@ -218,7 +219,12 @@ module Riak
218
219
  end
219
220
 
220
221
  def decode_doc(doc)
221
- Hash[doc.properties.map {|p| [ p.key, p.value ] }]
222
+ Hash[doc.properties.map {|p| [ force_utf8(p.key), force_utf8(p.value) ] }]
223
+ end
224
+
225
+ def force_utf8(str)
226
+ # Search returns strings that should always be valid UTF-8
227
+ ObjectMethods::ENCODING ? str.force_encoding('UTF-8') : str
222
228
  end
223
229
  end
224
230
  end
@@ -150,12 +150,22 @@ module Riak
150
150
  end
151
151
 
152
152
  def connection
153
- @connection ||= Excon::Connection.new(
154
- root_uri.to_s,
155
- :read_timeout => self.class.read_timeout,
153
+ @connection ||= new_connection
154
+ end
155
+
156
+ def new_connection
157
+ params = { :read_timeout => self.class.read_timeout,
156
158
  :write_timeout => self.class.write_timeout,
157
- :connect_timeout => self.class.connect_timeout
158
- )
159
+ :connect_timeout => self.class.connect_timeout }
160
+ args = [ params ]
161
+ if self.class.minimum_version?("0.19.0")
162
+ params.merge!(:scheme => root_uri.scheme,
163
+ :host => root_uri.host,
164
+ :port => root_uri.port)
165
+ else
166
+ args.unshift root_uri.to_s
167
+ end
168
+ Excon::Connection.new(*args)
159
169
  end
160
170
  end
161
171
  end
@@ -13,7 +13,8 @@ module Riak
13
13
  VERSION = {
14
14
  1 => Gem::Version.new("1.0.0"),
15
15
  1.1 => Gem::Version.new("1.1.0"),
16
- 1.2 => Gem::Version.new("1.2.0")
16
+ 1.2 => Gem::Version.new("1.2.0"),
17
+ 1.3 => Gem::Version.new("1.3.0")
17
18
  }.freeze
18
19
 
19
20
  # @return [String] the version of the Riak node
@@ -71,6 +72,12 @@ module Riak
71
72
  at_least? VERSION[1]
72
73
  end
73
74
 
75
+ # @return [true,false] whether bucket properties can be cleared
76
+ # (reset to defaults) over HTTP
77
+ def http_props_clearable?
78
+ at_least? VERSION[1.3]
79
+ end
80
+
74
81
  protected
75
82
  # @return [true,false] whether the server version is the same or
76
83
  # newer than the requested version
@@ -133,6 +133,22 @@ module Riak
133
133
  put(204, bucket_properties_path(bucket), body, {"Content-Type" => "application/json"})
134
134
  end
135
135
 
136
+ # Clears bucket properties
137
+ # @param [Bucket, String] bucket the bucket to clear properties
138
+ # on
139
+ # @return [true, false] whether the operation succeeded
140
+ # @note false will be returned if the operation is not supported
141
+ # on the connected node
142
+ def clear_bucket_props(bucket)
143
+ if http_props_clearable?
144
+ bucket = bucket.name if Bucket === bucket
145
+ delete(204, bucket_properties_path(bucket))
146
+ true
147
+ else
148
+ false
149
+ end
150
+ end
151
+
136
152
  # List keys in a bucket
137
153
  # @param [Bucket, String] bucket the bucket to fetch the keys
138
154
  # for
@@ -53,7 +53,7 @@ module Riak
53
53
  raise ArgumentError, t("stored_function_invalid") unless type == :link || value.has_key?(:bucket) && value.has_key?(:key)
54
54
  @language = "javascript"
55
55
  when String
56
- @language = "javascript"
56
+ @language = (value =~ /\s*fun\s*\(.*\)\s*->/) ? "erlang" : "javascript"
57
57
  when WalkSpec
58
58
  raise ArgumentError, t("walk_spec_invalid_unless_link") unless type == :link
59
59
  else
@@ -78,7 +78,7 @@ module Riak
78
78
  when Hash
79
79
  defaults.merge(function)
80
80
  when String
81
- if function =~ /\s*function/
81
+ if function =~ /\s*function\s*\(/ || function =~ /\s*fun\s*\(.*\)\s*->/
82
82
  defaults.merge("source" => function)
83
83
  else
84
84
  defaults.merge("name" => function)
@@ -1,3 +1,3 @@
1
1
  module Riak
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -12,6 +12,7 @@ module Riak
12
12
  # Riak::WalkSpec.new({:bucket => 'tracks', :result => true})
13
13
  class WalkSpec
14
14
  include Util::Translation
15
+ extend Util::Translation
15
16
  include Util::Escape
16
17
 
17
18
  # @return [String] The bucket followed links should be restricted to. "_" represents all buckets.
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.authors = ["Sean Cribbs"]
13
13
 
14
14
  # Deps
15
- gem.add_development_dependency "rspec", "~>2.10.0"
15
+ gem.add_development_dependency "rspec", "~>2.13.0"
16
16
  gem.add_development_dependency "fakeweb", ">=1.2"
17
17
  gem.add_development_dependency "rack", ">=1.0"
18
18
  gem.add_development_dependency "excon", ">=0.6.1"
@@ -37,6 +37,21 @@ describe "HTTP" do
37
37
  end
38
38
  end
39
39
 
40
+ context "clearing bucket properties" do
41
+ it "should return false when unsupported", :version => "< 1.3.0" do
42
+ @backend.clear_bucket_props('foo').should be_false
43
+ end
44
+
45
+ it "should reset a previously set property to the default", :version => ">= 1.3.0" do
46
+ bucket = @client['bucketpropscleartest']
47
+ original_n = @backend.get_bucket_props(bucket)['n_val']
48
+ @backend.set_bucket_props(bucket, {'n_val' => 2})
49
+ @backend.get_bucket_props(bucket)['n_val'].should == 2
50
+ @backend.clear_bucket_props(bucket)
51
+ @backend.get_bucket_props(bucket)['n_val'].should == original_n
52
+ end
53
+ end
54
+
40
55
  context "using Luwak", :version => "< 1.1.0" do
41
56
  let(:file) { File.open(__FILE__) }
42
57
  let(:key) { "spec.rb" }
@@ -30,6 +30,20 @@ describe "Protocol Buffers" do
30
30
  results['docs'].should include({"id" => "munchausen-605"})
31
31
  end
32
32
  end
33
+
34
+ if "".respond_to?(:encoding) # Ruby 1.9 and later only
35
+ describe "searching fulltext indexes (1.2 and later)", :version => '>= 1.2.0' do
36
+ include_context "search corpus setup"
37
+
38
+ it 'should return documents with UTF-8 fields (GH #75)' do
39
+ utf8 = Encoding.find('UTF-8')
40
+ results = @backend.search 'search_test', 'fearless elephant rushed'
41
+ results['docs'].each do |d|
42
+ d.each {|(k,v)| k.encoding.should == utf8; v.encoding.should == utf8 }
43
+ end
44
+ end
45
+ end
46
+ end
33
47
  end
34
48
  end
35
49
  end
@@ -86,6 +86,14 @@ describe Riak::Bucket do
86
86
  end
87
87
  end
88
88
 
89
+ describe "clearing the bucket properties" do
90
+ it "should make the request and delete the internal properties cache" do
91
+ @client.should_receive(:clear_bucket_props).with(@bucket).and_return(true)
92
+ @bucket.clear_props.should be_true
93
+ @bucket.instance_variable_get(:@props).should be_nil
94
+ end
95
+ end
96
+
89
97
  describe "fetching an object" do
90
98
  it "should fetch the object via the backend" do
91
99
  @backend.should_receive(:fetch_object).with(@bucket, "db", {}).and_return(nil)
@@ -24,6 +24,7 @@ describe Riak::Client::FeatureDetection do
24
24
  it { should_not be_quorum_controls }
25
25
  it { should_not be_tombstone_vclocks }
26
26
  it { should_not be_pb_head }
27
+ it { should_not be_http_props_clearable }
27
28
  end
28
29
 
29
30
  context "when the Riak version is 1.0.x" do
@@ -35,6 +36,7 @@ describe Riak::Client::FeatureDetection do
35
36
  it { should be_quorum_controls }
36
37
  it { should be_tombstone_vclocks }
37
38
  it { should be_pb_head }
39
+ it { should_not be_http_props_clearable }
38
40
  end
39
41
 
40
42
  context "when the Riak version is 1.1.x" do
@@ -46,10 +48,11 @@ describe Riak::Client::FeatureDetection do
46
48
  it { should be_quorum_controls }
47
49
  it { should be_tombstone_vclocks }
48
50
  it { should be_pb_head }
51
+ it { should_not be_http_props_clearable }
49
52
  end
50
53
 
51
54
  context "when the Riak version is 1.2.x" do
52
- before { subject.stub!(:get_server_version).and_return("1.2.0") }
55
+ before { subject.stub!(:get_server_version).and_return("1.2.1") }
53
56
  it { should be_mapred_phaseless }
54
57
  it { should be_pb_indexes }
55
58
  it { should be_pb_search }
@@ -57,5 +60,18 @@ describe Riak::Client::FeatureDetection do
57
60
  it { should be_quorum_controls }
58
61
  it { should be_tombstone_vclocks }
59
62
  it { should be_pb_head }
63
+ it { should_not be_http_props_clearable }
64
+ end
65
+
66
+ context "when the Riak version is 1.3.x" do
67
+ before { subject.stub!(:get_server_version).and_return("1.3.0") }
68
+ it { should be_mapred_phaseless }
69
+ it { should be_pb_indexes }
70
+ it { should be_pb_search }
71
+ it { should be_pb_conditionals }
72
+ it { should be_quorum_controls }
73
+ it { should be_tombstone_vclocks }
74
+ it { should be_pb_head }
75
+ it { should be_http_props_clearable }
60
76
  end
61
77
  end
@@ -2,13 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe Riak::MapReduce::Phase do
4
4
  before :each do
5
- @fun = "function(v,_,_){ return v['values'][0]['data']; }"
5
+ @js_fun = "function(v,_,_){ return v['values'][0]['data']; }"
6
+ @erl_fun = "fun(Obj, _KeyData, _Arg) -> [{riak_object:key(Obj), riak_object:get_value(Obj)}] end."
6
7
  end
7
8
 
8
9
  it "should initialize with a type and a function" do
9
- phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun, :language => "javascript")
10
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @js_fun, :language => "javascript")
10
11
  phase.type.should == :map
11
- phase.function.should == @fun
12
+ phase.function.should == @js_fun
12
13
  phase.language.should == "javascript"
13
14
  end
14
15
 
@@ -31,11 +32,16 @@ describe Riak::MapReduce::Phase do
31
32
  phase.language.should == "erlang"
32
33
  end
33
34
 
34
- it "should assume the language is javascript when the function is a string" do
35
- phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun)
35
+ it "should assume the language is javascript when the function is a string and starts with function" do
36
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @js_fun)
36
37
  phase.language.should == "javascript"
37
38
  end
38
39
 
40
+ it "should assume the language is erlang when the function is a string and starts with anon fun" do
41
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @erl_fun)
42
+ phase.language.should == "erlang"
43
+ end
44
+
39
45
  it "should assume the language is javascript when the function is a hash" do
40
46
  phase = Riak::MapReduce::Phase.new(:type => :map, :function => {:bucket => "jobs", :key => "awesome_map"})
41
47
  phase.language.should == "javascript"
@@ -101,6 +101,10 @@ describe Riak::WalkSpec do
101
101
  specs.should be_all {|s| s.kind_of?(Riak::WalkSpec) }
102
102
  specs.join("/").should == "_,next,_/foo,_,_/_,child,1"
103
103
  end
104
+
105
+ it "should raise an error when given invalid number of parameters" do
106
+ expect { Riak::WalkSpec.normalize("foo") }.to raise_error(ArgumentError)
107
+ end
104
108
  end
105
109
 
106
110
  describe "matching other objects with ===" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riak-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-10 00:00:00.000000000 Z
12
+ date: 2013-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 2.10.0
21
+ version: 2.13.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 2.10.0
29
+ version: 2.13.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: fakeweb
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -329,12 +329,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
329
329
  - - ! '>='
330
330
  - !ruby/object:Gem::Version
331
331
  version: '0'
332
+ segments:
333
+ - 0
334
+ hash: 20034304450029998
332
335
  required_rubygems_version: !ruby/object:Gem::Requirement
333
336
  none: false
334
337
  requirements:
335
338
  - - ! '>='
336
339
  - !ruby/object:Gem::Version
337
340
  version: '0'
341
+ segments:
342
+ - 0
343
+ hash: 20034304450029998
338
344
  requirements: []
339
345
  rubyforge_project:
340
346
  rubygems_version: 1.8.23