zermelo 1.3.0 → 1.4.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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69911858d3394494076bade1249037f111eb5e7b
4
- data.tar.gz: 5b2c9e463d7fb0b71a7135bad76b481e4e18629a
3
+ metadata.gz: 41344d467203608ea5d05ba4e7e50ba3d0ba08c5
4
+ data.tar.gz: 62498b43b9556a7de290d83fc118ca0aa8ed6c48
5
5
  SHA512:
6
- metadata.gz: b2b62aabc2f4421d99e53bc298e260550d2124cb957786c6ef1bce894cb0fd43c0cd704a6378e6a6acfbc2cfebffda52412984756fc314f98322a2ea63cb7a23
7
- data.tar.gz: 69d7a165a1da92e759c6923828d12340d793eead6ee20681a0e22c9f7dde901b0421323ce0fd4c960bc708f5d84e9ebfab79bf166f638a3768032c8b75214074
6
+ metadata.gz: 475b586c7cca398659befa76233ff27eda95ead07db02b7ac56c3fdd8fbb4ef6ea724708da35ca9d3e471fa4f54023ea18129f145ec141053d6ea7bf601ee010
7
+ data.tar.gz: d3b7c8da76210b3d6f0c350bbc3601ec4d3f78c336864a1d885e5a9ac1682db0bd8575a16d68641869eb791a3799ee5e5ed92fdaeca7d0c936ccdc8df23c057c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Zermelo Changelog
2
2
 
3
+ # 1.4.0 - 2015-10-07
4
+
5
+ * store sorted_set ids in zset, makes some queries combine properly that
6
+ previously resulted in errors
7
+ * bugfix transactions, weren't applied properly
8
+
3
9
  # 1.3.0 - 2015-08-15
4
10
 
5
11
  * handle some Zermelo objects as query values, less data back-and-forth
@@ -114,7 +114,7 @@ module Zermelo
114
114
  idx_data = name.nil? ? @index_data : @index_data[name]
115
115
  yield idx_data unless idx_data.nil?
116
116
  end
117
- end
117
+ end
118
118
  # end used internally within Zermelo
119
119
 
120
120
  def add_index_data(klass, name, args = {})
@@ -82,7 +82,7 @@ module Zermelo
82
82
  def add_ids(*record_ids)
83
83
  raise 'No record ids to add' if record_ids.empty?
84
84
  @parent_klass.lock(*@lock_klasses) do
85
- records = @associated_class.find_by_ids!(*record_ids)
85
+ @associated_class.find_by_ids!(*record_ids) # ensure they exist
86
86
  _add_ids({:callbacks => true}, *record_ids)
87
87
  end
88
88
  end
@@ -155,20 +155,23 @@ module Zermelo
155
155
  when :has_many
156
156
  # inverse is belongs_to
157
157
  record_ids.each do |record_id|
158
- _inverse.id = record_id
159
- @backend.add(_inverse, "#{@inverse}_id" => @parent_id)
158
+ _inverse_copy = _inverse.clone
159
+ _inverse_copy.id = record_id
160
+ @backend.add(_inverse_copy, "#{@inverse}_id" => @parent_id)
160
161
  end
161
162
  when :has_sorted_set
162
163
  # inverse is belongs_to
163
- record_ids.each do |(score, record_id)|
164
- _inverse.id = record_id
165
- @backend.add(_inverse, "#{@inverse}_id" => @parent_id)
164
+ record_ids.each do |score_and_record_id|
165
+ _inverse_copy = _inverse.clone
166
+ _inverse_copy.id = score_and_record_id.last
167
+ @backend.add(_inverse_copy, "#{@inverse}_id" => @parent_id)
166
168
  end
167
169
  when :has_and_belongs_to_many
168
170
  # inverse is has_and_belongs_to_many
169
171
  record_ids.each do |record_id|
170
- _inverse.id = record_id
171
- @backend.add(_inverse, @parent_id)
172
+ _inverse_copy = _inverse.clone
173
+ _inverse_copy.id = record_id
174
+ @backend.add(_inverse_copy, @parent_id)
172
175
  end
173
176
  end
174
177
 
@@ -194,14 +197,16 @@ module Zermelo
194
197
  when :has_many, :has_sorted_set
195
198
  # inverse is belongs_to
196
199
  record_ids.each do |record_id|
197
- _inverse.id = record_id
198
- @backend.delete(_inverse, "#{@inverse}_id")
200
+ _inverse_copy = _inverse.clone
201
+ _inverse_copy.id = record_id
202
+ @backend.delete(_inverse_copy, "#{@inverse}_id")
199
203
  end
200
204
  when :has_and_belongs_to_many
201
205
  # inverse is has_and_belongs_to_many
202
206
  record_ids.each do |record_id|
203
- _inverse.id = record_id
204
- @backend.delete(_inverse, @parent_id)
207
+ _inverse_copy = _inverse.clone
208
+ _inverse_copy.id = record_id
209
+ @backend.delete(_inverse_copy, @parent_id)
205
210
  end
206
211
  end
207
212
 
@@ -12,6 +12,11 @@ module Zermelo
12
12
 
13
13
  include Zermelo::Backend
14
14
 
15
+ def initialize
16
+ @transaction_redis = nil
17
+ @changes = nil
18
+ end
19
+
15
20
  # def default_sorted_set_key
16
21
  # :timestamp
17
22
  # end
@@ -153,9 +158,9 @@ module Zermelo
153
158
  end
154
159
  end
155
160
 
156
- # TODO converge usage of idx_class and _index lookup invocation
161
+ def index_lookup(att, associated_class, type, idx_class, value,
162
+ attr_type, temp_keys)
157
163
 
158
- def index_lookup(att, associated_class, idx_class, value, attr_type, temp_keys)
159
164
  if (idx_class == Zermelo::Associations::RangeIndex) && !value.is_a?(Zermelo::Filters::IndexRange)
160
165
  raise "Range index must be passed a range"
161
166
  end
@@ -164,7 +169,7 @@ module Zermelo
164
169
  when Regexp
165
170
  raise "Can't query non-string values via regexp" unless :string.eql?(attr_type)
166
171
 
167
- idx_key = associated_class.send(:temp_key, :set)
172
+ idx_key = associated_class.send(:temp_key, type)
168
173
  temp_keys << idx_key
169
174
  idx_result = key_to_redis_key(idx_key)
170
175
 
@@ -182,7 +187,15 @@ module Zermelo
182
187
  (starts_with_string_re === k) &&
183
188
  (value === unescape_key_name(k.sub(starts_with_string_re, '')))
184
189
  })
185
- Zermelo.redis.sadd(idx_result, matching_ids) unless matching_ids.empty?
190
+
191
+ unless matching_ids.empty?
192
+ case type
193
+ when :set
194
+ Zermelo.redis.sadd(idx_result, matching_ids)
195
+ when :sorted_set
196
+ Zermelo.redis.zadd(idx_result, matching_ids.map {|m| [1, m]})
197
+ end
198
+ end
186
199
  when 'Zermelo::Associations::Index'
187
200
  key_root = key_to_redis_key(Zermelo::Records::Key.new(
188
201
  :klass => associated_class,
@@ -209,7 +222,14 @@ module Zermelo
209
222
  value === $1
210
223
  end
211
224
 
212
- Zermelo.redis.sunionstore(idx_result, matching_sets) unless matching_sets.empty?
225
+ unless matching_sets.empty?
226
+ case type
227
+ when :set
228
+ Zermelo.redis.sunionstore(idx_result, matching_sets)
229
+ when :sorted_set
230
+ Zermelo.redis.zunionstore(idx_result, matching_sets)
231
+ end
232
+ end
213
233
  end
214
234
  idx_key
215
235
  else
@@ -217,30 +237,20 @@ module Zermelo
217
237
 
218
238
  case index
219
239
  when Zermelo::Associations::RangeIndex
220
- r_index_key = key_to_redis_key(index.key)
221
- range = if value.by_score
222
- range_start = value.start.nil? ? '-inf' : safe_value(attr_type, value.start)
223
- range_finish = value.finish.nil? ? '+inf' : safe_value(attr_type, value.finish)
224
- Zermelo.redis.zrangebyscore(r_index_key, range_start, range_finish)
225
- else
226
- range_start = value.start || 0
227
- range_finish = value.finish || -1
228
- Zermelo.redis.zrange(r_index_key, range_start, range_finish)
229
- end
230
-
231
- # TODO another way for index_lookup to indicate 'empty result', rather
232
- # than creating & returning an empty key
233
- idx_key = associated_class.send(:temp_key, :set)
234
- temp_keys << idx_key
235
- Zermelo.redis.sadd(key_to_redis_key(idx_key), range) unless range.empty?
236
- idx_key
240
+ range_lookup(index.key, value, type, attr_type, associated_class, temp_keys)
237
241
  when Zermelo::Associations::UniqueIndex
238
- idx_key = associated_class.send(:temp_key, :set)
242
+ idx_key = associated_class.send(:temp_key, type)
239
243
  temp_keys << idx_key
240
244
 
241
- Zermelo.redis.sadd(key_to_redis_key(idx_key),
242
- Zermelo.redis.hget(key_to_redis_key(index.key),
243
- index_keys(attr_type, value).join(':')))
245
+ val = Zermelo.redis.hget(key_to_redis_key(index.key),
246
+ index_keys(attr_type, value).join(':'))
247
+
248
+ case type
249
+ when :set
250
+ Zermelo.redis.sadd(key_to_redis_key(idx_key), val)
251
+ when :sorted_set
252
+ Zermelo.redis.zadd(key_to_redis_key(idx_key), [1, val])
253
+ end
244
254
  idx_key
245
255
  when Zermelo::Associations::Index
246
256
  index.key(value)
@@ -248,15 +258,49 @@ module Zermelo
248
258
  end
249
259
  end
250
260
 
261
+ def range_lookup(key, range, type, attr_type, associated_class, temp_keys)
262
+ r_key = key_to_redis_key(key)
263
+ opts = case type
264
+ when :set
265
+ {}
266
+ when :sorted_set
267
+ {:with_scores => true}
268
+ end
269
+ result = if range.by_score
270
+ range_start = range.start.nil? ? '-inf' : safe_value(attr_type, range.start)
271
+ range_finish = range.finish.nil? ? '+inf' : safe_value(attr_type, range.finish)
272
+ Zermelo.redis.zrangebyscore(r_key, range_start, range_finish, opts)
273
+ else
274
+ range_start = range.start || 0
275
+ range_finish = range.finish || -1
276
+ Zermelo.redis.zrange(r_key, range_start, range_finish, opts)
277
+ end
278
+
279
+ # TODO another way for index_lookup to indicate 'empty result', rather
280
+ # than creating & returning an empty key
281
+ ret_key = associated_class.send(:temp_key, key.type)
282
+ temp_keys << ret_key
283
+ unless result.empty?
284
+ r_key = key_to_redis_key(ret_key)
285
+ case type
286
+ when :set
287
+ Zermelo.redis.sadd(r_key, result)
288
+ when :sorted_set
289
+ Zermelo.redis.zadd(r_key, result.map {|r| [r.last, r.first]})
290
+ end
291
+ end
292
+ ret_key
293
+ end
294
+
251
295
  private
252
296
 
253
297
  def change(op, key, value = nil, key_to = nil, value_to = nil)
254
298
  ch = [op, key, value, key_to, value_to]
255
- if @in_transaction
256
- @changes << ch
257
- else
299
+ if @transaction_redis.nil?
258
300
  apply_changes([ch])
301
+ return
259
302
  end
303
+ @changes << ch
260
304
  end
261
305
 
262
306
  def apply_changes(changes)
@@ -169,8 +169,8 @@ module Zermelo
169
169
  end
170
170
 
171
171
  def associations_for(name)
172
- data_type, type_klass = @associated_class.send(:with_association_data, name.to_sym) do |data|
173
- [data.data_type, data.type_klass]
172
+ data_type = @associated_class.send(:with_association_data, name.to_sym) do |data|
173
+ data.data_type
174
174
  end
175
175
 
176
176
  lock {
@@ -25,8 +25,8 @@ module Zermelo
25
25
  when Zermelo::Backends::Redis
26
26
 
27
27
  source = opts[:source]
28
- idx_attrs = opts[:index_attrs]
29
- attr_types = opts[:attr_types]
28
+ # idx_attrs = opts[:index_attrs]
29
+ # attr_types = opts[:attr_types]
30
30
  temp_keys = opts[:temp_keys]
31
31
 
32
32
  # TODO apply these transformations via a subset?
@@ -46,7 +46,7 @@ module Zermelo
46
46
  r_source, o, (o + l), :with_scores => true
47
47
  )
48
48
 
49
- Zermelo.redis.zadd(r_limited, lim.collect {|l| [l[1], l[0]]} )
49
+ Zermelo.redis.zadd(r_limited, lim.collect {|li| [li[1], li[0]]} )
50
50
 
51
51
  [limited, r_limited]
52
52
  when :list
@@ -26,9 +26,14 @@ module Zermelo
26
26
 
27
27
  source_keys = @attributes.each_with_object([]) do |(att, value), memo|
28
28
  idx_class = nil
29
+ use_sort_attr = false
29
30
  unless :id.eql?(att)
30
31
  idx_class = idx_attrs[att.to_s]
31
- raise "'#{att}' property is not indexed" if idx_class.nil?
32
+ if idx_class.nil?
33
+ use_sort_attr = :sorted_set.eql?(source.type) &&
34
+ att.eql?(associated_class.instance_variable_get('@sort_attribute'))
35
+ raise "'#{att}' property is not indexed" unless use_sort_attr
36
+ end
32
37
  end
33
38
 
34
39
  if [Set, Array].any? {|t| value.is_a?(t) }
@@ -37,7 +42,21 @@ module Zermelo
37
42
  r_conditions_set = backend.key_to_redis_key(conditions_set)
38
43
 
39
44
  backend.temp_key_wrap do |conditions_temp_keys|
40
- if idx_class.nil?
45
+ if use_sort_attr
46
+ range_keys = value.collect {|v|
47
+ rl = backend.range_lookup(associated_class.ids_key, v,
48
+ source_type, attr_types[att], associated_class, conditions_temp_keys)
49
+ backend.key_to_redis_key(rl)
50
+ }
51
+
52
+ case source.type
53
+ when :set
54
+ Zermelo.redis.sunionstore(r_conditions_set, *range_keys)
55
+ when :sorted_set
56
+ Zermelo.redis.zunionstore(r_conditions_set, range_keys)
57
+ end
58
+ elsif idx_class.nil?
59
+ # query against the :id field
41
60
  cond_objects, cond_ids = value.partition do |v|
42
61
  [Zermelo::Filter, Zermelo::Associations::Multiple].any? {|c| v.is_a?(c)}
43
62
  end
@@ -53,15 +72,33 @@ module Zermelo
53
72
  backend.key_to_redis_key(k)
54
73
  end
55
74
 
56
- Zermelo.redis.sunionstore(r_conditions_set, *cond_keys)
75
+ case source.type
76
+ when :set
77
+ Zermelo.redis.sunionstore(r_conditions_set, *cond_keys)
78
+ when :sorted_set
79
+ Zermelo.redis.zunionstore(r_conditions_set, cond_keys)
80
+ end
57
81
  end
58
82
  unless cond_ids.empty?
59
- cond_ids.map! {|ci| ci.is_a?(Zermelo::Associations::Singular) ? ci.id : ci }
60
- Zermelo.redis.sadd(r_conditions_set, cond_ids)
83
+ case source.type
84
+ when :set
85
+ s_ids = cond_ids.map {|ci| ci.is_a?(Zermelo::Associations::Singular) ? ci.id : ci }
86
+ Zermelo.redis.sadd(r_conditions_set, s_ids)
87
+ when :sorted_set
88
+ z_ids = cond_ids.map do |ci|
89
+ # is 1 a valid sort value? what's happening with it?
90
+ if ci.is_a?(Zermelo::Associations::Singular)
91
+ [1, ci.id]
92
+ else
93
+ [1, ci]
94
+ end
95
+ end
96
+ Zermelo.redis.zadd(r_conditions_set, z_ids)
97
+ end
61
98
  end
62
99
  else
63
- index_keys = value.to_a.collect {|v|
64
- il = backend.index_lookup(att, associated_class,
100
+ index_keys = value.collect {|v|
101
+ il = backend.index_lookup(att, associated_class, source.type,
65
102
  idx_class, v, attr_types[att], conditions_temp_keys)
66
103
  backend.key_to_redis_key(il)
67
104
  }
@@ -75,6 +112,9 @@ module Zermelo
75
112
  end
76
113
  end
77
114
  memo << conditions_set
115
+ elsif use_sort_attr
116
+ memo << backend.range_lookup(associated_class.ids_key, value,
117
+ source.type, attr_types[att], associated_class, temp_keys)
78
118
  elsif idx_class.nil?
79
119
  case value
80
120
  when Zermelo::Filter
@@ -84,15 +124,22 @@ module Zermelo
84
124
  when Zermelo::Associations::Multiple
85
125
  memo << value.instance_variable_get('@record_ids_key')
86
126
  else
87
- ts = associated_class.send(:temp_key, :set)
127
+ ts = associated_class.send(:temp_key, source.type)
88
128
  temp_keys << ts
89
129
  r_ts = backend.key_to_redis_key(ts)
90
- Zermelo.redis.sadd(r_ts,
91
- value.is_a?(Zermelo::Associations::Singular) ? value.id : value)
130
+ case source.type
131
+ when :set
132
+ s_id = value.is_a?(Zermelo::Associations::Singular) ? value.id : value
133
+ Zermelo.redis.sadd(r_ts, s_id)
134
+ when :sorted_set
135
+ # is 1 a valid sort value? what's happening with it?
136
+ z_id = [1, (value.is_a?(Zermelo::Associations::Singular) ? value.id : value)]
137
+ Zermelo.redis.zadd(r_ts, z_id)
138
+ end
92
139
  memo << ts
93
140
  end
94
141
  else
95
- memo << backend.index_lookup(att, associated_class,
142
+ memo << backend.index_lookup(att, associated_class, source.type,
96
143
  idx_class, value, attr_types[att], temp_keys)
97
144
  end
98
145
  end
@@ -16,7 +16,7 @@ module Zermelo
16
16
  case backend
17
17
  when Zermelo::Backends::Redis
18
18
  source = opts[:source]
19
- idx_attrs = opts[:index_attrs]
19
+ # idx_attrs = opts[:index_attrs]
20
20
  attr_types = opts[:attr_types]
21
21
  temp_keys = opts[:temp_keys]
22
22
 
@@ -12,9 +12,7 @@ require 'zermelo/records/class_methods'
12
12
  require 'zermelo/records/type_validator'
13
13
 
14
14
  module Zermelo
15
-
16
15
  module Record
17
-
18
16
  extend ActiveSupport::Concern
19
17
 
20
18
  include Zermelo::Records::InstMethods
@@ -31,11 +29,11 @@ module Zermelo
31
29
 
32
30
  # include ActiveModel::MassAssignmentSecurity
33
31
 
34
- @lock = Monitor.new
35
-
36
32
  extend Zermelo::Records::ClassMethods
37
33
  extend Zermelo::Associations::ClassMethods
38
34
 
35
+ @lock = Monitor.new
36
+
39
37
  attr_accessor :attributes
40
38
 
41
39
  define_model_callbacks :create, :update, :destroy
@@ -47,7 +45,5 @@ module Zermelo
47
45
 
48
46
  define_attributes :id => :string
49
47
  end
50
-
51
48
  end
52
-
53
49
  end
@@ -11,11 +11,8 @@ require 'zermelo/records/attributes'
11
11
  require 'zermelo/records/key'
12
12
 
13
13
  module Zermelo
14
-
15
14
  module Records
16
-
17
15
  module ClassMethods
18
-
19
16
  include Zermelo::Records::Attributes
20
17
 
21
18
  extend Forwardable
@@ -37,14 +34,6 @@ module Zermelo
37
34
  "%08x-%04x-%04x-%04x-%04x%08x" % ary
38
35
  end
39
36
 
40
- def add_id(id)
41
- backend.add(ids_key, id.to_s)
42
- end
43
-
44
- def delete_id(id)
45
- backend.delete(ids_key, id.to_s)
46
- end
47
-
48
37
  def lock(*klasses, &block)
49
38
  klasses += [self] unless klasses.include?(self)
50
39
  backend.lock(*klasses, &block)
@@ -57,7 +46,7 @@ module Zermelo
57
46
 
58
47
  begin
59
48
  yield
60
- rescue Exception => e
49
+ rescue Exception # => e
61
50
  backend.abort_transaction
62
51
  # p e.message
63
52
  # puts e.backtrace.join("\n")
@@ -94,14 +83,6 @@ module Zermelo
94
83
  self.name.demodulize.underscore
95
84
  end
96
85
 
97
- def ids_key
98
- @ids_key ||= Zermelo::Records::Key.new(
99
- :klass => self, :name => 'ids',
100
- :type => :set,
101
- :object => :attribute
102
- )
103
- end
104
-
105
86
  def temp_key(type)
106
87
  Zermelo::Records::Key.new(
107
88
  :klass => self,
@@ -119,9 +100,60 @@ module Zermelo
119
100
  def filter
120
101
  backend.filter(ids_key, self)
121
102
  end
103
+ end
104
+
105
+ module Unordered
106
+ extend ActiveSupport::Concern
107
+
108
+ module ClassMethods
109
+ def ids_key
110
+ @ids_key ||= Zermelo::Records::Key.new(
111
+ :klass => self, :name => 'ids',
112
+ :type => :set,
113
+ :object => :attribute
114
+ )
115
+ end
116
+
117
+ def add_id(id)
118
+ backend.add(ids_key, id)
119
+ end
122
120
 
121
+ def delete_id(id)
122
+ backend.delete(ids_key, id)
123
+ end
124
+ end
123
125
  end
124
126
 
125
- end
127
+ module Ordered
128
+ extend ActiveSupport::Concern
129
+
130
+ module ClassMethods
131
+ extend Forwardable
126
132
 
133
+ def_delegators :filter,
134
+ :first, :last
135
+
136
+ def ids_key
137
+ @ids_key ||= Zermelo::Records::Key.new(
138
+ :klass => self, :name => 'ids',
139
+ :type => :sorted_set,
140
+ :object => :attribute
141
+ )
142
+ end
143
+
144
+ def define_sort_attribute(k)
145
+ @sort_attribute = k
146
+ @sort_attribute_type = attribute_types[k.to_sym]
147
+ end
148
+
149
+ def add_id(id, val)
150
+ backend.add(ids_key, [backend.safe_value(@sort_attribute_type, val), id])
151
+ end
152
+
153
+ def delete_id(id)
154
+ backend.delete(ids_key, id)
155
+ end
156
+ end
157
+ end
158
+ end
127
159
  end
@@ -25,6 +25,7 @@ module Zermelo
25
25
  extend ActiveSupport::Concern
26
26
 
27
27
  include Zermelo::Record
28
+ include Zermelo::Records::Unordered
28
29
 
29
30
  included do
30
31
  set_backend :influxdb
@@ -83,6 +83,15 @@ module Zermelo
83
83
  creating = !self.persisted?
84
84
  saved = false
85
85
 
86
+ sort_val = nil
87
+ case self
88
+ when Zermelo::Records::Ordered
89
+ sort_attr = self.class.instance_variable_get('@sort_attribute')
90
+ raise 'Ordered record types must define_sort_attribute' if sort_attr.nil?
91
+ sort_val = @attributes[sort_attr.to_s]
92
+ raise "Value required for sort_attribute #{sort_attr}" if sort_val.nil?
93
+ end
94
+
86
95
  run_callbacks( (creating ? :create : :update) ) do
87
96
 
88
97
  idx_attrs = self.class.send(:with_index_data) do |d|
@@ -119,9 +128,16 @@ module Zermelo
119
128
  end
120
129
  end
121
130
 
122
- # ids is a set, so update won't create duplicates
131
+ # ids is a set/sorted set, so update won't create duplicates
123
132
  # NB influxdb backend doesn't need this
124
- self.class.add_id(@attributes['id'])
133
+
134
+ # FIXME distinguish between this in the class methods?
135
+ case self
136
+ when Zermelo::Records::Ordered
137
+ self.class.add_id(@attributes['id'], sort_val)
138
+ when Zermelo::Records::Unordered
139
+ self.class.add_id(@attributes['id'])
140
+ end
125
141
  end
126
142
 
127
143
  @is_new = false
@@ -4,10 +4,22 @@ require 'zermelo/record'
4
4
 
5
5
  module Zermelo
6
6
  module Records
7
- module Redis
7
+ module RedisSet
8
8
  extend ActiveSupport::Concern
9
9
 
10
10
  include Zermelo::Record
11
+ include Zermelo::Records::Unordered
12
+
13
+ included do
14
+ set_backend :redis
15
+ end
16
+ end
17
+
18
+ module RedisSortedSet
19
+ extend ActiveSupport::Concern
20
+
21
+ include Zermelo::Record
22
+ include Zermelo::Records::Ordered
11
23
 
12
24
  included do
13
25
  set_backend :redis
@@ -8,9 +8,9 @@ module Zermelo
8
8
  value = record.send(name)
9
9
  next if value.nil?
10
10
  valid_type = Zermelo::ALL_TYPES[type]
11
- unless valid_type.any? {|type| value.is_a?(type) }
11
+ unless valid_type.any? {|t| value.is_a?(t) }
12
12
  count = (valid_type.size > 1) ? 'one of ' : ''
13
- type_str = valid_type.collect {|type| type.name }.join(", ")
13
+ type_str = valid_type.collect {|t| t.name }.join(", ")
14
14
  record.errors.add(name, "should be #{count}#{type_str} but is #{value.class.name}")
15
15
  end
16
16
  end
@@ -1,3 +1,3 @@
1
1
  module Zermelo
2
- VERSION = '1.3.0'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -12,7 +12,7 @@ describe Zermelo::Associations::Index do
12
12
 
13
13
  module ZermeloExamples
14
14
  class RedisIndex
15
- include Zermelo::Records::Redis
15
+ include Zermelo::Records::RedisSet
16
16
  define_attributes :emotion => :string
17
17
  validates :emotion, :presence => true, :inclusion => {:in => %w(happy sad indifferent)}
18
18
  index_by :emotion
@@ -212,13 +212,13 @@ describe Zermelo::Associations::Multiple do
212
212
 
213
213
  module ZermeloExamples
214
214
  class AssociationsHasManyParentRedis
215
- include Zermelo::Records::Redis
215
+ include Zermelo::Records::RedisSet
216
216
  has_many :children, :class_name => 'ZermeloExamples::AssociationsHasManyChildRedis',
217
217
  :inverse_of => :parent
218
218
  end
219
219
 
220
220
  class AssociationsHasManyChildRedis
221
- include Zermelo::Records::Redis
221
+ include Zermelo::Records::RedisSet
222
222
  define_attributes :important => :boolean
223
223
  index_by :important
224
224
  belongs_to :parent, :class_name => 'ZermeloExamples::AssociationsHasManyParentRedis',
@@ -671,7 +671,7 @@ describe Zermelo::Associations::Multiple do
671
671
 
672
672
  module ZermeloExamples
673
673
  class AssociationsHasAndBelongsToManyPrimaryRedis
674
- include Zermelo::Records::Redis
674
+ include Zermelo::Records::RedisSet
675
675
  define_attributes :active => :boolean
676
676
  index_by :active
677
677
  has_and_belongs_to_many :secondaries,
@@ -680,7 +680,7 @@ describe Zermelo::Associations::Multiple do
680
680
  end
681
681
 
682
682
  class AssociationsHasAndBelongsToManySecondaryRedis
683
- include Zermelo::Records::Redis
683
+ include Zermelo::Records::RedisSet
684
684
  # define_attributes :important => :boolean
685
685
  # index_by :important
686
686
  has_and_belongs_to_many :primaries,
@@ -773,7 +773,7 @@ describe Zermelo::Associations::Multiple do
773
773
 
774
774
  module ZermeloExamples
775
775
  class AssociationsHasSortedSetParentRedis
776
- include Zermelo::Records::Redis
776
+ include Zermelo::Records::RedisSet
777
777
  has_sorted_set :children, :class_name => 'ZermeloExamples::AssociationsHasSortedSetChildRedis',
778
778
  :inverse_of => :parent, :key => :timestamp
779
779
  has_sorted_set :reversed_children, :class_name => 'ZermeloExamples::AssociationsHasSortedSetChildRedis',
@@ -781,11 +781,11 @@ describe Zermelo::Associations::Multiple do
781
781
  end
782
782
 
783
783
  class AssociationsHasSortedSetChildRedis
784
- include Zermelo::Records::Redis
784
+ include Zermelo::Records::RedisSortedSet
785
785
  define_attributes :emotion => :string,
786
786
  :timestamp => :timestamp
787
+ define_sort_attribute :timestamp
787
788
  index_by :emotion
788
- range_index_by :timestamp
789
789
  belongs_to :parent, :class_name => 'ZermeloExamples::AssociationsHasSortedSetParentRedis',
790
790
  :inverse_of => :children
791
791
  belongs_to :reversed_parent, :class_name => 'ZermeloExamples::AssociationsHasSortedSetParentRedis',
@@ -811,10 +811,9 @@ describe Zermelo::Associations::Multiple do
811
811
  'timestamp' => attrs[:timestamp].to_f}.to_a.flatten)
812
812
 
813
813
  redis.sadd("#{ck}::indices:by_emotion:string:#{attrs[:emotion]}", attrs[:id])
814
- redis.zadd("#{ck}::indices:by_timestamp", attrs[:timestamp].to_f, attrs[:id])
815
814
  redis.hmset("#{ck}:#{attrs[:id]}:assocs:belongs_to",
816
815
  {'parent_id' => parent.id}.to_a.flatten) unless parent.nil?
817
- redis.sadd("#{ck}::attrs:ids", attrs[:id])
816
+ redis.zadd("#{ck}::attrs:ids", attrs[:timestamp].to_f, attrs[:id])
818
817
  end
819
818
 
820
819
  def create_reversed_child(parent, attrs = {})
@@ -824,10 +823,9 @@ describe Zermelo::Associations::Multiple do
824
823
  'timestamp' => attrs[:timestamp].to_f}.to_a.flatten)
825
824
 
826
825
  redis.sadd("#{ck}::indices:by_emotion:string:#{attrs[:emotion]}", attrs[:id])
827
- redis.zadd("#{ck}::indices:by_timestamp", attrs[:timestamp].to_f, attrs[:id])
828
826
  redis.hmset("#{ck}:#{attrs[:id]}:assocs:belongs_to",
829
827
  {'reversed_parent_id' => parent.id}.to_a.flatten) unless parent.nil?
830
- redis.sadd("#{ck}::attrs:ids", attrs[:id])
828
+ redis.zadd("#{ck}::attrs:ids", attrs[:timestamp].to_f, attrs[:id])
831
829
  end
832
830
 
833
831
  let(:parent) {
@@ -846,11 +844,10 @@ describe Zermelo::Associations::Multiple do
846
844
  "#{pk}:8:assocs:children_ids",
847
845
  "#{ck}::attrs:ids",
848
846
  "#{ck}::indices:by_emotion:string:indifferent",
849
- "#{ck}::indices:by_timestamp",
850
847
  "#{ck}:4:attrs",
851
848
  "#{ck}:4:assocs:belongs_to"])
852
849
 
853
- expect(redis.smembers("#{ck}::attrs:ids")).to eq(['4'])
850
+ expect(redis.zrange("#{ck}::attrs:ids", 0, -1)).to eq(['4'])
854
851
  expect(redis.hgetall("#{ck}:4:attrs")).to eq(
855
852
  {'emotion' => 'indifferent', 'timestamp' => time.to_f.to_s}
856
853
  )
@@ -882,12 +879,12 @@ describe Zermelo::Associations::Multiple do
882
879
  create_child(parent, :id => '4', :emotion => 'indifferent', :timestamp => time)
883
880
  child = child_class.find_by_id('4')
884
881
 
885
- expect(redis.smembers("#{ck}::attrs:ids")).to eq(['4'])
882
+ expect(redis.zrange("#{ck}::attrs:ids", 0, -1)).to eq(['4'])
886
883
  expect(redis.zrange("#{pk}:8:assocs:children_ids", 0, -1)).to eq(['4'])
887
884
 
888
885
  parent.children.remove(child)
889
886
 
890
- expect(redis.smembers("#{ck}::attrs:ids")).to eq(['4']) # child not deleted
887
+ expect(redis.zrange("#{ck}::attrs:ids", 0, -1)).to eq(['4']) # child not deleted
891
888
  expect(redis.zrange("#{pk}:8:assocs:children_ids", 0, -1)).to eq([]) # but association is
892
889
  end
893
890
 
@@ -898,7 +895,6 @@ describe Zermelo::Associations::Multiple do
898
895
  expect(redis.keys).to match_array(["#{pk}::attrs:ids",
899
896
  "#{pk}:8:assocs:children_ids",
900
897
  "#{ck}::attrs:ids",
901
- "#{ck}::indices:by_timestamp",
902
898
  "#{ck}::indices:by_emotion:string:upset",
903
899
  "#{ck}:6:attrs",
904
900
  "#{ck}:6:assocs:belongs_to"])
@@ -906,7 +902,6 @@ describe Zermelo::Associations::Multiple do
906
902
  parent.destroy
907
903
 
908
904
  expect(redis.keys).to match_array(["#{ck}::attrs:ids",
909
- "#{ck}::indices:by_timestamp",
910
905
  "#{ck}::indices:by_emotion:string:upset",
911
906
  "#{ck}:6:attrs"])
912
907
  end
@@ -12,10 +12,10 @@ describe Zermelo::Associations::RangeIndex do
12
12
 
13
13
  module ZermeloExamples
14
14
  class RedisRangeIndex
15
- include Zermelo::Records::Redis
15
+ include Zermelo::Records::RedisSet
16
16
  define_attributes :created_at => :timestamp
17
- validates :created_at, :presence => true
18
17
  range_index_by :created_at
18
+ validates :created_at, :presence => true
19
19
  end
20
20
  end
21
21
 
@@ -42,13 +42,13 @@ describe Zermelo::Associations::Singular do
42
42
 
43
43
  module ZermeloExamples
44
44
  class AssociationsHasOneParentRedis
45
- include Zermelo::Records::Redis
45
+ include Zermelo::Records::RedisSet
46
46
  has_one :child, :class_name => 'ZermeloExamples::AssociationsHasOneChildRedis',
47
47
  :inverse_of => :parent
48
48
  end
49
49
 
50
50
  class AssociationsHasOneChildRedis
51
- include Zermelo::Records::Redis
51
+ include Zermelo::Records::RedisSet
52
52
  belongs_to :parent, :class_name => 'ZermeloExamples::AssociationsHasOneParentRedis',
53
53
  :inverse_of => :child
54
54
  end
@@ -10,7 +10,7 @@ describe Zermelo::Associations::UniqueIndex do
10
10
 
11
11
  module ZermeloExamples
12
12
  class RedisUniqueIndex
13
- include Zermelo::Records::Redis
13
+ include Zermelo::Records::RedisSet
14
14
  define_attributes :name => :string
15
15
  validates :name, :presence => true
16
16
  unique_index_by :name
@@ -229,7 +229,7 @@ describe Zermelo::Filter do
229
229
 
230
230
  module ZermeloExamples
231
231
  class FilterRedis
232
- include Zermelo::Records::Redis
232
+ include Zermelo::Records::RedisSet
233
233
  define_attributes :name => :string,
234
234
  :active => :boolean,
235
235
  :created_at => :timestamp
@@ -8,12 +8,12 @@ describe Zermelo::Locks::RedisLock, :redis => true do
8
8
 
9
9
  module Zermelo
10
10
  class RedisLockExample
11
- include Zermelo::Records::Redis
11
+ include Zermelo::Records::RedisSet
12
12
  define_attributes :name => :string
13
13
  end
14
14
 
15
15
  class AnotherExample
16
- include Zermelo::Records::Redis
16
+ include Zermelo::Records::RedisSet
17
17
  define_attributes :age => :integer
18
18
  end
19
19
  end
@@ -89,7 +89,7 @@ describe Zermelo::Records::InstMethods do
89
89
 
90
90
  module ZermeloExamples
91
91
  class InstanceMethodsRedis
92
- include Zermelo::Records::Redis
92
+ include Zermelo::Records::RedisSet
93
93
 
94
94
  define_attributes :name => :string
95
95
  validates :name, :presence => true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zermelo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali Graham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-15 00:00:00.000000000 Z
11
+ date: 2015-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -137,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  requirements:
138
138
  - Redis and/or InfluxDB, and the related gems
139
139
  rubyforge_project:
140
- rubygems_version: 2.4.8
140
+ rubygems_version: 2.4.5.1
141
141
  signing_key:
142
142
  specification_version: 4
143
143
  summary: ActiveModel-based set-theoretic ORM for Redis/InfluxDB