rico 0.0.1 → 0.1.0
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.
- data/.rspec +1 -1
- data/Guardfile +5 -0
- data/lib/rico/array.rb +31 -9
- data/lib/rico/object.rb +7 -2
- data/lib/rico/resolver.rb +18 -0
- data/lib/rico/value.rb +14 -1
- data/lib/rico/version.rb +1 -1
- data/lib/rico.rb +12 -0
- data/rico.gemspec +1 -0
- data/spec/array_spec.rb +23 -0
- data/spec/resolver_spec.rb +45 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/value_spec.rb +40 -0
- metadata +22 -2
data/.rspec
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--color
|
1
|
+
--tty --color --format nested
|
data/Guardfile
ADDED
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
|
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
|
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
|
-
#
|
45
|
+
# Resolve conflict between one or more RObject siblings
|
46
46
|
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
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, :
|
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
|
-
|
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
|
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
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
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
|
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-
|
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
|