canery 0.1.3 → 0.1.4
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 +5 -2
- data/lib/canery/backend.rb +17 -10
- data/lib/canery/client.rb +11 -9
- data/lib/canery/tub.rb +15 -14
- data/lib/canery/version.rb +1 -1
- data/spec/canery_tub_spec.rb +9 -0
- data/spec/spec_helper.rb +4 -0
- metadata +4 -4
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Canery
|
2
|
-
Canery is a simple and easy to use key/value store with several commands to store and retrieve data.
|
2
|
+
Canery is a simple and easy to use key/value store with several commands to store and retrieve data. Canery uses [Sequel](https://github.com/jeremyevans/sequel/) for persistence, so it can be used in virtually any environment where a SQL database is available. (For more information about the available database adapters please check out the appropriate section in the Sequel documentation.)
|
3
3
|
|
4
4
|
## Installation
|
5
5
|
gem install canery
|
@@ -29,6 +29,9 @@ Canery provides a simple and understandable API which is a bit inspired by Redis
|
|
29
29
|
|
30
30
|
# Get this complex value
|
31
31
|
store.get("demo_hash") # => {:first_name => "John", :last_name => "Doe"}
|
32
|
+
|
33
|
+
# If you set nil as key, Canery builds a uuid-key for you
|
34
|
+
store.set(nil, "oh my god, no key given!") # => "2cf7541a-00c1-4bda-8c75-fc32a5f5fac7"
|
32
35
|
|
33
36
|
For more information consider the wiki. (Comming soon... I promise!)
|
34
37
|
|
@@ -37,7 +40,7 @@ Due to the nature of SQL databases it's (almost) impossible for Canery to be as
|
|
37
40
|
|
38
41
|
## Information about data types
|
39
42
|
### Keys & Tub names
|
40
|
-
Theoretically every string can be used as a key/tub name, from a string like "foo" to the content of a
|
43
|
+
Theoretically every string can be used as a key/tub name, from a string like "foo" to the serialized content of a PNG file. Even an empty string is a valid key/tub name. But for better performance the max key size defaults to 255 characters.
|
41
44
|
|
42
45
|
Please keep in mind that Canery uses strings for all keys/tub names, so any other data type will be converted to a string!
|
43
46
|
|
data/lib/canery/backend.rb
CHANGED
@@ -11,10 +11,18 @@ module Canery
|
|
11
11
|
|
12
12
|
def initialize(connection_uri)
|
13
13
|
raise ArgumentError, "connection_uri must be a String or nil" unless NilClass === connection_uri || String === connection_uri
|
14
|
+
|
14
15
|
@connection = connection_uri.nil? ? Sequel.sqlite : Sequel.connect(connection_uri)
|
15
16
|
@namespace_cache = {}
|
16
17
|
end
|
17
18
|
|
19
|
+
# Only expose call method
|
20
|
+
def call(command, *args)
|
21
|
+
self.send(command, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
18
26
|
# Basic namespace methods #
|
19
27
|
###########################
|
20
28
|
|
@@ -41,8 +49,8 @@ module Canery
|
|
41
49
|
def namespace?(name)
|
42
50
|
connection.table_exists?(basic_tub_name(name))
|
43
51
|
end
|
44
|
-
|
45
|
-
|
52
|
+
|
53
|
+
|
46
54
|
# Methods for get, set, etc. #
|
47
55
|
##############################
|
48
56
|
|
@@ -55,14 +63,14 @@ module Canery
|
|
55
63
|
raise ArgumentError, "keys argument must be an Array of keys" unless Array === keys
|
56
64
|
keys.map!{ |key| build_key(key) }
|
57
65
|
|
58
|
-
# Sort data in the order they appear in the 'keys' Array
|
66
|
+
# Sort the data in the order they appear in the 'keys' Array
|
59
67
|
namespace(name).where(:key => keys).sort_by { |element| keys.index(element[:key]) }.map {|dataset| load(dataset[:value]) }
|
60
68
|
end
|
61
69
|
|
62
70
|
def set(name, key, value)
|
63
71
|
begin
|
64
72
|
namespace(name).insert(:key => build_key(key), :value => dump(value)) && build_key(key)
|
65
|
-
rescue Sequel::DatabaseError #
|
73
|
+
rescue Sequel::DatabaseError # key already exists, use update instead
|
66
74
|
update(name, key, value)
|
67
75
|
rescue
|
68
76
|
"ERROR"
|
@@ -74,7 +82,7 @@ module Canery
|
|
74
82
|
begin
|
75
83
|
namespace(name).multi_insert(data.map{ |key, value| {:key => build_key(key), :value => dump(value)} }) && "OK"
|
76
84
|
rescue
|
77
|
-
# Fallback to the
|
85
|
+
# Fallback to the O(n) update method
|
78
86
|
data.each do |key, value|
|
79
87
|
update(name, key, value)
|
80
88
|
end && "OK"
|
@@ -116,7 +124,7 @@ module Canery
|
|
116
124
|
end
|
117
125
|
|
118
126
|
unless limit.nil?
|
119
|
-
raise ArgumentError, "limit must be
|
127
|
+
raise ArgumentError, "limit parameter must be an Integer" unless Integer === limit
|
120
128
|
data = data.limit(limit)
|
121
129
|
end
|
122
130
|
data.map{ |dataset| dataset[:key] }
|
@@ -126,13 +134,12 @@ module Canery
|
|
126
134
|
namespace(name).where(:key => build_key(old_key)).limit(1).update(:key => build_key(new_key)) && "OK"
|
127
135
|
end
|
128
136
|
|
129
|
-
def
|
137
|
+
def count(name)
|
130
138
|
namespace(name).count
|
131
139
|
end
|
132
140
|
|
133
|
-
|
134
|
-
|
135
|
-
# Sequel seems to have problems with escaping, so we use Base64 encoding/decoding as a simple work around
|
141
|
+
# Sequel seems to have problems with escaping,
|
142
|
+
# therefore we use Base64 encoding/decoding as a simple work around
|
136
143
|
def load(data)
|
137
144
|
Marshal.load(Base64.urlsafe_decode64(data))
|
138
145
|
end
|
data/lib/canery/client.rb
CHANGED
@@ -14,27 +14,29 @@ module Canery
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def tub(name)
|
17
|
-
|
17
|
+
build_tub_name!(name)
|
18
|
+
create_tub(name) unless tub?(name)
|
18
19
|
begin
|
19
20
|
@tub_cache ||= {}
|
20
|
-
@tub_cache[
|
21
|
+
@tub_cache[name] ||= Tub.new(backend, name)
|
21
22
|
rescue
|
22
23
|
raise Canery::CaneryError, "This tub does not exist! You must create it before you can use it."
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
27
|
def delete_tub(name)
|
27
|
-
|
28
|
-
|
28
|
+
build_tub_name!(name)
|
29
|
+
@tub_cache.delete(name) if @tub_cache[name]
|
30
|
+
backend.call(:delete_namespace, name)
|
29
31
|
end
|
30
32
|
|
31
33
|
def has_tub?(name)
|
32
|
-
backend.namespace
|
34
|
+
backend.call(:namespace?, name)
|
33
35
|
end
|
34
36
|
alias :tub? :has_tub?
|
35
37
|
|
36
38
|
def tubs
|
37
|
-
backend.namespaces
|
39
|
+
backend.call(:namespaces)
|
38
40
|
end
|
39
41
|
|
40
42
|
private
|
@@ -45,14 +47,14 @@ module Canery
|
|
45
47
|
|
46
48
|
def create_tub(name)
|
47
49
|
begin
|
48
|
-
backend.create_namespace
|
50
|
+
backend.call(:create_namespace, name)
|
49
51
|
rescue => exception
|
50
52
|
raise Canery::CaneryError, exception
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
55
|
-
name.to_s.strip
|
56
|
+
def build_tub_name!(name)
|
57
|
+
name.to_s.strip!
|
56
58
|
end
|
57
59
|
|
58
60
|
end
|
data/lib/canery/tub.rb
CHANGED
@@ -14,60 +14,61 @@ module Canery
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def get(key)
|
17
|
-
backend.get
|
17
|
+
backend.call(:get, name, key)
|
18
18
|
end
|
19
19
|
alias :[] :get
|
20
20
|
|
21
21
|
def mget(keys)
|
22
|
-
backend.mget
|
22
|
+
backend.call(:mget, name, keys)
|
23
23
|
end
|
24
24
|
|
25
25
|
def set(key, value)
|
26
|
-
backend.set
|
26
|
+
backend.call(:set, name, key || uuid, value)
|
27
27
|
end
|
28
28
|
alias :[]= :set
|
29
29
|
|
30
30
|
def mset(data)
|
31
|
-
backend.mset
|
31
|
+
backend.call(:mset, name, data)
|
32
32
|
end
|
33
33
|
|
34
34
|
def delete(key)
|
35
|
-
backend.delete
|
35
|
+
backend.call(:delete, name, key)
|
36
36
|
end
|
37
37
|
|
38
38
|
def clear
|
39
|
-
backend.clear
|
39
|
+
backend.call(:clear, name)
|
40
40
|
end
|
41
41
|
|
42
42
|
def has_key?(key)
|
43
|
-
backend.has_key
|
43
|
+
backend.call(:has_key?, name, key)
|
44
44
|
end
|
45
45
|
alias :key? :has_key?
|
46
46
|
|
47
47
|
def keys
|
48
|
-
backend.keys
|
48
|
+
backend.call(:keys, name)
|
49
49
|
end
|
50
50
|
|
51
51
|
def values
|
52
|
-
backend.values
|
52
|
+
backend.call(:values, name)
|
53
53
|
end
|
54
54
|
|
55
55
|
def sort(order, limit = nil)
|
56
56
|
begin
|
57
|
-
backend.sort
|
58
|
-
rescue ArgumentError
|
59
|
-
raise Canery::CaneryError,
|
57
|
+
backend.call(:sort, name, order, limit)
|
58
|
+
rescue ArgumentError => e
|
59
|
+
raise Canery::CaneryError, e
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
def rename(old_key, new_key)
|
64
|
-
backend.rename
|
64
|
+
backend.call(:rename, name, old_key, new_key)
|
65
65
|
end
|
66
66
|
|
67
67
|
def length
|
68
|
-
backend.
|
68
|
+
backend.call(:count, name)
|
69
69
|
end
|
70
70
|
alias :size :length
|
71
|
+
alias :count :length
|
71
72
|
|
72
73
|
private
|
73
74
|
|
data/lib/canery/version.rb
CHANGED
data/spec/canery_tub_spec.rb
CHANGED
@@ -73,6 +73,15 @@ describe Canery::Tub do
|
|
73
73
|
store.get(key).should == value
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
it "should overwrite alread set values" do
|
78
|
+
store = @client.tub("store")
|
79
|
+
store.mset(demo_hash).should == "OK"
|
80
|
+
store.mset(second_demo_hash).should == "OK"
|
81
|
+
second_demo_hash.each do |key, value|
|
82
|
+
store.get(key).should == value
|
83
|
+
end
|
84
|
+
end
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
data/spec/spec_helper.rb
CHANGED
@@ -6,4 +6,8 @@ end
|
|
6
6
|
|
7
7
|
def demo_hash
|
8
8
|
{"homer" => "Homer Simpson", "marge" => "Marge Simpson", "lisa" => "Lisa Simpson", "bart" => "Bart Simpson", "maggy" => "Maggy Simpson"}
|
9
|
+
end
|
10
|
+
|
11
|
+
def second_demo_hash
|
12
|
+
{"homer" => "Simpson Homer", "marge" => "Simpson Marge", "lisa" => "Simpson Lisa", "bart" => "Simpson Bart", "maggy" => "Simpson Maggy"}
|
9
13
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
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-08-
|
12
|
+
date: 2012-08-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sequel
|
@@ -94,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
94
|
version: '0'
|
95
95
|
segments:
|
96
96
|
- 0
|
97
|
-
hash: -
|
97
|
+
hash: -3305371081524146636
|
98
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
99
|
none: false
|
100
100
|
requirements:
|
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
103
|
version: '0'
|
104
104
|
segments:
|
105
105
|
- 0
|
106
|
-
hash: -
|
106
|
+
hash: -3305371081524146636
|
107
107
|
requirements: []
|
108
108
|
rubyforge_project:
|
109
109
|
rubygems_version: 1.8.24
|