relix 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzI0ZGYzYjgyYjdiMjlkN2ExZjA3MTk0ZjRkYTM3YmZiMmFjMjJlYQ==
4
+ MjY4Y2ExMjRhYTk5MTJjYjUyYTUwZjE4NWUxZDlmOGEwNGU5YWJjYw==
5
5
  data.tar.gz: !binary |-
6
- YmZjNDU0NmUwMGI0NGY5OGE0ZjUxMTBkNmQyOGVjY2VhMTM2NmVhMA==
6
+ ZjA5NGFhODZhODYyYzZjZjA3MmU1ODA5YTkyM2Q2YWM4ZGZkNjJlYw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NDhjZjgyY2RjYTIzMWU0YmMyZjI5MDEwNTg4ZmVkYTZkYjRkYjBhYTBiZDZk
10
- Yjk4MWQ1YjE0MjFmOTc4YzlhZWFhZjNiN2I0MWIwMTdkMmVjMDYxODIzMWNj
11
- Y2RhMDU2MDI0ZTVmM2FiNjRhY2EzMDg5MDMzM2JhZGQ2Y2M5ZTY=
9
+ Yzg0NzA4YjczZTI0YzJkZmE2NTJlNzA1NWNkNWJkZTEyNzIzYTU1MjYzYjgz
10
+ YWQyYjQ2NjA0MzJmZThjMzJjYTY3YmYyNjZhNGRjYzFhNzhlNmViYWU3ODFl
11
+ ZDAwY2Y2OTc4NzFlMzVmNDlhYTMwMDI5ZGI4ZTE3ZGMwZDEwYTI=
12
12
  data.tar.gz: !binary |-
13
- MjI1MDIyN2Y1ZDZiOGIwYjJlOGJlZDQ5NjNmZjdmMjc2ZWRmOWQ5NTAxNWNi
14
- MTUzODBiZDM4NDdkZDI2ZTNkY2ZlNWYyNDI3NmE1MTk2N2YxZDNlYjFmNTA4
15
- MjIyZGQ2MTk3NjdiMjAzMGQwYTc4ZWZhNmFkYzQ0MWE3ZDA5YzQ=
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
@@ -8,3 +8,4 @@ require 'relix/indexes/multi'
8
8
  require 'relix/indexes/unique'
9
9
  require 'relix/indexes/primary_key'
10
10
  require 'relix/indexes/ordered'
11
+ require 'relix/version'
data/lib/relix/core.rb CHANGED
@@ -26,6 +26,10 @@ module Relix
26
26
  relix.lookup(&block)
27
27
  end
28
28
 
29
+ def lookup_values(index)
30
+ relix.lookup_values(index)
31
+ end
32
+
29
33
  def deindex_by_primary_key!(pk)
30
34
  relix.deindex_by_primary_key!(pk)
31
35
  end
data/lib/relix/index.rb CHANGED
@@ -135,4 +135,5 @@ module Relix
135
135
 
136
136
  class UnorderableValueError < Relix::Error; end
137
137
  class MissingIndexValueError < Relix::Error; end
138
+ class ValuesNotIndexedError < Relix::Error; end
138
139
  end
@@ -47,7 +47,8 @@ module Relix
47
47
  end
48
48
 
49
49
  def indexes
50
- (parent ? parent.indexes.merge(@indexes) : @indexes)
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 = indexes.collect do |name,index|
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
- indexes.map do |name, index|
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
- indexes.map do |name, index|
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
- private
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
@@ -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.zrem(key_for(old_value), pk)
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.indexes[index_name.to_s]
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
- end
37
+
38
+ class UnsupportedRedisVersion < Exception; end
39
+ end
data/lib/relix/version.rb CHANGED
@@ -1,3 +1,42 @@
1
1
  module Relix
2
- VERSION = "1.5.0"
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: 1.5.0
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-16 00:00:00.000000000 Z
11
+ date: 2013-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  prerelease: false