zermelo 1.0.1 → 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.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.travis.yml +3 -5
- data/CHANGELOG.md +8 -2
- data/lib/zermelo/associations/belongs_to.rb +3 -3
- data/lib/zermelo/associations/has_and_belongs_to_many.rb +3 -3
- data/lib/zermelo/associations/has_many.rb +3 -3
- data/lib/zermelo/associations/has_one.rb +3 -3
- data/lib/zermelo/associations/has_sorted_set.rb +4 -4
- data/lib/zermelo/associations/index.rb +1 -2
- data/lib/zermelo/associations/unique_index.rb +1 -2
- data/lib/zermelo/backends/base.rb +1 -1
- data/lib/zermelo/backends/influxdb_backend.rb +29 -18
- data/lib/zermelo/backends/redis_backend.rb +106 -6
- data/lib/zermelo/filters/base.rb +34 -57
- data/lib/zermelo/filters/influxdb_filter.rb +22 -70
- data/lib/zermelo/filters/redis_filter.rb +35 -482
- data/lib/zermelo/filters/steps/list_step.rb +79 -0
- data/lib/zermelo/filters/steps/set_step.rb +176 -0
- data/lib/zermelo/filters/steps/sort_step.rb +85 -0
- data/lib/zermelo/filters/steps/sorted_set_step.rb +156 -0
- data/lib/zermelo/records/class_methods.rb +16 -4
- data/lib/zermelo/records/influxdb_record.rb +2 -0
- data/lib/zermelo/records/instance_methods.rb +4 -4
- data/lib/zermelo/records/key.rb +2 -0
- data/lib/zermelo/version.rb +1 -1
- data/lib/zermelo.rb +9 -1
- data/spec/lib/zermelo/records/influxdb_record_spec.rb +186 -10
- data/spec/lib/zermelo/records/redis_record_spec.rb +11 -4
- data/spec/spec_helper.rb +12 -10
- metadata +5 -11
- data/lib/zermelo/filters/steps/diff_range_step.rb +0 -17
- data/lib/zermelo/filters/steps/diff_step.rb +0 -17
- data/lib/zermelo/filters/steps/intersect_range_step.rb +0 -17
- data/lib/zermelo/filters/steps/intersect_step.rb +0 -17
- data/lib/zermelo/filters/steps/limit_step.rb +0 -17
- data/lib/zermelo/filters/steps/offset_step.rb +0 -17
- data/lib/zermelo/filters/steps/union_range_step.rb +0 -17
- data/lib/zermelo/filters/steps/union_step.rb +0 -17
- data/lib/zermelo/records/collection.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9908061576a4c3d173358524eaf988a6d16bd33
|
4
|
+
data.tar.gz: 843acdcd8b10b1b13407a7c1440f30f87412ac71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5365e1259edae7641187444a6dce2f903be37ae3787f47c5d12006d8f4dd7cf308e6874e54509dabd1ac336a62c39e166839b8ffd76d8126530e43fcc6488a22
|
7
|
+
data.tar.gz: c405762c072ab4f1fe5d366e9997448ba6f35d4b202a6be33535481abc20a1fdf6cbb1d14f87cd4bae37a082cbd9dbe9be3010785c453dd22622064bf5c3bea7
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -8,15 +8,13 @@ services:
|
|
8
8
|
- redis-server
|
9
9
|
before_install:
|
10
10
|
- gem --version
|
11
|
-
- wget
|
11
|
+
- wget https://s3.amazonaws.com/influxdb/influxdb_0.8.8_amd64.deb
|
12
12
|
- sudo dpkg -i influxdb_0.8.8_amd64.deb
|
13
13
|
- sudo /etc/init.d/influxdb start
|
14
14
|
- sleep 8
|
15
15
|
- 'curl -X POST ''http://localhost:8086/db?u=root&p=root'' -d ''{"name": "zermelo_test"}'''
|
16
|
-
- 'curl -X POST ''http://localhost:8086/db/zermelo_test/users?u=root&p=root'' -d
|
17
|
-
|
18
|
-
- 'curl -X POST ''http://localhost:8086/db/zermelo_test/users/zermelo?u=root&p=root''
|
19
|
-
-d ''{"admin": true}'''
|
16
|
+
- 'curl -X POST ''http://localhost:8086/db/zermelo_test/users?u=root&p=root'' -d ''{"name": "zermelo", "password": "zermelo"}'''
|
17
|
+
- 'curl -X POST ''http://localhost:8086/db/zermelo_test/users/zermelo?u=root&p=root'' -d ''{"admin": true}'''
|
20
18
|
notifications:
|
21
19
|
hipchat:
|
22
20
|
template:
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
## Zermelo Changelog
|
2
2
|
|
3
|
+
# 1.1.0 - 2015-04-09
|
4
|
+
|
5
|
+
* refactored query builder to improve composability
|
6
|
+
* bugfix; source key not included when intersecting redis sets
|
7
|
+
* log redis return values as well when redis log is used
|
8
|
+
|
3
9
|
# 1.0.1 - 2015-02-04
|
4
10
|
|
5
|
-
* bugfix has_one class locking (779907d8d)
|
11
|
+
* bugfix; has_one class locking (779907d8d)
|
6
12
|
* add save! command, raise exceptions on error (#13)
|
7
13
|
|
8
14
|
# 1.0.0 - 2015-01-28
|
9
15
|
|
10
|
-
* Initial release
|
16
|
+
* Initial release
|
@@ -14,7 +14,7 @@ module Zermelo
|
|
14
14
|
@backend = parent.send(:backend)
|
15
15
|
|
16
16
|
@record_ids_key = Zermelo::Records::Key.new(
|
17
|
-
:klass => parent.class
|
17
|
+
:klass => parent.class,
|
18
18
|
:id => parent.id,
|
19
19
|
:name => 'belongs_to',
|
20
20
|
:type => :hash,
|
@@ -88,10 +88,10 @@ module Zermelo
|
|
88
88
|
@backend.clear(@record_ids_key)
|
89
89
|
end
|
90
90
|
|
91
|
-
def self.associated_ids_for(backend,
|
91
|
+
def self.associated_ids_for(backend, klass, name, inversed, *these_ids)
|
92
92
|
these_ids.each_with_object({}) do |this_id, memo|
|
93
93
|
key = Zermelo::Records::Key.new(
|
94
|
-
:klass =>
|
94
|
+
:klass => klass,
|
95
95
|
:id => this_id,
|
96
96
|
:name => 'belongs_to',
|
97
97
|
:type => :hash,
|
@@ -23,7 +23,7 @@ module Zermelo
|
|
23
23
|
@backend = parent.send(:backend)
|
24
24
|
|
25
25
|
@record_ids_key = Zermelo::Records::Key.new(
|
26
|
-
:klass => parent.class
|
26
|
+
:klass => parent.class,
|
27
27
|
:id => parent.id,
|
28
28
|
:name => "#{name}_ids",
|
29
29
|
:type => :set,
|
@@ -110,10 +110,10 @@ module Zermelo
|
|
110
110
|
@backend.filter(@record_ids_key, @associated_class)
|
111
111
|
end
|
112
112
|
|
113
|
-
def self.associated_ids_for(backend,
|
113
|
+
def self.associated_ids_for(backend, klass, name, *these_ids)
|
114
114
|
these_ids.each_with_object({}) do |this_id, memo|
|
115
115
|
key = Zermelo::Records::Key.new(
|
116
|
-
:klass =>
|
116
|
+
:klass => klass,
|
117
117
|
:id => this_id,
|
118
118
|
:name => "#{name}_ids",
|
119
119
|
:type => :set,
|
@@ -19,7 +19,7 @@ module Zermelo
|
|
19
19
|
@backend = parent.send(:backend)
|
20
20
|
|
21
21
|
@record_ids_key = Zermelo::Records::Key.new(
|
22
|
-
:klass => parent.class
|
22
|
+
:klass => parent.class,
|
23
23
|
:id => parent.id,
|
24
24
|
:name => "#{name}_ids",
|
25
25
|
:type => :set,
|
@@ -102,10 +102,10 @@ module Zermelo
|
|
102
102
|
@backend.filter(@record_ids_key, @associated_class)
|
103
103
|
end
|
104
104
|
|
105
|
-
def self.associated_ids_for(backend,
|
105
|
+
def self.associated_ids_for(backend, klass, name, *these_ids)
|
106
106
|
these_ids.each_with_object({}) do |this_id, memo|
|
107
107
|
key = Zermelo::Records::Key.new(
|
108
|
-
:klass =>
|
108
|
+
:klass => klass,
|
109
109
|
:id => this_id,
|
110
110
|
:name => "#{name}_ids",
|
111
111
|
:type => :set,
|
@@ -9,7 +9,7 @@ module Zermelo
|
|
9
9
|
|
10
10
|
# TODO would be better as a 'has_one' hash, a bit like belongs_to
|
11
11
|
@record_id_key = Zermelo::Records::Key.new(
|
12
|
-
:klass => parent.class
|
12
|
+
:klass => parent.class,
|
13
13
|
:id => parent.id,
|
14
14
|
:name => "#{name}_id",
|
15
15
|
:type => :string,
|
@@ -91,10 +91,10 @@ module Zermelo
|
|
91
91
|
@backend.clear(@record_id_key)
|
92
92
|
end
|
93
93
|
|
94
|
-
def self.associated_ids_for(backend,
|
94
|
+
def self.associated_ids_for(backend, klass, name, *these_ids)
|
95
95
|
these_ids.each_with_object({}) do |this_id, memo|
|
96
96
|
key = Zermelo::Records::Key.new(
|
97
|
-
:klass =>
|
97
|
+
:klass => klass,
|
98
98
|
:id => this_id,
|
99
99
|
:name => "#{name}_id",
|
100
100
|
:type => :string,
|
@@ -21,7 +21,7 @@ module Zermelo
|
|
21
21
|
@backend = parent.send(:backend)
|
22
22
|
|
23
23
|
@record_ids_key = Zermelo::Records::Key.new(
|
24
|
-
:klass => parent.class
|
24
|
+
:klass => parent.class,
|
25
25
|
:id => parent.id,
|
26
26
|
:name => "#{name}_ids",
|
27
27
|
:type => :sorted_set,
|
@@ -32,7 +32,7 @@ module Zermelo
|
|
32
32
|
@associated_class = data.data_klass
|
33
33
|
@lock_klasses = [data.data_klass] + data.related_klasses
|
34
34
|
@inverse = data.inverse
|
35
|
-
@sort_key = data.sort_key
|
35
|
+
@sort_key = data.sort_key || backend.default_sort_key
|
36
36
|
@callbacks = data.callbacks
|
37
37
|
end
|
38
38
|
end
|
@@ -106,10 +106,10 @@ module Zermelo
|
|
106
106
|
@backend.filter(@record_ids_key, @associated_class)
|
107
107
|
end
|
108
108
|
|
109
|
-
def self.associated_ids_for(backend,
|
109
|
+
def self.associated_ids_for(backend, klass, name, *these_ids)
|
110
110
|
these_ids.each_with_object({}) do |this_id, memo|
|
111
111
|
key = Zermelo::Records::Key.new(
|
112
|
-
:klass =>
|
112
|
+
:klass => klass,
|
113
113
|
:id => this_id,
|
114
114
|
:name => "#{name}_ids",
|
115
115
|
:type => :sorted_set,
|
@@ -9,7 +9,6 @@ module Zermelo
|
|
9
9
|
@attribute_name = name
|
10
10
|
|
11
11
|
@backend = parent_klass.send(:backend)
|
12
|
-
@class_key = parent_klass.send(:class_key)
|
13
12
|
|
14
13
|
@indexers = {}
|
15
14
|
|
@@ -38,7 +37,7 @@ module Zermelo
|
|
38
37
|
raise "Can't index '#{@value}' (#{@attribute_type}" if index_keys.nil?
|
39
38
|
|
40
39
|
@indexers[index_keys.join(":")] ||= Zermelo::Records::Key.new(
|
41
|
-
:klass => @
|
40
|
+
:klass => @parent_klass,
|
42
41
|
:name => "by_#{@attribute_name}:#{index_keys.join(':')}",
|
43
42
|
:type => :set,
|
44
43
|
:object => :index
|
@@ -9,7 +9,6 @@ module Zermelo
|
|
9
9
|
@attribute_name = name
|
10
10
|
|
11
11
|
@backend = parent_klass.send(:backend)
|
12
|
-
@class_key = parent_klass.send(:class_key)
|
13
12
|
|
14
13
|
@indexers = {}
|
15
14
|
|
@@ -32,7 +31,7 @@ module Zermelo
|
|
32
31
|
|
33
32
|
def key
|
34
33
|
@indexer ||= Zermelo::Records::Key.new(
|
35
|
-
:klass => @
|
34
|
+
:klass => @parent_klass,
|
36
35
|
:name => "by_#{@attribute_name}",
|
37
36
|
:type => :hash,
|
38
37
|
:object => :index
|
@@ -15,6 +15,10 @@ module Zermelo
|
|
15
15
|
|
16
16
|
include Zermelo::Backends::Base
|
17
17
|
|
18
|
+
def default_sorted_set_key
|
19
|
+
:time
|
20
|
+
end
|
21
|
+
|
18
22
|
def filter(ids_key, record)
|
19
23
|
Zermelo::Filters::InfluxDBFilter.new(self, ids_key, record)
|
20
24
|
end
|
@@ -22,28 +26,30 @@ module Zermelo
|
|
22
26
|
# TODO get filter calling this instead of using same logic
|
23
27
|
def exists?(key)
|
24
28
|
return if key.id.nil?
|
25
|
-
|
29
|
+
class_key = attr_key.klass.send(:class_key)
|
30
|
+
Zermelo.influxdb.query("SELECT id FROM /#{class_key}\\/.*/ LIMIT 1").size > 0
|
26
31
|
end
|
27
32
|
|
28
33
|
# nb: does lots of queries, should batch, but ensuring single operations are correct
|
29
34
|
# for now
|
30
35
|
def get_multiple(*attr_keys)
|
31
36
|
attr_keys.inject({}) do |memo, attr_key|
|
37
|
+
class_key = attr_key.klass.send(:class_key)
|
32
38
|
begin
|
33
39
|
records = Zermelo.influxdb.query("SELECT #{attr_key.name} FROM " +
|
34
|
-
"\"#{
|
40
|
+
"\"#{class_key}/#{attr_key.id}\" LIMIT 1")["#{class_key}/#{attr_key.id}"]
|
35
41
|
rescue InfluxDB::Error => ide
|
36
42
|
raise unless
|
37
|
-
/^Field #{attr_key.name} doesn't exist in series #{
|
43
|
+
/^Field #{attr_key.name} doesn't exist in series #{class_key}\/#{attr_key.id}$/ === ide.message
|
38
44
|
|
39
45
|
records = []
|
40
46
|
end
|
41
47
|
value = (records && !records.empty?) ? records.first[attr_key.name.to_s] : nil
|
42
48
|
|
43
|
-
memo[
|
44
|
-
memo[
|
49
|
+
memo[class_key] ||= {}
|
50
|
+
memo[class_key][attr_key.id] ||= {}
|
45
51
|
|
46
|
-
memo[
|
52
|
+
memo[class_key][attr_key.id][attr_key.name.to_s] = if value.nil?
|
47
53
|
nil
|
48
54
|
else
|
49
55
|
|
@@ -121,18 +127,20 @@ module Zermelo
|
|
121
127
|
|
122
128
|
next if key.id.nil?
|
123
129
|
|
124
|
-
|
125
|
-
|
130
|
+
class_key = key.klass.send(:class_key)
|
131
|
+
|
132
|
+
records[class_key] ||= {}
|
133
|
+
records[class_key][key.id] ||= {}
|
126
134
|
|
127
|
-
records[
|
135
|
+
records[class_key][key.id][key.name] = case op
|
128
136
|
when :set
|
129
137
|
case key.type
|
130
138
|
when :string, :integer
|
131
|
-
value.to_s
|
139
|
+
value.nil? ? nil : value.to_s
|
132
140
|
when :timestamp
|
133
|
-
value.to_f
|
141
|
+
value.nil? ? nil : value.to_f
|
134
142
|
when :boolean
|
135
|
-
(!!value).to_s
|
143
|
+
value.nil? ? nil : (!!value).to_s
|
136
144
|
when :list, :hash
|
137
145
|
value
|
138
146
|
when :set
|
@@ -144,27 +152,30 @@ module Zermelo
|
|
144
152
|
value
|
145
153
|
when :set
|
146
154
|
value.to_a
|
155
|
+
when :sorted_set
|
156
|
+
(1...value.size).step(2).collect {|i| value[i] }
|
147
157
|
end
|
148
158
|
when :purge
|
149
|
-
purges << "\"#{
|
159
|
+
purges << "\"#{class_key}/#{key.id}\""
|
150
160
|
end
|
151
161
|
|
152
162
|
end
|
153
163
|
|
154
|
-
records.each_pair do |
|
164
|
+
records.each_pair do |class_key, klass_records|
|
155
165
|
klass_records.each_pair do |id, data|
|
156
166
|
begin
|
157
|
-
prior = Zermelo.influxdb.query("SELECT * FROM \"#{
|
167
|
+
prior = Zermelo.influxdb.query("SELECT * FROM \"#{class_key}/#{id}\" LIMIT 1")["#{class_key}/#{id}"]
|
158
168
|
rescue InfluxDB::Error => ide
|
159
169
|
raise unless
|
160
|
-
(/^Couldn't look up columns for series: #{
|
170
|
+
(/^Couldn't look up columns for series: #{class_key}\/#{id}$/ === ide.message) ||
|
161
171
|
(/^Couldn't look up columns$/ === ide.message) ||
|
162
|
-
(/^Couldn't find series: #{
|
172
|
+
(/^Couldn't find series: #{class_key}\/#{id}$/ === ide.message)
|
163
173
|
|
164
174
|
prior = nil
|
165
175
|
end
|
166
176
|
record = prior.nil? ? {} : prior.first.delete_if {|k,v| ["time", "sequence_number"].include?(k) }
|
167
|
-
|
177
|
+
data.delete('time') if data.has_key?('time') && data['time'].nil?
|
178
|
+
Zermelo.influxdb.write_point("#{class_key}/#{id}", record.merge(data).merge('id' => id))
|
168
179
|
end
|
169
180
|
end
|
170
181
|
|
@@ -11,6 +11,10 @@ module Zermelo
|
|
11
11
|
|
12
12
|
include Zermelo::Backends::Base
|
13
13
|
|
14
|
+
def default_sorted_set_key
|
15
|
+
:timestamp
|
16
|
+
end
|
17
|
+
|
14
18
|
def generate_lock
|
15
19
|
Zermelo::Locks::RedisLock.new
|
16
20
|
end
|
@@ -23,9 +27,11 @@ module Zermelo
|
|
23
27
|
attr_keys.inject({}) do |memo, attr_key|
|
24
28
|
redis_attr_key = key_to_redis_key(attr_key)
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
memo[
|
30
|
+
class_key = attr_key.klass.send(:class_key)
|
31
|
+
|
32
|
+
memo[class_key] ||= {}
|
33
|
+
memo[class_key][attr_key.id] ||= {}
|
34
|
+
memo[class_key][attr_key.id][attr_key.name.to_s] = if Zermelo::COLLECTION_TYPES.has_key?(attr_key.type)
|
29
35
|
|
30
36
|
case attr_key.type
|
31
37
|
when :list
|
@@ -126,8 +132,9 @@ module Zermelo
|
|
126
132
|
true
|
127
133
|
end
|
128
134
|
|
129
|
-
# used by redis_filter
|
130
135
|
def key_to_redis_key(key)
|
136
|
+
class_key = key.klass.send(:class_key)
|
137
|
+
|
131
138
|
obj = case key.object
|
132
139
|
when :attribute
|
133
140
|
'attrs'
|
@@ -135,11 +142,104 @@ module Zermelo
|
|
135
142
|
'assocs'
|
136
143
|
when :index
|
137
144
|
'indices'
|
145
|
+
when :temporary
|
146
|
+
'tmp'
|
138
147
|
end
|
139
148
|
|
140
149
|
name = Zermelo::COLLECTION_TYPES.has_key?(key.type) ? ":#{key.name}" : ''
|
141
150
|
|
142
|
-
"#{
|
151
|
+
"#{class_key}:#{key.id.nil? ? '' : key.id}:#{obj}#{name}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def temp_key_wrap
|
155
|
+
return unless block_given?
|
156
|
+
temp_keys = []
|
157
|
+
begin
|
158
|
+
yield(temp_keys)
|
159
|
+
rescue
|
160
|
+
raise
|
161
|
+
ensure
|
162
|
+
unless temp_keys.empty?
|
163
|
+
Zermelo.redis.del(*temp_keys.collect {|tk| key_to_redis_key(tk)})
|
164
|
+
temp_keys.clear
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# TODO converge usage of idx_class and _index lookup invocation
|
170
|
+
|
171
|
+
def index_lookup(att, associated_class, idx_class, value, attr_type, temp_keys)
|
172
|
+
case value
|
173
|
+
# when Zermelo::Filters::RedisFilter
|
174
|
+
|
175
|
+
# TODO (maybe) if a filter from different backend, resolve to ids and
|
176
|
+
# put that in a Redis temp set
|
177
|
+
|
178
|
+
# collection, should_be_deleted = value.resolve_steps
|
179
|
+
|
180
|
+
# if should_be_deleted
|
181
|
+
# temp_sets << collection.name
|
182
|
+
# end
|
183
|
+
|
184
|
+
# unless :set.eql?(collection.type)
|
185
|
+
# raise "Unsure as yet if non-sets are safe as Filter step values"
|
186
|
+
# end
|
187
|
+
|
188
|
+
when Regexp
|
189
|
+
raise "Can't query non-string values via regexp" unless :string.eql?(attr_type)
|
190
|
+
|
191
|
+
idx_key = associated_class.send(:temp_key, :set)
|
192
|
+
temp_keys << idx_key
|
193
|
+
idx_result = key_to_redis_key(idx_key)
|
194
|
+
|
195
|
+
starts_with_string_re = /^string:/
|
196
|
+
case idx_class.name
|
197
|
+
when 'Zermelo::Associations::UniqueIndex'
|
198
|
+
index_key = key_to_redis_key(Zermelo::Records::Key.new(
|
199
|
+
:klass => associated_class,
|
200
|
+
:name => "by_#{att}",
|
201
|
+
:type => :hash,
|
202
|
+
:object => :index
|
203
|
+
))
|
204
|
+
candidates = Zermelo.redis.hgetall(index_key)
|
205
|
+
matching_ids = candidates.values_at(*candidates.keys.select {|k|
|
206
|
+
(starts_with_string_re === k) &&
|
207
|
+
(value === unescape_key_name(k.sub(starts_with_string_re, '')))
|
208
|
+
})
|
209
|
+
Zermelo.redis.sadd(idx_result, matching_ids) unless matching_ids.empty?
|
210
|
+
when 'Zermelo::Associations::Index'
|
211
|
+
key_root = key_to_redis_key(Zermelo::Records::Key.new(
|
212
|
+
:klass => associated_class,
|
213
|
+
:name => "by_#{att}:string",
|
214
|
+
:type => :set,
|
215
|
+
:object => :index
|
216
|
+
))
|
217
|
+
|
218
|
+
matching_sets = Zermelo.redis.keys(key_root + ":*").inject([]) do |memo, k|
|
219
|
+
k =~ /^#{key_root}:(.+)$/
|
220
|
+
memo << k if value === $1
|
221
|
+
memo
|
222
|
+
end
|
223
|
+
|
224
|
+
Zermelo.redis.sunionstore(idx_result, matching_sets) unless matching_sets.empty?
|
225
|
+
end
|
226
|
+
idx_key
|
227
|
+
else
|
228
|
+
index = associated_class.send("#{att}_index")
|
229
|
+
|
230
|
+
case index
|
231
|
+
when Zermelo::Associations::UniqueIndex
|
232
|
+
idx_key = associated_class.send(:temp_key, :set)
|
233
|
+
temp_keys << idx_key
|
234
|
+
|
235
|
+
Zermelo.redis.sadd(key_to_redis_key(idx_key),
|
236
|
+
Zermelo.redis.hget(key_to_redis_key(index.key),
|
237
|
+
index_keys(attr_type, value).join(':')))
|
238
|
+
idx_key
|
239
|
+
when Zermelo::Associations::Index
|
240
|
+
index.key(value)
|
241
|
+
end
|
242
|
+
end
|
143
243
|
end
|
144
244
|
|
145
245
|
private
|
@@ -230,7 +330,7 @@ module Zermelo
|
|
230
330
|
|
231
331
|
elsif :purge.eql?(op)
|
232
332
|
# TODO get keys for all assocs & indices, purge them too
|
233
|
-
purges << ["#{key.klass}:#{key.id}:attrs"]
|
333
|
+
purges << ["#{key.klass.send(:class_key)}:#{key.id}:attrs"]
|
234
334
|
else
|
235
335
|
simple_attr_key = key_to_redis_key(key)
|
236
336
|
simple_attrs[simple_attr_key] ||= {}
|
data/lib/zermelo/filters/base.rb
CHANGED
@@ -2,15 +2,10 @@ require 'active_support/concern'
|
|
2
2
|
|
3
3
|
require 'zermelo/records/errors'
|
4
4
|
|
5
|
-
require 'zermelo/filters/steps/
|
6
|
-
require 'zermelo/filters/steps/
|
7
|
-
require 'zermelo/filters/steps/
|
8
|
-
require 'zermelo/filters/steps/intersect_step'
|
9
|
-
require 'zermelo/filters/steps/limit_step'
|
10
|
-
require 'zermelo/filters/steps/offset_step'
|
5
|
+
require 'zermelo/filters/steps/list_step'
|
6
|
+
require 'zermelo/filters/steps/set_step'
|
7
|
+
require 'zermelo/filters/steps/sorted_set_step'
|
11
8
|
require 'zermelo/filters/steps/sort_step'
|
12
|
-
require 'zermelo/filters/steps/union_range_step'
|
13
|
-
require 'zermelo/filters/steps/union_step'
|
14
9
|
|
15
10
|
module Zermelo
|
16
11
|
|
@@ -24,75 +19,74 @@ module Zermelo
|
|
24
19
|
|
25
20
|
# initial set a Zermelo::Record::Key object
|
26
21
|
# associated_class the class of the result record
|
27
|
-
def initialize(data_backend,
|
22
|
+
def initialize(data_backend, initial_key, associated_class, ancestor = nil, step = nil)
|
28
23
|
@backend = data_backend
|
29
|
-
@
|
24
|
+
@initial_key = initial_key
|
30
25
|
@associated_class = associated_class
|
31
26
|
@steps = ancestor.nil? ? [] : ancestor.steps.dup
|
32
27
|
@steps << step unless step.nil?
|
33
28
|
end
|
34
29
|
|
35
|
-
# TODO each step type have class methods list its acceptable input types, and
|
36
|
-
# have a class method giving its output type
|
37
|
-
|
38
30
|
def intersect(attrs = {})
|
39
|
-
self.class.new(@backend, @
|
40
|
-
::Zermelo::Filters::Steps::
|
31
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
32
|
+
::Zermelo::Filters::Steps::SetStep.new({:op => :intersect}, attrs))
|
41
33
|
end
|
42
34
|
|
43
35
|
def union(attrs = {})
|
44
|
-
self.class.new(@backend, @
|
45
|
-
::Zermelo::Filters::Steps::
|
36
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
37
|
+
::Zermelo::Filters::Steps::SetStep.new({:op => :union}, attrs))
|
46
38
|
end
|
47
39
|
|
48
40
|
def diff(attrs = {})
|
49
|
-
self.class.new(@backend, @
|
50
|
-
::Zermelo::Filters::Steps::
|
41
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
42
|
+
::Zermelo::Filters::Steps::SetStep.new({:op => :diff}, attrs))
|
51
43
|
end
|
52
44
|
|
53
45
|
def sort(keys, opts = {})
|
54
|
-
self.class.new(@backend, @
|
46
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
55
47
|
::Zermelo::Filters::Steps::SortStep.new({:keys => keys,
|
56
48
|
:desc => opts[:desc], :limit => opts[:limit],
|
57
49
|
:offset => opts[:offset]}, {})
|
58
50
|
)
|
59
51
|
end
|
60
52
|
|
61
|
-
def
|
62
|
-
self.class.new(@backend, @
|
63
|
-
::Zermelo::Filters::Steps::
|
53
|
+
def offset(amount, opts = {})
|
54
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
55
|
+
::Zermelo::Filters::Steps::ListStep.new({:offset => amount,
|
56
|
+
:limit => opts[:limit]}, {}))
|
64
57
|
end
|
65
58
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
59
|
+
def page(num, opts = {})
|
60
|
+
per_page = opts[:per_page].to_i || 20
|
61
|
+
start = per_page * (num - 1)
|
62
|
+
finish = start + (per_page - 1)
|
63
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
64
|
+
::Zermelo::Filters::Steps::ListStep.new({:offset => start,
|
65
|
+
:limit => per_page}, {}))
|
69
66
|
end
|
70
67
|
|
71
68
|
def intersect_range(start, finish, attrs_opts = {})
|
72
|
-
self.class.new(@backend, @
|
73
|
-
::Zermelo::Filters::Steps::
|
74
|
-
{:start => start, :finish => finish,
|
75
|
-
:desc => attrs_opts.delete(:desc),
|
69
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
70
|
+
::Zermelo::Filters::Steps::SortedSetStep.new(
|
71
|
+
{:op => :intersect_range, :start => start, :finish => finish,
|
76
72
|
:by_score => attrs_opts.delete(:by_score)},
|
77
73
|
attrs_opts)
|
78
74
|
)
|
79
75
|
end
|
80
76
|
|
81
77
|
def union_range(start, finish, attrs_opts = {})
|
82
|
-
self.class.new(@backend, @
|
83
|
-
::Zermelo::Filters::Steps::
|
84
|
-
{:start => start, :finish => finish,
|
85
|
-
:desc => attrs_opts.delete(:desc),
|
78
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
79
|
+
::Zermelo::Filters::Steps::SortedSetStep.new(
|
80
|
+
{:op => :union_range, :start => start, :finish => finish,
|
86
81
|
:by_score => attrs_opts.delete(:by_score)},
|
87
82
|
attrs_opts)
|
88
83
|
)
|
89
84
|
end
|
90
85
|
|
91
86
|
def diff_range(start, finish, attrs_opts = {})
|
92
|
-
self.class.new(@backend, @
|
93
|
-
::Zermelo::Filters::Steps::
|
94
|
-
{:start => start, :finish => finish,
|
95
|
-
:desc => attrs_opts.delete(:desc),
|
87
|
+
self.class.new(@backend, @initial_key, @associated_class, self,
|
88
|
+
::Zermelo::Filters::Steps::SortedSetStep.new(
|
89
|
+
{:op => :diff_range, :start => start, :finish => finish,
|
96
90
|
:by_score => attrs_opts.delete(:by_score)},
|
97
91
|
attrs_opts)
|
98
92
|
)
|
@@ -141,23 +135,6 @@ module Zermelo
|
|
141
135
|
lock { _all }
|
142
136
|
end
|
143
137
|
|
144
|
-
# NB makes no sense to apply this without order clause
|
145
|
-
def page(num, opts = {})
|
146
|
-
ret = nil
|
147
|
-
per_page = opts[:per_page].to_i || 20
|
148
|
-
if (num > 0) && (per_page > 0)
|
149
|
-
lock do
|
150
|
-
start = per_page * (num - 1)
|
151
|
-
finish = start + (per_page - 1)
|
152
|
-
@steps += [Zermelo::Filters::Steps::OffsetStep.new({:amount => start}, {}),
|
153
|
-
Zermelo::Filters::Steps::LimitStep.new({:amount => per_page}, {})]
|
154
|
-
page_ids = _ids
|
155
|
-
ret = page_ids.collect {|f_id| _load(f_id)} unless page_ids.nil?
|
156
|
-
end
|
157
|
-
end
|
158
|
-
ret || []
|
159
|
-
end
|
160
|
-
|
161
138
|
def collect(&block)
|
162
139
|
lock { _ids.collect {|id| block.call(_load(id))} }
|
163
140
|
end
|
@@ -191,11 +168,11 @@ module Zermelo
|
|
191
168
|
case klass.name
|
192
169
|
when ::Zermelo::Associations::BelongsTo.name
|
193
170
|
klass.send(:associated_ids_for, @backend,
|
194
|
-
@associated_class
|
171
|
+
@associated_class, name,
|
195
172
|
options[:inversed].is_a?(TrueClass), *_ids)
|
196
173
|
else
|
197
174
|
klass.send(:associated_ids_for, @backend,
|
198
|
-
@associated_class
|
175
|
+
@associated_class, name, *_ids)
|
199
176
|
end
|
200
177
|
}
|
201
178
|
end
|