rico 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec CHANGED
@@ -1 +1 @@
1
- --color
1
+ --tty --color --format nested
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard "rspec" do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1].split("/").last}_spec.rb" }
4
+ watch("spec/spec_helper.rb") { "spec" }
5
+ end
data/lib/rico/array.rb CHANGED
@@ -4,7 +4,7 @@ module Rico
4
4
  include Enumerable
5
5
  extend Forwardable
6
6
 
7
- def_delegators :members, :each, :[]
7
+ def_delegators :members, :each, :[], :length, :count
8
8
 
9
9
  public
10
10
 
@@ -14,7 +14,7 @@ module Rico
14
14
  #
15
15
  # Returns the result of the store operation
16
16
  def add(*items)
17
- mutate compute_add(items)
17
+ mutate build_map_add(items)
18
18
  end
19
19
 
20
20
  # Removes the requested items from the array and stores the object
@@ -23,14 +23,14 @@ module Rico
23
23
  #
24
24
  # Returns the result of the store operation
25
25
  def remove(*items)
26
- mutate compute_remove(items)
26
+ mutate build_map_remove(items)
27
27
  end
28
28
 
29
29
  # Obtains the items in the array
30
30
  #
31
31
  # Returns the data in the object as an array
32
32
  def members
33
- Array(data)
33
+ Array((data || {})["_values"])
34
34
  end
35
35
 
36
36
  # Tests whether or not an item exists in the array
@@ -42,16 +42,38 @@ module Rico
42
42
  members.include? item
43
43
  end
44
44
 
45
- # Returns the number of items in the array
45
+ # Resolve conflict between one or more RObject siblings
46
46
  #
47
- # Returns an Integer
48
- def length
49
- members.length
47
+ # robjects - array of RObjects to merge
48
+ #
49
+ # Returns a single RObject result or nil
50
+ def self.resolve(robject)
51
+ siblings = robject.siblings
52
+ values = siblings.map {|r| Array(r.data["_values"]) }
53
+ deletions = siblings.map {|r| Array(r.data["_deletes"]) }.flatten
54
+
55
+ result = []
56
+ values.each do |v|
57
+ result += (v - result)
58
+ end
59
+
60
+ result -= deletions
61
+
62
+ obj = Riak::RObject.new(robject.bucket, robject.key)
63
+ obj.data = { "_values" => result, "_deletes" => deletions }
64
+ obj
50
65
  end
51
- alias_method :count, :length
52
66
 
53
67
  protected
54
68
 
69
+ def build_map_add(items)
70
+ { "_type" => type_key, "_values" => compute_add(items) }
71
+ end
72
+
73
+ def build_map_remove(items)
74
+ { "_type" => type_key, "_values" => compute_remove(items), "_deletes" => items }
75
+ end
76
+
55
77
  def compute_add(items)
56
78
  members + items
57
79
  end
data/lib/rico/object.rb CHANGED
@@ -2,7 +2,7 @@ module Rico
2
2
  module Object
3
3
  extend Forwardable
4
4
 
5
- def_delegators :riak_object, :store, :delete
5
+ def_delegators :riak_object, :conflict?, :delete, :store
6
6
 
7
7
  # Initialize an object with a bucket and key
8
8
  #
@@ -26,7 +26,7 @@ module Rico
26
26
  def mutate(value)
27
27
  @data = value
28
28
  riak_object.data = value
29
- riak_object.store
29
+ store
30
30
  end
31
31
 
32
32
  # Determine whether an object exists or not
@@ -38,6 +38,11 @@ module Rico
38
38
 
39
39
  protected
40
40
 
41
+ def type_key
42
+ name = self.class.name.split("::").last
43
+ Rico::TYPES[name]
44
+ end
45
+
41
46
  def riak_object
42
47
  @riak_object ||= Rico.bucket(@bucket).get_or_new @key
43
48
  end
@@ -0,0 +1,18 @@
1
+ module Rico
2
+ class Resolver
3
+ def self.to_proc
4
+ @to_proc ||= lambda do |robject|
5
+ klasses = robject.siblings.map{|s| s.data && s.data["_type"] }.compact.uniq
6
+ return nil unless klasses.length == 1
7
+
8
+ klass_name = Rico::TYPES.invert[klasses.first]
9
+ return nil unless klass_name
10
+
11
+ klass = Rico.const_get(klass_name)
12
+ return nil unless klass.respond_to?(:resolve)
13
+
14
+ klass.resolve(robject.siblings)
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/rico/value.rb CHANGED
@@ -20,12 +20,25 @@ module Rico
20
20
  #
21
21
  # Returns true if stored, false if not
22
22
  def setnx(value)
23
- if redis_object.exists?
23
+ if exists?
24
24
  false
25
25
  else
26
26
  set value
27
27
  true
28
28
  end
29
29
  end
30
+
31
+ # Resolve conflict between one or more RObject siblings
32
+ #
33
+ # This currently just returns the first sibling
34
+ #
35
+ # robjects - array of RObjects to resolve
36
+ #
37
+ # Returns a single RObject result or nil
38
+ def self.resolve(robject)
39
+ obj = Riak::RObject.new(robject.bucket, robject.key)
40
+ obj.data = robject.siblings.first.data
41
+ obj
42
+ end
30
43
  end
31
44
  end
data/lib/rico/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rico
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/rico.rb CHANGED
@@ -8,10 +8,20 @@ require "rico/set"
8
8
  require "rico/sorted_set"
9
9
  require "rico/value"
10
10
 
11
+ require "rico/resolver"
12
+
11
13
  require "rico/version"
12
14
 
13
15
  module Rico
14
16
 
17
+ TYPES = {
18
+ "Array" => "array",
19
+ "List" => "list",
20
+ "Set" => "set",
21
+ "SortedSet" => "sset",
22
+ "Value" => "value"
23
+ }
24
+
15
25
  def self.configure
16
26
  yield self if block_given?
17
27
  end
@@ -38,3 +48,5 @@ module Rico
38
48
  @riak = riak
39
49
  end
40
50
  end
51
+
52
+ Riak::RObject.on_conflict(&Rico::Resolver.to_proc)
data/rico.gemspec CHANGED
@@ -17,4 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency "riak-client", "~> 1.1"
19
19
  gem.add_development_dependency "rspec", "~> 2.12"
20
+ gem.add_development_dependency "guard-rspec", "~> 2.3"
20
21
  end
data/spec/array_spec.rb CHANGED
@@ -133,6 +133,29 @@ describe Rico::Array do
133
133
  end
134
134
  end
135
135
 
136
+ describe ".resolve" do
137
+ it "properly resolves missing values" do
138
+ datas = [
139
+ { "_type" => "array", "_values" => [1,2,3] },
140
+ { "_type" => "array", "_values" => [1,2,3,4] }
141
+ ]
142
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_simple", datas
143
+ result = Rico::Array.resolve(conflicted)
144
+ result.data["_values"].should eql [1,2,3,4]
145
+ end
146
+
147
+ it "properly deletes deleted values after resolve" do
148
+ datas = [
149
+ { "_type" => "array", "_values" => [1,2,3,4] },
150
+ { "_type" => "array", "_values" => [1,2,3], "_deletes" => [4] }
151
+ ]
152
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_delete", datas
153
+ result = Rico::Array.resolve(conflicted)
154
+ result.data["_values"].should eql [1,2,3]
155
+ result.data["_deletes"].should eql [4]
156
+ end
157
+ end
158
+
136
159
  it "is enumerable" do
137
160
  a = Rico::Array.new RiakHelpers.bucket, "enumerable"
138
161
  a.add(3, 1, 4, 1, 5, 9)
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe Rico::Resolver do
4
+ describe ".to_proc" do
5
+ it "returns nil for data without type" do
6
+ datas = [
7
+ { "a" => "b" },
8
+ { "c" => "d" },
9
+ { "f" => "e" }
10
+ ]
11
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_no_type", datas
12
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
13
+ end
14
+
15
+ it "returns nil for data with conflicted types" do
16
+ datas = [
17
+ { "_type" => "array", "_values" => [1,2,3,4,1] },
18
+ { "_type" => "set", "_values" => [1,2,3,4] }
19
+ ]
20
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_conflicted_types", datas
21
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
22
+ end
23
+
24
+ it "returns nil for data without a known rico class" do
25
+ datas = [
26
+ { "_type" => "unknown", "_values" => [1,2,3] },
27
+ { "_type" => "unknown", "_values" => [1,2,3,4] }
28
+ ]
29
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_unknown_type", datas
30
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
31
+ end
32
+
33
+ it "returns the result of the resolve function on known types" do
34
+ datas = [
35
+ { "_type" => "array", "_values" => [1,2,3] },
36
+ { "_type" => "array", "_values" => [1,2,3,4] }
37
+ ]
38
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_no_resolve_function", datas
39
+
40
+ Rico::Array.stub(:resolve).and_return(conflicted.siblings.last)
41
+ Rico::Resolver.to_proc.call(conflicted).should eql conflicted.siblings.last
42
+ Rico::Array.unstub(:resolve)
43
+ end
44
+ end
45
+ end
data/spec/spec_helper.rb CHANGED
@@ -17,5 +17,30 @@ module RiakHelpers
17
17
  b.keys.each do |k|
18
18
  b.delete k
19
19
  end
20
+
21
+ a = Rico::Array.new bucket, "visual_array"
22
+ a.add 1,2,3,4,5,6
23
+ a.remove 6
24
+ end
25
+
26
+ def self.build_conflicted_robject(key, values)
27
+ bucket = Rico.bucket RiakHelpers.bucket
28
+ o = Riak::RObject.new bucket, key
29
+ siblings = values.map do |v|
30
+ x = Riak::RObject.new bucket, key
31
+ x.data = v
32
+ x
33
+ end
34
+
35
+ o = Riak::RObject.new bucket, key
36
+ o.siblings = siblings
37
+ o
38
+ end
39
+
40
+ def self.build_conflicted_rico_object(klass, key, values=["v1", "v2", "v3"])
41
+ o = build_conflicted_robject key, values
42
+ v = klass.new RiakHelpers.bucket, key
43
+ v.instance_variable_set("@riak_object", o)
44
+ v
20
45
  end
21
46
  end
data/spec/value_spec.rb CHANGED
@@ -42,6 +42,25 @@ describe Rico::Value do
42
42
  end
43
43
  end
44
44
 
45
+ describe "#setnx" do
46
+ it "writes the value, returns true if new" do
47
+ a = Rico::Value.new RiakHelpers.bucket, "setnx_new"
48
+ a.setnx("value").should eql true
49
+ b = Rico::Value.new RiakHelpers.bucket, "setnx_new"
50
+ b.get.should eql "value"
51
+ end
52
+
53
+ it "does nothing, returns false if the value exists" do
54
+ a = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
55
+ a.set "value"
56
+ b = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
57
+ b.setnx("other").should eql false
58
+ b.get.should eql "value"
59
+ c = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
60
+ c.get.should eql "value"
61
+ end
62
+ end
63
+
45
64
  describe "#delete" do
46
65
  it "deletes an existing object" do
47
66
  a = Rico::Value.new RiakHelpers.bucket, "delete_existing"
@@ -52,4 +71,25 @@ describe Rico::Value do
52
71
  b.get.should eql nil
53
72
  end
54
73
  end
74
+
75
+ describe ".resolve" do
76
+ it "just returns the first sibling" do
77
+ datas = ["Tom", "Jerry"]
78
+ conflicted = RiakHelpers.build_conflicted_robject "value_resolve_simple", datas
79
+ result = Rico::Value.resolve(conflicted)
80
+ result.data.should eql "Tom"
81
+ end
82
+
83
+ it "properly deletes deleted values after resolve" do
84
+ datas = [
85
+ { "_type" => "array", "_values" => [1,2,3,4] },
86
+ { "_type" => "array", "_values" => [1,2,3], "_deletes" => [4] }
87
+ ]
88
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_delete", datas
89
+ result = Rico::Array.resolve(conflicted)
90
+ result.data["_values"].should eql [1,2,3]
91
+ result.data["_deletes"].should eql [4]
92
+ end
93
+ end
94
+
55
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rico
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.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: 2012-12-09 00:00:00.000000000 Z
12
+ date: 2012-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: riak-client
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: '2.12'
46
+ - !ruby/object:Gem::Dependency
47
+ name: guard-rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
46
62
  description: Primative data types on Riak
47
63
  email:
48
64
  - jcoene@gmail.com
@@ -53,6 +69,7 @@ files:
53
69
  - .gitignore
54
70
  - .rspec
55
71
  - Gemfile
72
+ - Guardfile
56
73
  - LICENSE
57
74
  - README.md
58
75
  - Rakefile
@@ -61,6 +78,7 @@ files:
61
78
  - lib/rico/counter.rb
62
79
  - lib/rico/list.rb
63
80
  - lib/rico/object.rb
81
+ - lib/rico/resolver.rb
64
82
  - lib/rico/set.rb
65
83
  - lib/rico/sorted_set.rb
66
84
  - lib/rico/value.rb
@@ -68,6 +86,7 @@ files:
68
86
  - rico.gemspec
69
87
  - spec/array_spec.rb
70
88
  - spec/list_spec.rb
89
+ - spec/resolver_spec.rb
71
90
  - spec/rico_spec.rb
72
91
  - spec/set_spec.rb
73
92
  - spec/sorted_set_spec.rb
@@ -100,6 +119,7 @@ summary: Primative data types on Riak
100
119
  test_files:
101
120
  - spec/array_spec.rb
102
121
  - spec/list_spec.rb
122
+ - spec/resolver_spec.rb
103
123
  - spec/rico_spec.rb
104
124
  - spec/set_spec.rb
105
125
  - spec/sorted_set_spec.rb