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 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