relix 1.5.0 → 2.0.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.
- checksums.yaml +8 -8
- data/HISTORY.md +7 -0
- data/README.md +20 -0
- data/lib/relix.rb +1 -0
- data/lib/relix/core.rb +4 -0
- data/lib/relix/index.rb +1 -0
- data/lib/relix/index_set.rb +20 -5
- data/lib/relix/indexes/multi.rb +33 -2
- data/lib/relix/query.rb +2 -2
- data/lib/relix/redis.rb +7 -1
- data/lib/relix/version.rb +40 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MjY4Y2ExMjRhYTk5MTJjYjUyYTUwZjE4NWUxZDlmOGEwNGU5YWJjYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjA5NGFhODZhODYyYzZjZjA3MmU1ODA5YTkyM2Q2YWM4ZGZkNjJlYw==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Yzg0NzA4YjczZTI0YzJkZmE2NTJlNzA1NWNkNWJkZTEyNzIzYTU1MjYzYjgz
|
10
|
+
YWQyYjQ2NjA0MzJmZThjMzJjYTY3YmYyNjZhNGRjYzFhNzhlNmViYWU3ODFl
|
11
|
+
ZDAwY2Y2OTc4NzFlMzVmNDlhYTMwMDI5ZGI4ZTE3ZGMwZDEwYTI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDA1ZTZjMDMxMzliMDIyZjZmZjIxZjk3MTYxOTAzYTk1NjhjODJiYzFiOTAx
|
14
|
+
NmZlMDQ4Y2JlNGIzN2RiMTI2MDk3MDM2ODg0NjI0OTg1YmExN2E0NDlmN2Yy
|
15
|
+
NjQyN2RkYjEzNTQ2YzA2NmIxMjIxMWVkMzE5NjE4ZDg0Y2M3MTk=
|
data/HISTORY.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 2.0.0
|
2
|
+
|
3
|
+
* Require Redis 2.6. (ntalbott)
|
4
|
+
* Add deprecation support. (ntalbott)
|
5
|
+
* Add proper API for accessing indexes by name. (ntalbott)
|
6
|
+
* Add lookup of multi index values. (ntalbott)
|
7
|
+
|
1
8
|
### 1.5.0
|
2
9
|
|
3
10
|
* Add special handling for interrogative methods. (ntalbott)
|
data/README.md
CHANGED
@@ -36,6 +36,8 @@ You can configure the Redis host, port and db like so:
|
|
36
36
|
Relix.port = 10000
|
37
37
|
Relix.db = 5
|
38
38
|
|
39
|
+
Relix requires Redis 2.6 or later.
|
40
|
+
|
39
41
|
|
40
42
|
## Usage
|
41
43
|
|
@@ -209,6 +211,24 @@ Multi indexes allow multiple matching primary keys per indexed value, and are id
|
|
209
211
|
**Supported Operators**: eq
|
210
212
|
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
211
213
|
|
214
|
+
#### Values
|
215
|
+
|
216
|
+
If you declare the correct option, it's possible to pull the set of values that are being indexed on as well:
|
217
|
+
|
218
|
+
relix.multi :account_id, index_values: true
|
219
|
+
|
220
|
+
# Enables this call
|
221
|
+
relix.lookup_values(:account_id)
|
222
|
+
|
223
|
+
This will yield all of the `account_ids` being indexed on, rather than the set of keys indexed by a particular set of `account_ids`. A typical use case would be fast iteration over grouped sub-models of a `many` relationship:
|
224
|
+
|
225
|
+
User.lookup_values(:account_id).each do |account_id|
|
226
|
+
users_for_account = User.lookup{|q| q[:account_id].eq(account_id)}
|
227
|
+
# Aggregate processing for the users in the account
|
228
|
+
end
|
229
|
+
|
230
|
+
The ordering of returned values is undefined.
|
231
|
+
|
212
232
|
### UniqueIndex
|
213
233
|
|
214
234
|
Unique indexes will raise an error if the same value is indexed twice for a different primary key. They also provide super fast lookups. They are declared using #unique in the relix block:
|
data/lib/relix.rb
CHANGED
data/lib/relix/core.rb
CHANGED
data/lib/relix/index.rb
CHANGED
data/lib/relix/index_set.rb
CHANGED
@@ -47,7 +47,8 @@ module Relix
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def indexes
|
50
|
-
(
|
50
|
+
Relix.deprecate("Calling #indexes is deprecated; use #[] instead.", "2")
|
51
|
+
self
|
51
52
|
end
|
52
53
|
|
53
54
|
def lookup(&block)
|
@@ -60,12 +61,16 @@ module Relix
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
def lookup_values(index)
|
65
|
+
self[index].values(@redis)
|
66
|
+
end
|
67
|
+
|
63
68
|
def index_ops(object, pk)
|
64
69
|
current_values_name = current_values_name(pk)
|
65
70
|
@redis.watch current_values_name
|
66
71
|
current_values = @redis.hgetall(current_values_name)
|
67
72
|
|
68
|
-
ops =
|
73
|
+
ops = full_index_list.collect do |name,index|
|
69
74
|
value = index.read_normalized(object)
|
70
75
|
old_value = current_values[name]
|
71
76
|
|
@@ -105,7 +110,7 @@ module Relix
|
|
105
110
|
@redis.watch current_values_name
|
106
111
|
current_values = @redis.hgetall(current_values_name)
|
107
112
|
|
108
|
-
|
113
|
+
full_index_list.map do |name, index|
|
109
114
|
old_value = if index.attribute_immutable?
|
110
115
|
index.read_normalized(object)
|
111
116
|
else
|
@@ -124,7 +129,7 @@ module Relix
|
|
124
129
|
@redis.watch current_values_name
|
125
130
|
current_values = @redis.hgetall(current_values_name)
|
126
131
|
|
127
|
-
|
132
|
+
full_index_list.map do |name, index|
|
128
133
|
old_value = current_values[name]
|
129
134
|
|
130
135
|
((watch = index.watch(old_value)) && !watch.empty? && @redis.watch(*watch))
|
@@ -149,7 +154,17 @@ module Relix
|
|
149
154
|
keyer.values(pk, @klass)
|
150
155
|
end
|
151
156
|
|
152
|
-
|
157
|
+
def [](name)
|
158
|
+
full_index_list[name.to_s]
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
def full_index_list
|
164
|
+
(parent ? parent.full_index_list.merge(@indexes) : @indexes)
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
153
168
|
|
154
169
|
def handle_concurrent_modifications(primary_key)
|
155
170
|
retries = 5
|
data/lib/relix/indexes/multi.rb
CHANGED
@@ -3,16 +3,21 @@ module Relix
|
|
3
3
|
include Ordering
|
4
4
|
|
5
5
|
def watch_keys(*values)
|
6
|
-
values.compact.map { |v| key_for(v) }
|
6
|
+
keys = values.compact.map { |v| key_for(v) }
|
7
|
+
keys << values_key if index_values?
|
8
|
+
keys
|
7
9
|
end
|
8
10
|
|
9
11
|
def index(r, pk, object, value, old_value)
|
10
12
|
r.zadd(key_for(value), score(object, value), pk)
|
11
|
-
r
|
13
|
+
index_value(r, value) if index_values?
|
14
|
+
|
15
|
+
deindex(r, pk, old_value)
|
12
16
|
end
|
13
17
|
|
14
18
|
def deindex(r, pk, old_value)
|
15
19
|
r.zrem(key_for(old_value), pk)
|
20
|
+
deindex_value(r, old_value) if index_values?
|
16
21
|
end
|
17
22
|
|
18
23
|
def eq(r, value, options={})
|
@@ -28,6 +33,32 @@ module Relix
|
|
28
33
|
def key_for(value)
|
29
34
|
@set.keyer.component(name, value)
|
30
35
|
end
|
36
|
+
|
37
|
+
def index_values?
|
38
|
+
@options[:index_values]
|
39
|
+
end
|
40
|
+
|
41
|
+
def values_key
|
42
|
+
@set.keyer.component(name, "_values")
|
43
|
+
end
|
44
|
+
|
45
|
+
def values(r)
|
46
|
+
raise ValuesNotIndexedError.new("Value indexing not enabled for #{name}.") unless index_values?
|
47
|
+
r.smembers(values_key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def index_value(r, value)
|
51
|
+
r.sadd(values_key, value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def deindex_value(r, old_value)
|
55
|
+
r.eval %(
|
56
|
+
if(redis.call("ZCARD", KEYS[2]) == 0) then
|
57
|
+
return redis.call("SREM", KEYS[1], ARGV[1])
|
58
|
+
end
|
59
|
+
return "OK"
|
60
|
+
), [values_key, key_for(old_value)], [old_value]
|
61
|
+
end
|
31
62
|
end
|
32
63
|
register_index MultiIndex
|
33
64
|
end
|
data/lib/relix/query.rb
CHANGED
@@ -6,7 +6,7 @@ module Relix
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def [](index_name)
|
9
|
-
index = @model
|
9
|
+
index = @model[index_name]
|
10
10
|
raise MissingIndexError.new("No index declared for #{index_name}") unless index
|
11
11
|
@clause = index.create_query_clause(@model.redis)
|
12
12
|
end
|
@@ -49,4 +49,4 @@ module Relix
|
|
49
49
|
end
|
50
50
|
|
51
51
|
class MissingIndexError < Relix::Error; end
|
52
|
-
end
|
52
|
+
end
|
data/lib/relix/redis.rb
CHANGED
@@ -15,6 +15,10 @@ module Relix
|
|
15
15
|
|
16
16
|
def self.new_redis_client
|
17
17
|
::Redis.new(host: @redis_host, port: @redis_port).tap do |client|
|
18
|
+
version = client.info["redis_version"]
|
19
|
+
if(Relix::Version.new(version) < Relix::REDIS_VERSION)
|
20
|
+
raise UnsupportedRedisVersion.new("Relix requires Redis >= #{Relix::REDIS_VERSION}; you have #{version}.")
|
21
|
+
end
|
18
22
|
client.select @redis_db if @redis_db
|
19
23
|
end
|
20
24
|
end
|
@@ -30,4 +34,6 @@ module Relix
|
|
30
34
|
def self.db=(value)
|
31
35
|
@redis_db = value
|
32
36
|
end
|
33
|
-
|
37
|
+
|
38
|
+
class UnsupportedRedisVersion < Exception; end
|
39
|
+
end
|
data/lib/relix/version.rb
CHANGED
@@ -1,3 +1,42 @@
|
|
1
1
|
module Relix
|
2
|
-
VERSION = "
|
2
|
+
VERSION = "2.0.0"
|
3
|
+
REDIS_VERSION = "2.6"
|
4
|
+
|
5
|
+
class Version
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
attr_reader :major, :minor, :patch
|
9
|
+
def initialize(version)
|
10
|
+
@major, @minor, @patch = version.to_s.split(".").collect{|e| e.to_i}
|
11
|
+
@minor ||= 0
|
12
|
+
@patch ||= 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def <=>(other)
|
16
|
+
case other
|
17
|
+
when String
|
18
|
+
(self <=> Version.new(other))
|
19
|
+
else
|
20
|
+
if((r = (major <=> other.major)) != 0)
|
21
|
+
r
|
22
|
+
elsif((r = (minor <=> other.minor)) != 0)
|
23
|
+
r
|
24
|
+
else
|
25
|
+
(patch <=> other.patch)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.deprecate(message, as_of_version)
|
32
|
+
as_of_version = Version.new(as_of_version)
|
33
|
+
|
34
|
+
if Version.new(VERSION).major > as_of_version.major
|
35
|
+
raise DeprecationError.new(message)
|
36
|
+
else
|
37
|
+
$stderr.puts(message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DeprecationError < Exception; end
|
3
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathaniel Talbott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-03-
|
11
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
prerelease: false
|