relix 1.0.3 → 1.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/README.md +32 -4
- data/lib/relix.rb +1 -0
- data/lib/relix/core.rb +10 -4
- data/lib/relix/index.rb +20 -11
- data/lib/relix/index_set.rb +107 -42
- data/lib/relix/indexes/multi.rb +13 -5
- data/lib/relix/indexes/primary_key.rb +12 -8
- data/lib/relix/indexes/unique.rb +25 -18
- data/lib/relix/query.rb +7 -6
- data/lib/relix/redis.rb +7 -2
- data/lib/relix/version.rb +1 -1
- metadata +9 -6
data/README.md
CHANGED
@@ -153,7 +153,7 @@ The primary key index is the only index that is required on a model. Under the c
|
|
153
153
|
primary_key :id
|
154
154
|
end
|
155
155
|
|
156
|
-
**Supported Operators**: eq, all
|
156
|
+
**Supported Operators**: eq, all
|
157
157
|
**Ordering**: insertion
|
158
158
|
|
159
159
|
|
@@ -165,7 +165,7 @@ Multi indexes allow multiple matching primary keys per indexed value, and are id
|
|
165
165
|
multi :account_id, order: :created_at
|
166
166
|
end
|
167
167
|
|
168
|
-
**Supported Operators**: eq
|
168
|
+
**Supported Operators**: eq
|
169
169
|
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
170
170
|
|
171
171
|
|
@@ -179,5 +179,33 @@ Unique indexes will raise an error if the same value is indexed twice for a diff
|
|
179
179
|
|
180
180
|
Unique indexes ignore nil values - they will not be indexed and an error is not raised if there is more than one object with a value of nil. A multi-value unique index will be completely skipped if any value in it is nil.
|
181
181
|
|
182
|
-
**Supported Operators**: eq, all
|
183
|
-
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
182
|
+
**Supported Operators**: eq, all
|
183
|
+
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
184
|
+
|
185
|
+
|
186
|
+
## Keying
|
187
|
+
|
188
|
+
A big part of using Redis well is choosing solid keys; Relix has a pluggable keying infrastructure that makes it easy to use different key names for different situations. This actually rose out of the fact that the first release of Relix had a pathetic set of keys, and the need to support existing deployments while moving to something better going forward. Keyers are set on a per-model basis along with other configuration:
|
189
|
+
|
190
|
+
relix do
|
191
|
+
keyer Relix::Keyer::Compact
|
192
|
+
end
|
193
|
+
|
194
|
+
You can set the default keyer like so:
|
195
|
+
|
196
|
+
Relix.default_keyer(Relix::Keyer::Compact)
|
197
|
+
|
198
|
+
|
199
|
+
### Standard
|
200
|
+
|
201
|
+
This keyer is nice and verbose, which makes it ideal for development since you can browse the Redis keyspace and see at a glance how the indexes are stored. **Standard is the default keyer.**
|
202
|
+
|
203
|
+
|
204
|
+
### Compact
|
205
|
+
|
206
|
+
Keys take up space, and especially since Redis holds the keyset in memory it can be a big boon with a large data set to keep key names short. The Compact keyer tries to balance a reasonable level of readability (we can't sacrifice the ability to debug production issues) with keeping keys as compact as possible.
|
207
|
+
|
208
|
+
|
209
|
+
### Legacy
|
210
|
+
|
211
|
+
This (eventually to be deprecated and removed) strategy exactly mirrors the keying supported by Relix when first released.
|
data/lib/relix.rb
CHANGED
data/lib/relix/core.rb
CHANGED
@@ -8,13 +8,13 @@ module Relix
|
|
8
8
|
@index_types ||= {}
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.register_index(
|
12
|
-
index_types[
|
11
|
+
def self.register_index(index)
|
12
|
+
index_types[index.kind.to_sym] = index
|
13
13
|
end
|
14
14
|
|
15
15
|
module ClassMethods
|
16
16
|
def relix(&block)
|
17
|
-
@relix ||= IndexSet.new(self)
|
17
|
+
@relix ||= IndexSet.new(self, Relix.redis)
|
18
18
|
if block_given?
|
19
19
|
@relix.instance_eval(&block)
|
20
20
|
else
|
@@ -34,4 +34,10 @@ module Relix
|
|
34
34
|
def index!
|
35
35
|
relix.index!(self)
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
|
+
def deindex!
|
39
|
+
relix.deindex!(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
class Error < StandardError; end
|
43
|
+
end
|
data/lib/relix/index.rb
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
module Relix
|
2
2
|
class Index
|
3
|
-
def
|
4
|
-
@name
|
3
|
+
def self.kind
|
4
|
+
@kind ||= name.gsub(/(?:^.+::|Index$)/, '').gsub(/([a-z])([A-Z])/){"#{$1}_#{$2}"}.downcase
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.compact_kind
|
8
|
+
@compact_kind ||= kind[0..0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(set, base_name, accessor, options={})
|
12
|
+
@set = set
|
13
|
+
@base_name = base_name
|
5
14
|
@accessor = [accessor].flatten.collect{|a| a.to_s}
|
6
15
|
@options = options
|
7
16
|
end
|
8
17
|
|
18
|
+
def name
|
19
|
+
@set.keyer.index(self, @base_name)
|
20
|
+
end
|
21
|
+
|
9
22
|
def read(object)
|
10
23
|
@accessor.inject({}){|h,e| h[e] = object.send(e); h}
|
11
24
|
end
|
@@ -25,7 +38,7 @@ module Relix
|
|
25
38
|
if value_hash.include?(k)
|
26
39
|
value_hash[k].to_s
|
27
40
|
else
|
28
|
-
raise MissingIndexValueError, "Missing #{k} when looking up by #{
|
41
|
+
raise MissingIndexValueError, "Missing #{k} when looking up by #{name}"
|
29
42
|
end
|
30
43
|
end.join(":")
|
31
44
|
end
|
@@ -42,10 +55,6 @@ module Relix
|
|
42
55
|
nil
|
43
56
|
end
|
44
57
|
|
45
|
-
def key_for(value)
|
46
|
-
"#{@name}:#{value}"
|
47
|
-
end
|
48
|
-
|
49
58
|
module Ordering
|
50
59
|
def initialize(*args)
|
51
60
|
super
|
@@ -74,10 +83,10 @@ module Relix
|
|
74
83
|
end
|
75
84
|
end
|
76
85
|
|
77
|
-
def range_from_options(options, value=nil)
|
86
|
+
def range_from_options(r, options, value=nil)
|
78
87
|
start = (options[:offset] || 0)
|
79
88
|
if f = options[:from]
|
80
|
-
start = (position(f, value) + 1)
|
89
|
+
start = (position(r, f, value) + 1)
|
81
90
|
end
|
82
91
|
stop = (options[:limit] ? (start + options[:limit] - 1) : -1)
|
83
92
|
[start, stop]
|
@@ -85,6 +94,6 @@ module Relix
|
|
85
94
|
end
|
86
95
|
end
|
87
96
|
|
88
|
-
class UnorderableValueError <
|
89
|
-
class MissingIndexValueError <
|
97
|
+
class UnorderableValueError < Relix::Error; end
|
98
|
+
class MissingIndexValueError < Relix::Error; end
|
90
99
|
end
|
data/lib/relix/index_set.rb
CHANGED
@@ -1,15 +1,37 @@
|
|
1
1
|
module Relix
|
2
2
|
class IndexSet
|
3
|
-
|
3
|
+
attr_accessor :redis
|
4
|
+
def initialize(klass, redis)
|
4
5
|
@klass = klass
|
6
|
+
@redis = redis
|
5
7
|
@indexes = Hash.new
|
8
|
+
@keyer = Keyer.default_for(@klass)
|
6
9
|
end
|
7
10
|
|
8
11
|
def primary_key(accessor)
|
9
|
-
add_index(:primary_key,
|
12
|
+
@primary_key_index = add_index(:primary_key, accessor)
|
10
13
|
end
|
11
14
|
alias pk primary_key
|
12
15
|
|
16
|
+
def primary_key_index
|
17
|
+
unless @primary_key_index
|
18
|
+
if parent
|
19
|
+
@primary_key_index = parent.primary_key_index
|
20
|
+
else
|
21
|
+
raise MissingPrimaryKeyError.new("You must declare a primary key for #{@klass.name}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@primary_key_index
|
25
|
+
end
|
26
|
+
|
27
|
+
def keyer(value=nil, options={})
|
28
|
+
if value
|
29
|
+
@keyer = value.new(@klass, options)
|
30
|
+
else
|
31
|
+
@keyer
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
13
35
|
def method_missing(m, *args)
|
14
36
|
if Relix.index_types.keys.include?(m.to_sym)
|
15
37
|
add_index(m, *args)
|
@@ -20,7 +42,7 @@ module Relix
|
|
20
42
|
|
21
43
|
def add_index(index_type, name, options={})
|
22
44
|
accessor = (options.delete(:on) || name)
|
23
|
-
@indexes[name.to_s] = Relix.index_types[index_type].new(
|
45
|
+
@indexes[name.to_s] = Relix.index_types[index_type].new(self, name, accessor, options)
|
24
46
|
end
|
25
47
|
|
26
48
|
def indexes
|
@@ -28,56 +50,65 @@ module Relix
|
|
28
50
|
end
|
29
51
|
|
30
52
|
def lookup(&block)
|
31
|
-
unless primary_key = indexes['primary_key']
|
32
|
-
raise MissingPrimaryKeyError.new("You must declare a primary key for #{@klass.name}")
|
33
|
-
end
|
34
53
|
if block
|
35
54
|
query = Query.new(self)
|
36
55
|
yield(query)
|
37
56
|
query.run
|
38
57
|
else
|
39
|
-
|
58
|
+
primary_key_index.all(@redis)
|
40
59
|
end
|
41
60
|
end
|
42
61
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
pk = primary_key_index.read_normalized(object)
|
48
|
-
current_values_name = "#{key_prefix('current_values')}:#{pk}"
|
62
|
+
def index_ops(object, pk)
|
63
|
+
current_values_name = current_values_name(pk)
|
64
|
+
@redis.watch current_values_name
|
65
|
+
current_values = @redis.hgetall(current_values_name)
|
49
66
|
|
50
|
-
|
51
|
-
|
52
|
-
r.watch current_values_name
|
53
|
-
current_values = r.hgetall(current_values_name)
|
54
|
-
indexers = []
|
55
|
-
indexes.each do |name,index|
|
56
|
-
((watch = index.watch) && r.watch(*watch))
|
67
|
+
ops = indexes.collect do |name,index|
|
68
|
+
((watch = index.watch) && @redis.watch(*watch))
|
57
69
|
|
58
|
-
|
59
|
-
|
70
|
+
value = index.read_normalized(object)
|
71
|
+
old_value = current_values[name]
|
60
72
|
|
61
|
-
|
62
|
-
|
73
|
+
next if value == old_value
|
74
|
+
current_values[name] = value
|
63
75
|
|
64
|
-
|
76
|
+
next unless index.filter(@redis, object, value)
|
65
77
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
end
|
71
|
-
r.multi do
|
72
|
-
indexers.each do |indexer|
|
73
|
-
indexer.call
|
74
|
-
end
|
75
|
-
r.hmset(current_values_name, *current_values.flatten)
|
76
|
-
end.each do |result|
|
77
|
-
raise RedisIndexingError.new(result.message) if Exception === result
|
78
|
-
end
|
79
|
-
break
|
78
|
+
query_value = index.query(@redis, value)
|
79
|
+
proc do
|
80
|
+
index.index(@redis, pk, object, value, old_value, *query_value)
|
80
81
|
end
|
82
|
+
end.compact
|
83
|
+
|
84
|
+
ops << proc do
|
85
|
+
@redis.hmset(current_values_name, *current_values.flatten)
|
86
|
+
end
|
87
|
+
|
88
|
+
ops
|
89
|
+
end
|
90
|
+
|
91
|
+
def index!(object)
|
92
|
+
pk = primary_key_for(object)
|
93
|
+
|
94
|
+
handle_concurrent_modifications(pk) do
|
95
|
+
index_ops(object, pk)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def deindex!(object)
|
100
|
+
pk = primary_key_for(object)
|
101
|
+
|
102
|
+
handle_concurrent_modifications(pk) do
|
103
|
+
current_values_name = current_values_name(pk)
|
104
|
+
@redis.watch current_values_name
|
105
|
+
current_values = @redis.hgetall(current_values_name)
|
106
|
+
|
107
|
+
indexes.map do |name, index|
|
108
|
+
((watch = index.watch) && @redis.watch(*watch))
|
109
|
+
old_value = current_values[name]
|
110
|
+
proc { index.deindex(@redis, pk, object, old_value) }
|
111
|
+
end.tap { |ops| ops << proc { @redis.del current_values_name } }
|
81
112
|
end
|
82
113
|
end
|
83
114
|
|
@@ -92,8 +123,42 @@ module Relix
|
|
92
123
|
end
|
93
124
|
@parent
|
94
125
|
end
|
126
|
+
|
127
|
+
def current_values_name(pk)
|
128
|
+
@keyer.values(pk)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def handle_concurrent_modifications(primary_key)
|
134
|
+
retries = 5
|
135
|
+
loop do
|
136
|
+
ops = yield
|
137
|
+
|
138
|
+
results = @redis.multi do
|
139
|
+
ops.each do |op|
|
140
|
+
op.call(primary_key)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
if results
|
145
|
+
results.each do |result|
|
146
|
+
raise RedisIndexingError.new(result.message) if Exception === result
|
147
|
+
end
|
148
|
+
break
|
149
|
+
else
|
150
|
+
retries -= 1
|
151
|
+
raise ExceededRetriesForConcurrentWritesError.new if retries <= 0
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def primary_key_for(object)
|
157
|
+
primary_key_index.read_normalized(object)
|
158
|
+
end
|
95
159
|
end
|
96
160
|
|
97
|
-
class MissingPrimaryKeyError <
|
98
|
-
class RedisIndexingError <
|
99
|
-
end
|
161
|
+
class MissingPrimaryKeyError < Relix::Error; end
|
162
|
+
class RedisIndexingError < Relix::Error; end
|
163
|
+
class ExceededRetriesForConcurrentWritesError < Relix::Error; end
|
164
|
+
end
|
data/lib/relix/indexes/multi.rb
CHANGED
@@ -7,15 +7,23 @@ module Relix
|
|
7
7
|
r.zrem(key_for(old_value), pk)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def deindex(r, pk, object, old_value)
|
11
|
+
r.zrem(key_for(old_value), pk)
|
12
|
+
end
|
13
|
+
|
14
|
+
def eq(r, value, options={})
|
15
|
+
r.zrange(key_for(value), *range_from_options(r, options, value))
|
12
16
|
end
|
13
17
|
|
14
|
-
def position(pk, value)
|
15
|
-
position =
|
18
|
+
def position(r, pk, value)
|
19
|
+
position = r.zrank(key_for(value), pk)
|
16
20
|
raise MissingIndexValueError, "Cannot find key #{pk} in index for #{value}" unless position
|
17
21
|
position
|
18
22
|
end
|
23
|
+
|
24
|
+
def key_for(value)
|
25
|
+
@set.keyer.component(name, value)
|
26
|
+
end
|
19
27
|
end
|
20
|
-
register_index
|
28
|
+
register_index MultiIndex
|
21
29
|
end
|
@@ -3,28 +3,32 @@ module Relix
|
|
3
3
|
include Ordering
|
4
4
|
|
5
5
|
def watch
|
6
|
-
|
6
|
+
name
|
7
7
|
end
|
8
8
|
|
9
9
|
def filter(r, object, value)
|
10
|
-
!r.zrank(
|
10
|
+
!r.zrank(name, value)
|
11
11
|
end
|
12
12
|
|
13
13
|
def query(r, value)
|
14
|
-
r.zcard(
|
14
|
+
r.zcard(name)
|
15
15
|
end
|
16
16
|
|
17
17
|
def index(r, pk, object, value, old_value, rank)
|
18
|
-
r.zadd(
|
18
|
+
r.zadd(name, rank, pk)
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
21
|
+
def deindex(r, pk, object, old_value)
|
22
|
+
r.zrem(name, pk)
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
25
|
+
def all(r, options={})
|
26
|
+
r.zrange(name, *range_from_options(r, options))
|
27
|
+
end
|
28
|
+
|
29
|
+
def eq(r, value, options)
|
26
30
|
[value]
|
27
31
|
end
|
28
32
|
end
|
29
|
-
register_index
|
33
|
+
register_index PrimaryKeyIndex
|
30
34
|
end
|
data/lib/relix/indexes/unique.rb
CHANGED
@@ -2,44 +2,51 @@ module Relix
|
|
2
2
|
class UniqueIndex < Index
|
3
3
|
include Ordering
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def sorted_set_name
|
6
|
+
@set.keyer.component(name, 'ordering')
|
7
|
+
end
|
8
|
+
|
9
|
+
def hash_name
|
10
|
+
@set.keyer.component(name, 'lookup')
|
9
11
|
end
|
10
12
|
|
11
13
|
def watch
|
12
|
-
|
14
|
+
hash_name
|
13
15
|
end
|
14
16
|
|
15
17
|
def filter(r, object, value)
|
16
18
|
return true if read(object).values.any?{|e| e.nil?}
|
17
|
-
if r.hexists(
|
18
|
-
raise NotUniqueError.new("'#{value}' is not unique in index #{
|
19
|
+
if r.hexists(hash_name, value)
|
20
|
+
raise NotUniqueError.new("'#{value}' is not unique in index #{name}")
|
19
21
|
end
|
20
22
|
true
|
21
23
|
end
|
22
24
|
|
23
25
|
def index(r, pk, object, value, old_value)
|
24
26
|
if read(object).values.all?{|e| !e.nil?}
|
25
|
-
r.hset(
|
26
|
-
r.zadd(
|
27
|
+
r.hset(hash_name, value, pk)
|
28
|
+
r.zadd(sorted_set_name, score(object, value), pk)
|
27
29
|
else
|
28
|
-
r.hdel(
|
29
|
-
r.zrem(
|
30
|
+
r.hdel(hash_name, value)
|
31
|
+
r.zrem(sorted_set_name, pk)
|
30
32
|
end
|
31
|
-
r.hdel(
|
33
|
+
r.hdel(hash_name, old_value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def deindex(r, pk, object, old_value)
|
37
|
+
r.hdel(hash_name, old_value)
|
38
|
+
r.zrem(sorted_set_name, pk)
|
32
39
|
end
|
33
40
|
|
34
|
-
def all(options={})
|
35
|
-
|
41
|
+
def all(r, options={})
|
42
|
+
r.zrange(sorted_set_name, *range_from_options(r, options))
|
36
43
|
end
|
37
44
|
|
38
|
-
def eq(value, options={})
|
39
|
-
[
|
45
|
+
def eq(r, value, options={})
|
46
|
+
[r.hget(hash_name, value)].compact
|
40
47
|
end
|
41
48
|
end
|
42
|
-
register_index
|
49
|
+
register_index UniqueIndex
|
43
50
|
|
44
|
-
class NotUniqueError <
|
51
|
+
class NotUniqueError < Relix::Error; end
|
45
52
|
end
|
data/lib/relix/query.rb
CHANGED
@@ -8,19 +8,20 @@ module Relix
|
|
8
8
|
def [](index_name)
|
9
9
|
index = @model.indexes[index_name.to_s]
|
10
10
|
raise MissingIndexError.new("No index declared for #{index_name}") unless index
|
11
|
-
@clause = Clause.new(index)
|
11
|
+
@clause = Clause.new(@model.redis, index)
|
12
12
|
end
|
13
13
|
|
14
14
|
def run
|
15
15
|
if @clause
|
16
16
|
@clause.lookup
|
17
17
|
else
|
18
|
-
@model.
|
18
|
+
@model.primary_key_index.lookup
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
class Clause
|
23
|
-
def initialize(index)
|
23
|
+
def initialize(redis, index)
|
24
|
+
@redis = redis
|
24
25
|
@index = index
|
25
26
|
@options = {}
|
26
27
|
end
|
@@ -39,13 +40,13 @@ module Relix
|
|
39
40
|
if @options[:limit] == 0
|
40
41
|
[]
|
41
42
|
elsif @all
|
42
|
-
@index.all(@options)
|
43
|
+
@index.all(@redis, @options)
|
43
44
|
else
|
44
|
-
@index.eq(@value, @options)
|
45
|
+
@index.eq(@redis, @value, @options)
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
class MissingIndexError <
|
51
|
+
class MissingIndexError < Relix::Error; end
|
51
52
|
end
|
data/lib/relix/redis.rb
CHANGED
@@ -4,8 +4,7 @@ require 'redis'
|
|
4
4
|
module Relix
|
5
5
|
def self.redis
|
6
6
|
unless @redis
|
7
|
-
@redis =
|
8
|
-
@redis.select @redis_db if @redis_db
|
7
|
+
@redis = new_redis_client
|
9
8
|
end
|
10
9
|
if block_given?
|
11
10
|
yield(@redis)
|
@@ -14,6 +13,12 @@ module Relix
|
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
16
|
+
def self.new_redis_client
|
17
|
+
::Redis.new(host: @redis_host, port: @redis_port).tap do |client|
|
18
|
+
client.select @redis_db if @redis_db
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
17
22
|
def self.host=(value)
|
18
23
|
@redis_host = value
|
19
24
|
end
|
data/lib/relix/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: hiredis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70209042647380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70209042647380
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redis
|
27
|
-
requirement: &
|
27
|
+
requirement: &70209042646920 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 2.2.2
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70209042646920
|
36
36
|
description: ! 'Relix is a layer that can be added on to any model to make all the
|
37
37
|
normal types of querying you want to do: equality, less than/greater than, in set,
|
38
38
|
range, limit, etc., quick and painless. Relix depends on Redis to be awesome at
|
@@ -67,6 +67,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
67
|
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
hash: 2795857590381463961
|
70
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
74
|
none: false
|
72
75
|
requirements:
|