relix 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/HISTORY.md +5 -0
- data/README.md +22 -7
- data/lib/relix/core.rb +4 -0
- data/lib/relix/index_set.rb +16 -1
- data/lib/relix/indexes/multi.rb +2 -2
- data/lib/relix/indexes/ordered.rb +1 -1
- data/lib/relix/indexes/primary_key.rb +1 -1
- data/lib/relix/indexes/unique.rb +2 -2
- data/lib/relix/version.rb +1 -1
- metadata +21 -16
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDQwM2VkOWJiYjk5NGQzYmNiMjA4ZThjNzQ3ZDRmNmQzZDJmZjRlZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
N2Q3YTYyZWEyNjk2YTFjOGNiODQ0MDhmMGFmNTY1NTI5NDUxODE2ZQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzI2MTNmZmVmYTVlNTllNmQ2NDhkOTUxYjkwM2IxNGQ0NGI1NjQzMGNiYmE3
|
10
|
+
NWUxNjIzYjk1YWI1OGNkODdlYTNiMmZlNTcwZjdmOWI0MzlmYzYwMjAxMzQw
|
11
|
+
YWM5NzAwZGU2ODE5ZmMzOGExMzY2NmE5OWE2NGYzZDdkMzczYzY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTgxNzA5Y2I0YjZkMTVlYjM4NzBkYzUwYTAyNTExOTIwOTYwOGZlZWVmNjk3
|
14
|
+
Mjg3ZmVlNWQ2YWMyNGNhZWMzNzlhMTY1YjYwNWM0ZTNjMGU5YzY0ZTRmYTYz
|
15
|
+
MzdkY2E2NzczYTRlYTkyNjA0ZTY3M2ZkODZhNDNhYjM0OTBiZTk=
|
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
A Redis-backed indexing layer that can be used with any (or no) backend data storage.
|
4
4
|
|
5
|
+
|
5
6
|
## Rationale
|
6
7
|
|
7
8
|
With the rise in popularity of non-relational databases, and the regular use of relational databases in non-relational ways, data indexing has become an aspect of data storage that you can't simply assume is handled for you. More and more applications are storing their data in databases that treat that stored data as opaque, and thus there's no query engine sitting on top of the data making sure that it can be quickly and flexibly looked up.
|
8
9
|
|
9
10
|
Relix is a layer that can be added on to any model to make all the normal types of querying you want to do: equality, less than/greater than, in set, range, limit, etc., quick and painless. Relix depends on Redis to be awesome at what it does - blazingly fast operations on basic data types - and layers on top of that pluggable indexing of your data for fast lookup.
|
10
11
|
|
12
|
+
|
11
13
|
## Philosophy
|
12
14
|
|
13
15
|
* Performance is paramount - be FAST.
|
@@ -17,6 +19,7 @@ Relix is a layer that can be added on to any model to make all the normal types
|
|
17
19
|
** Make continuous index repair easy since the chaos monkey could attack at any time.
|
18
20
|
* Be pluggable; keep the core simple and allow easy extensibility
|
19
21
|
|
22
|
+
|
20
23
|
## Installation
|
21
24
|
|
22
25
|
If you're using bundler, add Relix to your Gemfile:
|
@@ -92,6 +95,7 @@ Since the :primary_key index is ordered by insertion order, we've also declared
|
|
92
95
|
|
93
96
|
p Transaction.lookup{|q| q[:by_created_at].all} # => [4,2,1,3]
|
94
97
|
|
98
|
+
|
95
99
|
## Querying
|
96
100
|
|
97
101
|
Relix uses a simple query language based on method chaining. A "root" query is passed in to the lookup block, and then query terms are chained off of it:
|
@@ -142,7 +146,6 @@ When there are multiple attributes, they are specified in a hash:
|
|
142
146
|
{storage_state: 'cached', account_id: 'bob'}, limit: 10)
|
143
147
|
end
|
144
148
|
|
145
|
-
|
146
149
|
### Space efficiency
|
147
150
|
|
148
151
|
Model attributes that are indexed on but that never change can be marked as immutable to prevent them being stored (since they don't have to be reindexed). The primary key is marked immutable by default, but other attributes can be as well:
|
@@ -154,6 +157,19 @@ Model attributes that are indexed on but that never change can be marked as immu
|
|
154
157
|
This can also provide concurrency benefits since the keys for the indexes on immutable attributes don't have to be watched for concurrent modification.
|
155
158
|
|
156
159
|
|
160
|
+
## Deindexing
|
161
|
+
|
162
|
+
You'll probably want to remove an object from the index at some point. To do that simply call `#deindex!` on it:
|
163
|
+
|
164
|
+
person.deindex!
|
165
|
+
|
166
|
+
You can also remove something from the index even if you don't have the complete object in hand anymore; simply call `.deindex_by_primary_key!` on its class:
|
167
|
+
|
168
|
+
Person.deindex_by_primary_key!(44)
|
169
|
+
|
170
|
+
The class-level `deindex_by_primary_key` cannot clean up immutable indexes other than the primary key (since the current value of immutable keys is not stored), so calling plain `deindex!` on an object is preferred.
|
171
|
+
|
172
|
+
|
157
173
|
## Index Types
|
158
174
|
|
159
175
|
### PrimaryKeyIndex
|
@@ -164,10 +180,9 @@ The primary key index is the only index that is required on a model. Under the c
|
|
164
180
|
primary_key :id
|
165
181
|
end
|
166
182
|
|
167
|
-
**Supported Operators**: eq, all
|
183
|
+
**Supported Operators**: eq, all
|
168
184
|
**Ordering**: insertion
|
169
185
|
|
170
|
-
|
171
186
|
### MultiIndex
|
172
187
|
|
173
188
|
Multi indexes allow multiple matching primary keys per indexed value, and are ideal for one to many relationships. They can include an ordering, and are declared using #multi in the relix block:
|
@@ -176,10 +191,9 @@ Multi indexes allow multiple matching primary keys per indexed value, and are id
|
|
176
191
|
multi :account_id, order: :created_at
|
177
192
|
end
|
178
193
|
|
179
|
-
**Supported Operators**: eq
|
194
|
+
**Supported Operators**: eq
|
180
195
|
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
181
196
|
|
182
|
-
|
183
197
|
### UniqueIndex
|
184
198
|
|
185
199
|
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:
|
@@ -190,7 +204,7 @@ Unique indexes will raise an error if the same value is indexed twice for a diff
|
|
190
204
|
|
191
205
|
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.
|
192
206
|
|
193
|
-
**Supported Operators**: eq, all
|
207
|
+
**Supported Operators**: eq, all
|
194
208
|
**Ordering**: can be ordered on any numeric attribute (default is the to_i of the indexed value)
|
195
209
|
|
196
210
|
### OrderedIndex
|
@@ -202,7 +216,7 @@ primary keys per indexed value. They are declared using #ordered in the relix bl
|
|
202
216
|
ordered :birthdate
|
203
217
|
end
|
204
218
|
|
205
|
-
**Supported Operators**: eq, lt, lte, gt, gte, order, limit, offset
|
219
|
+
**Supported Operators**: eq, lt, lte, gt, gte, order, limit, offset
|
206
220
|
**Ordering**: ordered ascending by the indexed value, but can be queried in
|
207
221
|
reverse order if you use `order(:desc)`.
|
208
222
|
|
@@ -218,6 +232,7 @@ Ordered indexes support a flexible fluent interface for specifying the query:
|
|
218
232
|
|
219
233
|
This query returns the primary keys of the 10 youngest people born in 1990.
|
220
234
|
|
235
|
+
|
221
236
|
## Keying
|
222
237
|
|
223
238
|
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:
|
data/lib/relix/core.rb
CHANGED
data/lib/relix/index_set.rb
CHANGED
@@ -113,7 +113,22 @@ module Relix
|
|
113
113
|
end
|
114
114
|
|
115
115
|
((watch = index.watch(old_value)) && @redis.watch(*watch))
|
116
|
-
proc { index.deindex(@redis, pk,
|
116
|
+
proc { index.deindex(@redis, pk, old_value) }
|
117
|
+
end.tap { |ops| ops << proc { @redis.del current_values_name } }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def deindex_by_primary_key!(pk)
|
122
|
+
handle_concurrent_modifications(pk) do
|
123
|
+
current_values_name = current_values_name(pk)
|
124
|
+
@redis.watch current_values_name
|
125
|
+
current_values = @redis.hgetall(current_values_name)
|
126
|
+
|
127
|
+
indexes.map do |name, index|
|
128
|
+
old_value = current_values[name]
|
129
|
+
|
130
|
+
((watch = index.watch(old_value)) && @redis.watch(*watch))
|
131
|
+
proc { index.deindex(@redis, pk, old_value) }
|
117
132
|
end.tap { |ops| ops << proc { @redis.del current_values_name } }
|
118
133
|
end
|
119
134
|
end
|
data/lib/relix/indexes/multi.rb
CHANGED
@@ -11,7 +11,7 @@ module Relix
|
|
11
11
|
r.zrem(key_for(old_value), pk)
|
12
12
|
end
|
13
13
|
|
14
|
-
def deindex(r, pk,
|
14
|
+
def deindex(r, pk, old_value)
|
15
15
|
r.zrem(key_for(old_value), pk)
|
16
16
|
end
|
17
17
|
|
@@ -30,4 +30,4 @@ module Relix
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
register_index MultiIndex
|
33
|
-
end
|
33
|
+
end
|
data/lib/relix/indexes/unique.rb
CHANGED
@@ -33,7 +33,7 @@ module Relix
|
|
33
33
|
r.hdel(hash_name, old_value)
|
34
34
|
end
|
35
35
|
|
36
|
-
def deindex(r, pk,
|
36
|
+
def deindex(r, pk, old_value)
|
37
37
|
r.hdel(hash_name, old_value)
|
38
38
|
r.zrem(sorted_set_name, pk)
|
39
39
|
end
|
@@ -49,4 +49,4 @@ module Relix
|
|
49
49
|
register_index UniqueIndex
|
50
50
|
|
51
51
|
class NotUniqueError < Relix::Error; end
|
52
|
-
end
|
52
|
+
end
|
data/lib/relix/version.rb
CHANGED
metadata
CHANGED
@@ -1,38 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.4.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Nathaniel Talbott
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-03-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
prerelease: false
|
15
15
|
name: hiredis
|
16
|
-
requirement:
|
17
|
-
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.4.1
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
18
22
|
requirements:
|
19
23
|
- - ~>
|
20
24
|
- !ruby/object:Gem::Version
|
21
25
|
version: 0.4.1
|
22
26
|
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: *70128679226480
|
25
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
prerelease: false
|
26
29
|
name: redis
|
27
|
-
requirement:
|
28
|
-
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '3.0'
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
36
|
requirements:
|
30
37
|
- - ~>
|
31
38
|
- !ruby/object:Gem::Version
|
32
39
|
version: '3.0'
|
33
40
|
type: :runtime
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *70128679224880
|
36
41
|
description: ! 'Relix is a layer that can be added on to any model to make all the
|
37
42
|
normal types of querying you want to do: equality, less than/greater than, in set,
|
38
43
|
range, limit, etc., quick and painless. Relix depends on Redis to be awesome at
|
@@ -59,28 +64,28 @@ files:
|
|
59
64
|
- lib/relix/redis.rb
|
60
65
|
- lib/relix/version.rb
|
61
66
|
homepage: http://github.com/ntalbott/relix
|
62
|
-
licenses:
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
63
70
|
post_install_message:
|
64
71
|
rdoc_options: []
|
65
72
|
require_paths:
|
66
73
|
- lib
|
67
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
75
|
requirements:
|
70
76
|
- - ! '>='
|
71
77
|
- !ruby/object:Gem::Version
|
72
78
|
version: '0'
|
73
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
80
|
requirements:
|
76
81
|
- - ! '>='
|
77
82
|
- !ruby/object:Gem::Version
|
78
83
|
version: 1.5.2
|
79
84
|
requirements: []
|
80
85
|
rubyforge_project:
|
81
|
-
rubygems_version:
|
86
|
+
rubygems_version: 2.0.0
|
82
87
|
signing_key:
|
83
|
-
specification_version:
|
88
|
+
specification_version: 4
|
84
89
|
summary: A Redis-backed indexing layer that can be used with any (or no) backend data
|
85
90
|
storage.
|
86
91
|
test_files: []
|