rico 0.2.0 → 0.3.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/README.md +51 -9
- data/lib/rico.rb +38 -1
- data/lib/rico/array.rb +1 -51
- data/lib/rico/capped_sorted_map.rb +19 -0
- data/lib/rico/collection.rb +54 -0
- data/lib/rico/map.rb +52 -0
- data/lib/rico/object.rb +5 -7
- data/lib/rico/sorted_map.rb +13 -0
- data/lib/rico/version.rb +1 -1
- data/rico.gemspec +1 -1
- data/spec/array_spec.rb +7 -0
- data/spec/capped_sorted_map_spec.rb +36 -0
- data/spec/map_spec.rb +129 -0
- data/spec/sorted_map_spec.rb +22 -0
- data/spec/value_spec.rb +35 -0
- metadata +14 -4
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/jcoene/rico)
|
4
4
|
|
5
|
-
Rico provides
|
5
|
+
Rico provides simple data types persisted to Riak.
|
6
|
+
|
7
|
+
Supports Array, List, Set, SortedSet, Map, SortedMap, CappedSortedMap, Value objects.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -59,7 +61,7 @@ end
|
|
59
61
|
|
60
62
|
```ruby
|
61
63
|
a = Rico::Array.new "bucket", "key"
|
62
|
-
a.add
|
64
|
+
a.add 3, 1, 1, 4, 2
|
63
65
|
a.members # => [3, 1, 1, 4, 2]
|
64
66
|
a.length # => 5
|
65
67
|
```
|
@@ -68,7 +70,7 @@ a.length # => 5
|
|
68
70
|
|
69
71
|
```ruby
|
70
72
|
l = Rico::List.new "bucket", "key"
|
71
|
-
l.add
|
73
|
+
l.add 3, 1, 1, 4, 2
|
72
74
|
l.members # => [1, 1, 2, 3, 4]
|
73
75
|
l.length # => 5
|
74
76
|
```
|
@@ -77,7 +79,7 @@ l.length # => 5
|
|
77
79
|
|
78
80
|
```ruby
|
79
81
|
s = Rico::Set.new "bucket", "key"
|
80
|
-
s.add
|
82
|
+
s.add 3, 1, 1, 4, 2
|
81
83
|
s.members # => [3, 1, 4, 2]
|
82
84
|
s.length # => 4
|
83
85
|
```
|
@@ -86,11 +88,41 @@ s.length # => 4
|
|
86
88
|
|
87
89
|
```ruby
|
88
90
|
s = Rico::SortedSet.new "bucket", "key"
|
89
|
-
s.add
|
91
|
+
s.add 3, 1, 1, 4, 2
|
90
92
|
s.members # => [1, 2, 3, 4]
|
91
93
|
s.length # => 4
|
92
94
|
```
|
93
95
|
|
96
|
+
**Maps** - key-value mappings
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
m = Rico::Map.new "bucket", "key"
|
100
|
+
m.add({"a" => 1})
|
101
|
+
m.add({"b" => 2, "c" => 3})
|
102
|
+
m.members # => {"a" => 1, "b" => 2, "c" => 3}
|
103
|
+
m.length # => 3
|
104
|
+
```
|
105
|
+
|
106
|
+
**Sorted Maps** - key-value mappings sorted by key
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
m = Rico::SortedMap.new "bucket", "key"
|
110
|
+
m.add({"b" => 2, "c" => 3})
|
111
|
+
m.add({"a" => 1})
|
112
|
+
m.members # => {"a" => 1, "b" => 2, "c" => 3}
|
113
|
+
m.length # => 3
|
114
|
+
```
|
115
|
+
|
116
|
+
**Capped Sorted Maps** - key-value mappings sorted by key and bound by size
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
m = Rico::CappedSortedMap.new "bucket", "key", limit: 2
|
120
|
+
m.add({"b" => 2, "c" => 3})
|
121
|
+
m.add({"a" => 1})
|
122
|
+
m.members # => {"b" => 2, "c" => 3}
|
123
|
+
m.length # => 2
|
124
|
+
```
|
125
|
+
|
94
126
|
**Values** - generic serialized values
|
95
127
|
|
96
128
|
```ruby
|
@@ -102,16 +134,26 @@ v.get # => "bob"
|
|
102
134
|
v.exists? # => true
|
103
135
|
```
|
104
136
|
|
137
|
+
## Content Types
|
138
|
+
|
139
|
+
**JSON**: Objects are serialized and stored as JSON by default, using a Content-Type header of `application/json`
|
140
|
+
|
141
|
+
**JSON+gzip**: Objects can be serialized and stored as JSON and then compressed with gzip by specifying a Content-Type header of `application/x-json`. Note that it is not currently possible non-JSON data with the gzip content header using Rico.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
s = Rico::Set.new "bucket", "key"
|
145
|
+
s.content_type = "application/x-gzip"
|
146
|
+
s.add 1, 2, 3
|
147
|
+
s.get # => [1, 2, 3]
|
148
|
+
s.raw_data # => "\u001F\x8B\b\u0000G...."
|
149
|
+
```
|
150
|
+
|
105
151
|
## Notes
|
106
152
|
|
107
153
|
### Enumerable
|
108
154
|
|
109
155
|
Enumerable-looking types are indeed Enumerable
|
110
156
|
|
111
|
-
### Serialization
|
112
|
-
|
113
|
-
Data is serialized using the Riak client libary provided by Basho, which serializes values as JSON and sets a Content-Type value of "application/json"
|
114
|
-
|
115
157
|
### Persistence
|
116
158
|
|
117
159
|
Data is persisted at operation time. For example, List#add(5) will immediately update the record in Riak. It'd generally be wise to compute a list of values to be added or removed and then issue a single operation.
|
data/lib/rico.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
require "riak"
|
2
2
|
|
3
3
|
require "rico/object"
|
4
|
+
require "rico/collection"
|
5
|
+
|
6
|
+
require "rico/value"
|
4
7
|
|
5
8
|
require "rico/array"
|
6
9
|
require "rico/list"
|
7
10
|
require "rico/set"
|
8
11
|
require "rico/sorted_set"
|
9
|
-
|
12
|
+
|
13
|
+
require "rico/map"
|
14
|
+
require "rico/sorted_map"
|
15
|
+
require "rico/capped_sorted_map"
|
10
16
|
|
11
17
|
require "rico/resolver"
|
12
18
|
|
@@ -17,8 +23,10 @@ module Rico
|
|
17
23
|
TYPES = {
|
18
24
|
"Array" => "array",
|
19
25
|
"List" => "list",
|
26
|
+
"Map" => "map",
|
20
27
|
"Set" => "set",
|
21
28
|
"SortedSet" => "sset",
|
29
|
+
"SortedMap" => "smap",
|
22
30
|
"Value" => "value"
|
23
31
|
}
|
24
32
|
|
@@ -53,4 +61,33 @@ module Rico
|
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
64
|
+
module Riak
|
65
|
+
module Serializers
|
66
|
+
module ApplicationXGZIP
|
67
|
+
extend self
|
68
|
+
|
69
|
+
def dump(object)
|
70
|
+
json = ApplicationJSON.dump(object)
|
71
|
+
io = StringIO.new
|
72
|
+
gz = Zlib::GzipWriter.new(io)
|
73
|
+
gz.write(json)
|
74
|
+
gz.close
|
75
|
+
|
76
|
+
io.string
|
77
|
+
end
|
78
|
+
|
79
|
+
def load(string)
|
80
|
+
io = StringIO.new(string)
|
81
|
+
gz = Zlib::GzipReader.new(io)
|
82
|
+
json = gz.read
|
83
|
+
gz.close
|
84
|
+
|
85
|
+
ApplicationJSON.load(json)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Serializers['application/x-gzip'] = ApplicationXGZIP
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
56
93
|
Riak::RObject.on_conflict(&Rico::Resolver.to_proc)
|
data/lib/rico/array.rb
CHANGED
@@ -1,31 +1,8 @@
|
|
1
1
|
module Rico
|
2
|
-
class Array
|
3
|
-
include Rico::Object
|
4
|
-
include Enumerable
|
5
|
-
extend Forwardable
|
6
|
-
|
7
|
-
def_delegators :members, :each, :[], :length, :count
|
2
|
+
class Array < Collection
|
8
3
|
|
9
4
|
public
|
10
5
|
|
11
|
-
# Adds the requested items to the array and stores the object
|
12
|
-
#
|
13
|
-
# items - items to be added to the array
|
14
|
-
#
|
15
|
-
# Returns the result of the store operation
|
16
|
-
def add(*items)
|
17
|
-
mutate build_map_add(items)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Removes the requested items from the array and stores the object
|
21
|
-
#
|
22
|
-
# items - items to be removed from the array
|
23
|
-
#
|
24
|
-
# Returns the result of the store operation
|
25
|
-
def remove(*items)
|
26
|
-
mutate build_map_remove(items)
|
27
|
-
end
|
28
|
-
|
29
6
|
# Obtains the items in the array
|
30
7
|
#
|
31
8
|
# Returns the data in the object as an array
|
@@ -33,15 +10,6 @@ module Rico
|
|
33
10
|
Array((data || {})["_values"])
|
34
11
|
end
|
35
12
|
|
36
|
-
# Tests whether or not an item exists in the array
|
37
|
-
#
|
38
|
-
# item - item to test against
|
39
|
-
#
|
40
|
-
# Returns true or false
|
41
|
-
def member?(item)
|
42
|
-
members.include? item
|
43
|
-
end
|
44
|
-
|
45
13
|
# Resolve conflict between one or more RObject siblings
|
46
14
|
#
|
47
15
|
# robjects - array of RObjects to merge
|
@@ -64,23 +32,5 @@ module Rico
|
|
64
32
|
obj.data = { "_values" => result, "_deletes" => deletions }
|
65
33
|
obj
|
66
34
|
end
|
67
|
-
|
68
|
-
protected
|
69
|
-
|
70
|
-
def build_map_add(items)
|
71
|
-
{ "_type" => type_key, "_values" => compute_add(items) }
|
72
|
-
end
|
73
|
-
|
74
|
-
def build_map_remove(items)
|
75
|
-
{ "_type" => type_key, "_values" => compute_remove(items), "_deletes" => items }
|
76
|
-
end
|
77
|
-
|
78
|
-
def compute_add(items)
|
79
|
-
members + items
|
80
|
-
end
|
81
|
-
|
82
|
-
def compute_remove(items)
|
83
|
-
members - items
|
84
|
-
end
|
85
35
|
end
|
86
36
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rico
|
2
|
+
class CappedSortedMap < Map
|
3
|
+
attr_accessor :limit
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
def compute_add(items)
|
8
|
+
unless @limit
|
9
|
+
raise ArgumentError, "please specify a limit in item construction"
|
10
|
+
end
|
11
|
+
|
12
|
+
Hash[super(items).sort.pop(@limit)]
|
13
|
+
end
|
14
|
+
|
15
|
+
def compute_remove(items)
|
16
|
+
Hash[super(items).sort]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Rico
|
2
|
+
class Collection
|
3
|
+
include Rico::Object
|
4
|
+
include Enumerable
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :members, :each, :[], :length, :count
|
8
|
+
|
9
|
+
# Adds the requested items to the array and stores the object
|
10
|
+
#
|
11
|
+
# items - items to be added to the array
|
12
|
+
#
|
13
|
+
# Returns the result of the store operation
|
14
|
+
def add(*items)
|
15
|
+
mutate build_map_add(items)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Removes the requested items from the array and stores the object
|
19
|
+
#
|
20
|
+
# items - items to be removed from the array
|
21
|
+
#
|
22
|
+
# Returns the result of the store operation
|
23
|
+
def remove(*items)
|
24
|
+
mutate build_map_remove(items)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Tests whether or not an item exists in the array
|
28
|
+
#
|
29
|
+
# item - item to test against
|
30
|
+
#
|
31
|
+
# Returns true or false
|
32
|
+
def member?(item)
|
33
|
+
members.include? item
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def build_map_add(items)
|
39
|
+
{ "_type" => type_key, "_values" => compute_add(items) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_map_remove(items)
|
43
|
+
{ "_type" => type_key, "_values" => compute_remove(items), "_deletes" => items }
|
44
|
+
end
|
45
|
+
|
46
|
+
def compute_add(items)
|
47
|
+
members + items
|
48
|
+
end
|
49
|
+
|
50
|
+
def compute_remove(items)
|
51
|
+
members - items
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/rico/map.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rico
|
2
|
+
class Map < Collection
|
3
|
+
|
4
|
+
public
|
5
|
+
|
6
|
+
# Obtains the items in the array
|
7
|
+
#
|
8
|
+
# Returns the data in the object as an array
|
9
|
+
def members
|
10
|
+
((data || {})["_values"] || {})
|
11
|
+
end
|
12
|
+
|
13
|
+
# Resolve conflict between one or more RObject siblings
|
14
|
+
#
|
15
|
+
# robjects - array of RObjects to merge
|
16
|
+
#
|
17
|
+
# Returns a single RObject result or nil
|
18
|
+
def self.resolve(robject)
|
19
|
+
siblings = robject.siblings
|
20
|
+
values = siblings.map {|r| (r.data["_values"] || {}) }
|
21
|
+
deletions = siblings.map {|r| Array(r.data["_deletes"]) }.flatten
|
22
|
+
result = values.inject({}) {|res, h| res.merge(h) }.reject {|k,v| deletions.include? k }
|
23
|
+
|
24
|
+
obj = robject.dup
|
25
|
+
obj.siblings = [obj.siblings.first]
|
26
|
+
obj.data = { "_values" => result, "_deletes" => deletions }
|
27
|
+
obj
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def build_map_remove(items)
|
33
|
+
keys = extract_keys(items)
|
34
|
+
{ "_type" => type_key, "_values" => compute_remove(items), "_deletes" => keys }
|
35
|
+
end
|
36
|
+
|
37
|
+
def compute_add(items)
|
38
|
+
Array(items).inject(members) do |res, h|
|
39
|
+
res.merge(h)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def compute_remove(items)
|
44
|
+
keys = extract_keys(items)
|
45
|
+
members.delete_if {|k,v| keys.include? k.to_s }
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_keys(items)
|
49
|
+
Array(items).map {|i| i.respond_to?(:keys) ? i.keys : i }.flatten.map(&:to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rico/object.rb
CHANGED
@@ -2,7 +2,9 @@ module Rico
|
|
2
2
|
module Object
|
3
3
|
extend Forwardable
|
4
4
|
|
5
|
-
def_delegators :riak_object, :conflict?, :delete, :store
|
5
|
+
def_delegators :riak_object, :conflict?, :content_type, :content_type=, :data, :delete, :store, :raw_data
|
6
|
+
|
7
|
+
attr_accessor :bucket, :key
|
6
8
|
|
7
9
|
# Initialize an object with a bucket and key
|
8
10
|
#
|
@@ -10,12 +12,9 @@ module Rico
|
|
10
12
|
# key - the name of the key
|
11
13
|
#
|
12
14
|
# Returns nothing
|
13
|
-
def initialize(bucket, key)
|
15
|
+
def initialize(bucket, key, options={})
|
14
16
|
@bucket, @key = bucket, key
|
15
|
-
|
16
|
-
|
17
|
-
def data
|
18
|
-
@data ||= riak_object.data
|
17
|
+
options.each {|k,v| send("#{k}=", v)}
|
19
18
|
end
|
20
19
|
|
21
20
|
# Sets a new value on the object and stores it
|
@@ -24,7 +23,6 @@ module Rico
|
|
24
23
|
#
|
25
24
|
# Returns the result of the store operation
|
26
25
|
def mutate(value)
|
27
|
-
@data = value
|
28
26
|
riak_object.data = value
|
29
27
|
store
|
30
28
|
end
|
data/lib/rico/version.rb
CHANGED
data/rico.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/rico/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Jason Coene"]
|
6
6
|
gem.email = ["jcoene@gmail.com"]
|
7
|
-
gem.description = "
|
7
|
+
gem.description = "Simple data types persisted to Riak"
|
8
8
|
gem.summary = gem.description
|
9
9
|
gem.homepage = "https://github.com/jcoene/rico"
|
10
10
|
|
data/spec/array_spec.rb
CHANGED
@@ -13,6 +13,13 @@ describe Rico::Array do
|
|
13
13
|
b.members.should eql [1, 2, 3]
|
14
14
|
end
|
15
15
|
|
16
|
+
it "retains a single value as an array" do
|
17
|
+
a = Rico::Array.new RiakHelpers.bucket, "add_flattens_values"
|
18
|
+
a.add([1, 2, 3])
|
19
|
+
b = Rico::Array.new RiakHelpers.bucket, "add_flattens_values"
|
20
|
+
b.members.should eql [[1, 2, 3]]
|
21
|
+
end
|
22
|
+
|
16
23
|
it "allows duplicate values" do
|
17
24
|
a = Rico::Array.new RiakHelpers.bucket, "add_allows_duplicates"
|
18
25
|
a.add(1, 2, 3)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rico::CappedSortedMap do
|
4
|
+
before :each do
|
5
|
+
RiakHelpers.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
let :test_map do
|
9
|
+
values = 900.upto(999).map {|i| [i.to_s, i] }
|
10
|
+
Hash[values.shuffle]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#add" do
|
14
|
+
it "sorts and caps in instance" do
|
15
|
+
a = Rico::CappedSortedMap.new RiakHelpers.bucket, "capped_sorted_map_add_1", limit: 34
|
16
|
+
a.add(test_map)
|
17
|
+
a.members.length.should eql 34
|
18
|
+
Array(a.members).first.should eql(["966", 966])
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sort and cap is retained on read" do
|
22
|
+
a = Rico::CappedSortedMap.new RiakHelpers.bucket, "capped_sorted_map_add_1", limit: 34
|
23
|
+
a.add(test_map)
|
24
|
+
a.members.length.should eql 34
|
25
|
+
Array(a.members).first.should eql(["966", 966])
|
26
|
+
b = Rico::CappedSortedMap.new RiakHelpers.bucket, "capped_sorted_map_add_1"
|
27
|
+
b.members.length.should eql 34
|
28
|
+
Array(b.members).first.should eql(["966", 966])
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises an error if a limit is not set" do
|
32
|
+
a = Rico::CappedSortedMap.new RiakHelpers.bucket, "capped_sorted_map_add_1"
|
33
|
+
lambda { a.add({"a" => 1}) }.should raise_error(ArgumentError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/map_spec.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rico::Map do
|
4
|
+
before :each do
|
5
|
+
RiakHelpers.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#add" do
|
9
|
+
it "writes a single hash to the map" do
|
10
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_add_single_hash"
|
11
|
+
a.add({"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5})
|
12
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_add_single_hash"
|
13
|
+
b.members.should eql({"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5})
|
14
|
+
end
|
15
|
+
|
16
|
+
it "writes multiple hashes to the map" do
|
17
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_add_multiple_hashes"
|
18
|
+
a.add({"a" => 1, "b" => 2, "c" => 3}, {"d" => 4, "e" => 5})
|
19
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_add_multiple_hashes"
|
20
|
+
b.members.should eql({"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5})
|
21
|
+
end
|
22
|
+
|
23
|
+
it "supports multiple multiple writes to the map" do
|
24
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_add_multiple_writes"
|
25
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
26
|
+
a.add({"d" => 4, "e" => 5})
|
27
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_add_multiple_writes"
|
28
|
+
b.members.should eql({"a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#remove" do
|
33
|
+
it "removes a single key by string" do
|
34
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_string"
|
35
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
36
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_string"
|
37
|
+
b.remove("a")
|
38
|
+
c = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_string"
|
39
|
+
c.members.should eql({"b" => 2, "c" => 3})
|
40
|
+
end
|
41
|
+
|
42
|
+
it "removes multiple keys by string" do
|
43
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_string"
|
44
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
45
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_string"
|
46
|
+
b.remove("a", "c")
|
47
|
+
c = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_string"
|
48
|
+
c.members.should eql({"b" => 2})
|
49
|
+
end
|
50
|
+
|
51
|
+
it "removes multiple keys by symbol" do
|
52
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_symbol"
|
53
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
54
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_symbol"
|
55
|
+
b.remove(:a, :c)
|
56
|
+
c = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_symbol"
|
57
|
+
c.members.should eql({"b" => 2})
|
58
|
+
end
|
59
|
+
|
60
|
+
it "removes multiple keys by integer" do
|
61
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_integer"
|
62
|
+
a.add({1 => 1, 2 => 2, 3 => 3})
|
63
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_integer"
|
64
|
+
b.remove(1, 3)
|
65
|
+
c = Rico::Map.new RiakHelpers.bucket, "map_remove_multiple_keys_integer"
|
66
|
+
c.members.should eql({"2" => 2})
|
67
|
+
end
|
68
|
+
|
69
|
+
it "removes multiple keys by map tuples" do
|
70
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_tuple"
|
71
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
72
|
+
b = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_tuple"
|
73
|
+
b.remove({"a" => 1})
|
74
|
+
c = Rico::Map.new RiakHelpers.bucket, "map_remove_single_key_tuple"
|
75
|
+
c.members.should eql({"b" => 2, "c" => 3})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#length" do
|
80
|
+
it "returns zero for an empty list" do
|
81
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_length_empty"
|
82
|
+
a.length.should eql 0
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns the number of entries" do
|
86
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_length_6"
|
87
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
88
|
+
a.length.should eql 3
|
89
|
+
end
|
90
|
+
|
91
|
+
it "is aliased to #count" do
|
92
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_length_alias"
|
93
|
+
a.add({"a" => 1, "b" => 2, "c" => 3})
|
94
|
+
a.count.should eql 3
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe ".resolve" do
|
99
|
+
it "properly resolves missing values" do
|
100
|
+
datas = [
|
101
|
+
{ "_type" => "map", "_values" => {"a" => 11, "b" => 12} },
|
102
|
+
{ "_type" => "map", "_values" => {"a" => 11, "b" => 12, "c" => 13} }
|
103
|
+
]
|
104
|
+
conflicted = RiakHelpers.build_conflicted_robject "map_resolve_simple", datas
|
105
|
+
result = Rico::Map.resolve(conflicted)
|
106
|
+
result.data["_values"].should eql({"a" => 11, "b" => 12, "c" => 13})
|
107
|
+
end
|
108
|
+
|
109
|
+
it "properly deletes deleted values after resolve" do
|
110
|
+
datas = [
|
111
|
+
{ "_type" => "map", "_values" => {"a" => 11, "b" => 12, "c" => 13} },
|
112
|
+
{ "_type" => "map", "_values" => {"a" => 11, "b" => 12}, "_deletes" => ["c"] }
|
113
|
+
]
|
114
|
+
conflicted = RiakHelpers.build_conflicted_robject "map_resolve_delete", datas
|
115
|
+
result = Rico::Map.resolve(conflicted)
|
116
|
+
result.data["_values"].should eql({"a" => 11, "b" => 12})
|
117
|
+
result.data["_deletes"].should eql ["c"]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "is enumerable" do
|
122
|
+
a = Rico::Map.new RiakHelpers.bucket, "map_enumerable"
|
123
|
+
a.add({"a" => 1, "b" => 2})
|
124
|
+
a.to_a.should eql [["a", 1], ["b", 2]]
|
125
|
+
a.each { }.length.should eql 2
|
126
|
+
a.map {|k,v| v + 1 }.should eql [2, 3]
|
127
|
+
a["b"].should eql 2
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rico::SortedMap do
|
4
|
+
before :each do
|
5
|
+
RiakHelpers.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#add" do
|
9
|
+
it "sorts in instance" do
|
10
|
+
a = Rico::SortedMap.new RiakHelpers.bucket, "sorted_map_add_1"
|
11
|
+
a.add({"x" => 1, "4" => 2, "a" => 3})
|
12
|
+
a.members.should eql({"4" => 2, "a" => 3, "x" => 1})
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sort is retained on read" do
|
16
|
+
a = Rico::SortedMap.new RiakHelpers.bucket, "sorted_map_add_2"
|
17
|
+
a.add({"x" => 1, "4" => 2, "a" => 3})
|
18
|
+
b = Rico::SortedMap.new RiakHelpers.bucket, "sorted_map_add_2"
|
19
|
+
b.members.should eql({"4" => 2, "a" => 3, "x" => 1})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/value_spec.rb
CHANGED
@@ -5,6 +5,41 @@ describe Rico::Value do
|
|
5
5
|
RiakHelpers.reset!
|
6
6
|
end
|
7
7
|
|
8
|
+
def gunzip(string)
|
9
|
+
io = StringIO.new(string)
|
10
|
+
gz = Zlib::GzipReader.new(io)
|
11
|
+
object = gz.read
|
12
|
+
gz.close
|
13
|
+
object
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "gzip serialization" do
|
17
|
+
it "sets the content type of gzip objects" do
|
18
|
+
a = Rico::Value.new RiakHelpers.bucket, "value_gzip_content_type"
|
19
|
+
a.content_type = "application/x-gzip"
|
20
|
+
a.set "JOHN DOE"
|
21
|
+
a.content_type.should eql "application/x-gzip"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "properly serializes of gzip objects" do
|
25
|
+
a = Rico::Value.new RiakHelpers.bucket, "value_gzip_content_type"
|
26
|
+
a.content_type = "application/x-gzip"
|
27
|
+
a.set "JOHN DOE"
|
28
|
+
gunzip(a.raw_data).should eql "\"JOHN DOE\""
|
29
|
+
a.content_type.should eql "application/x-gzip"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "retrieves the content type of persisted gzip objects" do
|
33
|
+
a = Rico::Value.new RiakHelpers.bucket, "value_gzip_content_type_2"
|
34
|
+
a.content_type = "application/x-gzip"
|
35
|
+
a.set "JOHN DOE"
|
36
|
+
|
37
|
+
b = Rico::Value.new RiakHelpers.bucket, "value_gzip_content_type_2"
|
38
|
+
b.content_type.should eql "application/x-gzip"
|
39
|
+
b.get.should eql "JOHN DOE"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
8
43
|
describe "#exists?" do
|
9
44
|
it "returns true if it exists" do
|
10
45
|
a = Rico::Value.new RiakHelpers.bucket, "value_exists_true"
|
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.
|
4
|
+
version: 0.3.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-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: riak-client
|
@@ -75,7 +75,7 @@ dependencies:
|
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '2.3'
|
78
|
-
description:
|
78
|
+
description: Simple data types persisted to Riak
|
79
79
|
email:
|
80
80
|
- jcoene@gmail.com
|
81
81
|
executables: []
|
@@ -92,20 +92,27 @@ files:
|
|
92
92
|
- Rakefile
|
93
93
|
- lib/rico.rb
|
94
94
|
- lib/rico/array.rb
|
95
|
+
- lib/rico/capped_sorted_map.rb
|
96
|
+
- lib/rico/collection.rb
|
95
97
|
- lib/rico/counter.rb
|
96
98
|
- lib/rico/list.rb
|
99
|
+
- lib/rico/map.rb
|
97
100
|
- lib/rico/object.rb
|
98
101
|
- lib/rico/resolver.rb
|
99
102
|
- lib/rico/set.rb
|
103
|
+
- lib/rico/sorted_map.rb
|
100
104
|
- lib/rico/sorted_set.rb
|
101
105
|
- lib/rico/value.rb
|
102
106
|
- lib/rico/version.rb
|
103
107
|
- rico.gemspec
|
104
108
|
- spec/array_spec.rb
|
109
|
+
- spec/capped_sorted_map_spec.rb
|
105
110
|
- spec/list_spec.rb
|
111
|
+
- spec/map_spec.rb
|
106
112
|
- spec/resolver_spec.rb
|
107
113
|
- spec/rico_spec.rb
|
108
114
|
- spec/set_spec.rb
|
115
|
+
- spec/sorted_map_spec.rb
|
109
116
|
- spec/sorted_set_spec.rb
|
110
117
|
- spec/spec_helper.rb
|
111
118
|
- spec/value_spec.rb
|
@@ -132,13 +139,16 @@ rubyforge_project:
|
|
132
139
|
rubygems_version: 1.8.23
|
133
140
|
signing_key:
|
134
141
|
specification_version: 3
|
135
|
-
summary:
|
142
|
+
summary: Simple data types persisted to Riak
|
136
143
|
test_files:
|
137
144
|
- spec/array_spec.rb
|
145
|
+
- spec/capped_sorted_map_spec.rb
|
138
146
|
- spec/list_spec.rb
|
147
|
+
- spec/map_spec.rb
|
139
148
|
- spec/resolver_spec.rb
|
140
149
|
- spec/rico_spec.rb
|
141
150
|
- spec/set_spec.rb
|
151
|
+
- spec/sorted_map_spec.rb
|
142
152
|
- spec/sorted_set_spec.rb
|
143
153
|
- spec/spec_helper.rb
|
144
154
|
- spec/value_spec.rb
|