redis_orm 0.5.1 → 0.6

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ v0.6 [12-09-2011]
2
+ * added equality operator for object, #to_s method for inspecting objects, #find! which could throw RecordNotFound error
3
+ * added self.descendants class method which returns all inherited from RedisOrm::Base classes
4
+ * introduced :sortable option (in property declaration and #find conditions hash) - rudimentary ability to sort records by any property (not just by default 'created_at')
5
+ * now handling models withing modules definitions (test for this in associations_test.rb)
6
+ * properly handling :as parameter in options for has_many/belongs_to self-references
7
+ * binding related models while creating model instance (like this: Article.create(:comment => comment))
8
+ * bunch of small fixes, updated tests and README.md
9
+
1
10
  v0.5.1 [27-07-2011]
2
11
  * added support of uuid as an id/primary key
3
12
  * added documentation on uuid support and connection to the redis server
data/Manifest CHANGED
@@ -11,6 +11,7 @@ lib/redis_orm/associations/has_many_helper.rb
11
11
  lib/redis_orm/associations/has_many_proxy.rb
12
12
  lib/redis_orm/associations/has_one.rb
13
13
  lib/redis_orm/redis_orm.rb
14
+ lib/redis_orm/utils.rb
14
15
  redis_orm.gemspec
15
16
  test/association_indices_test.rb
16
17
  test/associations_test.rb
@@ -23,6 +24,7 @@ test/exceptions_test.rb
23
24
  test/has_one_has_many_test.rb
24
25
  test/indices_test.rb
25
26
  test/options_test.rb
27
+ test/order_test.rb
26
28
  test/polymorphic_test.rb
27
29
  test/redis.conf
28
30
  test/test_helper.rb
data/README.md CHANGED
@@ -27,6 +27,18 @@ class User < RedisOrm::Base
27
27
  end
28
28
  ```
29
29
 
30
+ ## Installing redis_orm
31
+
32
+ gem install redis_orm
33
+
34
+ or
35
+
36
+ git clone git://github.com/german/redis_orm.git
37
+
38
+ cd redis_orm
39
+
40
+ bundle install
41
+
30
42
  ## Setting up a connection to the redis server
31
43
 
32
44
  If you are using Rails you should initialize redis and set up global $redis variable in *config/initializers/redis.rb* file:
@@ -68,6 +80,10 @@ Following options are available in property declaration:
68
80
 
69
81
  The default value of the attribute when it's getting saved w/o any.
70
82
 
83
+ * **:sortable**
84
+
85
+ if *true* is specified then you could sort records by this property later
86
+
71
87
  ## Searching records by the value
72
88
 
73
89
  Usually it's done via declaring an index and using *:conditions* hash or dynamic finders. For example:
@@ -102,7 +118,11 @@ To extract all or part of the associated records you could use 4 options:
102
118
 
103
119
  * :order
104
120
 
105
- Either :desc or :asc (default), since records are stored with *Time.now.to_f* scores, by default they could be fetched only in that (or reversed) order. To store them in different order you should *zadd* record's id to some other sorted list manually.
121
+ Either :desc or :asc (default), since records are stored with *Time.now.to_f* scores, by default they could be fetched only in that (or reversed) order. To order by different property you should:
122
+
123
+ 1. specify *:sortable => true* as option in property declaration
124
+
125
+ 2. specify the property by which you wish to order *:order => [:name, :desc]* or *:order => [:name]* (:asc order is default)
106
126
 
107
127
  * :conditions
108
128
 
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake'
4
4
  #=begin
5
5
  require 'echoe'
6
6
 
7
- Echoe.new('redis_orm', '0.5.1') do |p|
7
+ Echoe.new('redis_orm', '0.6') do |p|
8
8
  p.description = "ORM for Redis (advanced key-value storage) with ActiveRecord API"
9
9
  p.url = "https://github.com/german/redis_orm"
10
10
  p.author = "Dmitrii Samoilov"
@@ -26,8 +26,13 @@ Rake::TestTask.new(:test) do |t|
26
26
  end
27
27
  =end
28
28
 
29
+ #require 'rspec/core/rake_task'
29
30
  task :test do |t|
30
31
  Dir['test/**/*_test.rb'].each do |file|
31
32
  puts `ruby -I./lib #{file}`
32
33
  end
33
34
  end
35
+ #task :default => :test
36
+ #RSpec::Core::RakeTask.new(:spec) do |t|
37
+ # t.pattern = 'test/**/*_test.rb'
38
+ #end
data/lib/redis_orm.rb CHANGED
@@ -13,6 +13,8 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'associ
13
13
  require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'associations', 'has_many')
14
14
  require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'associations', 'has_one')
15
15
 
16
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'redis_orm', 'utils')
17
+
16
18
  class String
17
19
  def i18n_key
18
20
  self.to_s.tableize
@@ -1,14 +1,12 @@
1
1
  module ActiveModelBehavior
2
2
  module ClassMethods
3
3
  def model_name
4
- #@_model_name ||= ActiveModel::Name.new(self).to_s.downcase
5
4
  @_model_name ||= ActiveModel::Name.new(self).to_s.tableize.singularize
6
5
  end
7
6
  end
8
7
 
9
8
  module InstanceMethods
10
9
  def model_name
11
- #@_model_name ||= ActiveModel::Name.new(self.class).to_s.downcase
12
10
  @_model_name ||= ActiveModel::Name.new(self.class).to_s.tableize.singularize
13
11
  end
14
12
  end
@@ -14,20 +14,22 @@ module RedisOrm
14
14
  class_associations = class_variable_get(:"@@associations")
15
15
  class_variable_get(:"@@associations")[model_name] << {:type => :belongs_to, :foreign_model => foreign_model, :options => options}
16
16
 
17
- foreign_model_name = if options[:as]
18
- options[:as].to_sym
19
- else
20
- foreign_model.to_sym
21
- end
22
-
23
- define_method foreign_model_name.to_sym do
17
+ foreign_model_name = options[:as] ? options[:as].to_sym : foreign_model.to_sym
18
+
19
+ define_method foreign_model_name do
24
20
  if options[:polymorphic]
25
21
  model_type = $redis.get("#{model_name}:#{id}:#{foreign_model_name}_type")
26
22
  if model_type
27
23
  model_type.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}_id")
28
24
  end
29
25
  else
30
- foreign_model.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
26
+ # find model even if it's in some module
27
+ full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
28
+ if full_model_scope
29
+ full_model_scope.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
30
+ else
31
+ foreign_model.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
32
+ end
31
33
  end
32
34
  end
33
35
 
@@ -36,6 +38,8 @@ module RedisOrm
36
38
  define_method "#{foreign_model_name}=" do |assoc_with_record|
37
39
  # we need to store this to clear old association later
38
40
  old_assoc = self.send(foreign_model_name)
41
+ # find model even if it's in some module
42
+ full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
39
43
 
40
44
  if options[:polymorphic]
41
45
  $redis.set("#{model_name}:#{id}:#{foreign_model_name}_type", assoc_with_record.model_name)
@@ -43,7 +47,7 @@ module RedisOrm
43
47
  else
44
48
  if assoc_with_record.nil?
45
49
  $redis.del("#{model_name}:#{id}:#{foreign_model_name}")
46
- elsif assoc_with_record.model_name == foreign_model.to_s
50
+ elsif [foreign_model.to_s, full_model_scope.model_name].include?(assoc_with_record.model_name)
47
51
  $redis.set("#{model_name}:#{id}:#{foreign_model_name}", assoc_with_record.id)
48
52
  else
49
53
  raise TypeMismatchError
@@ -8,11 +8,7 @@ module RedisOrm
8
8
  class_associations = class_variable_get(:"@@associations")
9
9
  class_associations[model_name] << {:type => :has_many, :foreign_models => foreign_models, :options => options}
10
10
 
11
- foreign_models_name = if options[:as]
12
- options[:as].to_sym
13
- else
14
- foreign_models.to_sym
15
- end
11
+ foreign_models_name = options[:as] ? options[:as].to_sym : foreign_models.to_sym
16
12
 
17
13
  define_method foreign_models_name.to_sym do
18
14
  Associations::HasManyProxy.new(model_name, id, foreign_models, options)
@@ -51,17 +47,20 @@ module RedisOrm
51
47
  save_index_for_associated_record(index, record, [model_name, id, record.model_name.pluralize]) # record.model_name.pluralize => foreign_models_name
52
48
  end
53
49
 
54
- if !options[:as]
55
- # article.comments = [comment1, comment2]
56
- # iterate through the array of comments and create backlink
57
- # check whether *record* object has *has_many* declaration and TODO it states *self.model_name* in plural
58
- if class_associations[record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} #&& !$redis.zrank("#{record.model_name}:#{record.id}:#{model_name.pluralize}", id)#record.model_name.to_s.camelize.constantize.find(id).nil?
59
- $redis.zadd("#{record.model_name}:#{record.id}:#{model_name.pluralize}", Time.now.to_f, id)
60
- # check whether *record* object has *has_one* declaration and TODO it states *self.model_name*
61
- elsif record.get_associations.detect{|h| [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym}
62
- # overwrite assoc anyway so we don't need to check record.send(model_name.to_sym).nil? here
63
- $redis.set("#{record.model_name}:#{record.id}:#{model_name}", id)
64
- end
50
+ # article.comments = [comment1, comment2]
51
+ # iterate through the array of comments and create backlink
52
+ # check whether *record* object has *has_many* declaration and it states *self.model_name* in plural
53
+ if assoc = class_associations[record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} #&& !$redis.zrank("#{record.model_name}:#{record.id}:#{model_name.pluralize}", id)#record.model_name.to_s.camelize.constantize.find(id).nil?
54
+ assoc_foreign_models_name = assoc[:options][:as] ? assoc[:options][:as] : model_name.pluralize
55
+ key = "#{record.model_name}:#{record.id}:#{assoc_foreign_models_name}"
56
+ $redis.zadd(key, Time.now.to_f, id) if !$redis.zrank(key, id)
57
+ end
58
+
59
+ # check whether *record* object has *has_one* declaration and it states *self.model_name*
60
+ if assoc = record.get_associations.detect{|h| [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym}
61
+ foreign_model_name = assoc[:options][:as] ? assoc[:options][:as] : model_name
62
+ # overwrite assoc anyway so we don't need to check record.send(model_name.to_sym).nil? here
63
+ $redis.set("#{record.model_name}:#{record.id}:#{foreign_model_name}", id)
65
64
  end
66
65
  end
67
66
  end
@@ -82,7 +82,7 @@ module RedisOrm
82
82
  prepared_index = if options[:conditions] && options[:conditions].is_a?(Hash)
83
83
  properties = options[:conditions].collect{|key, value| key}
84
84
 
85
- index = @foreign_models.to_s.singularize.camelize.constantize.find_index(properties)
85
+ index = @foreign_models.to_s.singularize.camelize.constantize.find_indices(properties, :first => true)
86
86
 
87
87
  raise NotIndexFound if !index
88
88
 
@@ -20,6 +20,9 @@ module RedisOrm
20
20
  class NotIndexFound < StandardError
21
21
  end
22
22
 
23
+ class RecordNotFound < StandardError
24
+ end
25
+
23
26
  class TypeMismatchError < StandardError
24
27
  end
25
28
 
@@ -29,7 +32,7 @@ module RedisOrm
29
32
  class Base
30
33
  include ActiveModel::Validations
31
34
  include ActiveModelBehavior
32
-
35
+ include Utils
33
36
  include Associations::HasManyHelper
34
37
 
35
38
  extend Associations::BelongsTo
@@ -39,10 +42,11 @@ module RedisOrm
39
42
  attr_accessor :persisted
40
43
 
41
44
  @@properties = Hash.new{|h,k| h[k] = []}
42
- @@indices = Hash.new{|h,k| h[k] = []} # compound indices are available too
45
+ @@indices = Hash.new{|h,k| h[k] = []} # compound indices are available too
43
46
  @@associations = Hash.new{|h,k| h[k] = []}
44
47
  @@callbacks = Hash.new{|h,k| h[k] = {}}
45
48
  @@use_uuid_as_id = {}
49
+ @@descendants = []
46
50
 
47
51
  class << self
48
52
 
@@ -50,8 +54,14 @@ module RedisOrm
50
54
  [:after_save, :before_save, :after_create, :before_create, :after_destroy, :before_destroy].each do |callback_name|
51
55
  @@callbacks[from.model_name][callback_name] = []
52
56
  end
57
+
58
+ @@descendants << from
53
59
  end
54
-
60
+
61
+ def descendants
62
+ @@descendants
63
+ end
64
+
55
65
  # *options* currently supports
56
66
  # *unique* Boolean
57
67
  # *case_insensitive* Boolean
@@ -126,20 +136,29 @@ module RedisOrm
126
136
  $redis.zcard("#{model_name}:ids").to_i
127
137
  end
128
138
 
129
- def first
130
- id = $redis.zrangebyscore("#{model_name}:ids", 0, Time.now.to_f, :limit => [0, 1])
131
- id.empty? ? nil : find(id[0])
139
+ def first(options = {})
140
+ if options.empty?
141
+ id = $redis.zrangebyscore("#{model_name}:ids", 0, Time.now.to_f, :limit => [0, 1])
142
+ id.empty? ? nil : find(id[0])
143
+ else
144
+ find(:first, options)
145
+ end
132
146
  end
133
147
 
134
- def last
135
- id = $redis.zrevrangebyscore("#{model_name}:ids", Time.now.to_f, 0, :limit => [0, 1])
136
- id.empty? ? nil : find(id[0])
148
+ def last(options = {})
149
+ if options.empty?
150
+ id = $redis.zrevrangebyscore("#{model_name}:ids", Time.now.to_f, 0, :limit => [0, 1])
151
+ id.empty? ? nil : find(id[0])
152
+ else
153
+ find(:last, options)
154
+ end
137
155
  end
138
-
139
- def find_index(properties)
156
+
157
+ def find_indices(properties, options = {})
140
158
  properties.map!{|p| p.to_sym}
141
-
142
- @@indices[model_name].detect do |models_index|
159
+ method = options[:first] ? :detect : :select
160
+
161
+ @@indices[model_name].send(method) do |models_index|
143
162
  if models_index[:name].is_a?(Array) && models_index[:name].size == properties.size
144
163
  # check the elements not taking into account their order
145
164
  (models_index[:name] & properties).size == properties.size
@@ -168,6 +187,7 @@ module RedisOrm
168
187
  prepared_index
169
188
  end
170
189
 
190
+ # TODO refactor this messy function
171
191
  def all(options = {})
172
192
  limit = if options[:limit] && options[:offset]
173
193
  [options[:offset].to_i, options[:limit].to_i]
@@ -175,29 +195,49 @@ module RedisOrm
175
195
  [0, options[:limit].to_i]
176
196
  end
177
197
 
178
- if options[:conditions] && options[:conditions].is_a?(Hash)
198
+ order_max_limit = Time.now.to_f
199
+ ids_key = "#{model_name}:ids"
200
+ index = nil
201
+
202
+ prepared_index = if !options[:conditions].blank? && options[:conditions].is_a?(Hash)
179
203
  properties = options[:conditions].collect{|key, value| key}
180
- index = find_index(properties)
204
+ index = find_indices(properties, :first => true)
181
205
 
182
206
  raise NotIndexFound if !index
183
-
184
- prepared_index = construct_prepared_index(index, options[:conditions])
185
207
 
186
- records = []
208
+ construct_prepared_index(index, options[:conditions])
209
+ else
210
+ if options[:order] && options[:order].is_a?(Array)
211
+ model_name
212
+ else
213
+ ids_key
214
+ end
215
+ end
187
216
 
188
- if index[:options][:unique]
189
- id = $redis.get prepared_index
190
- records << model_name.to_s.camelize.constantize.find(id)
217
+ # if not array => created_at native order (in which ids were pushed to "#{model_name}:ids" set by default)
218
+ direction = if !options[:order].blank?
219
+ if options[:order].is_a?(Array)
220
+ # for String values max limit for search key could be 1.0, but for Numeric values there's actually no limit
221
+ order_max_limit = 100_000_000_000
222
+ ids_key = "#{prepared_index}:#{options[:order].first}_ids"
223
+ options[:order].size == 2 ? options[:order].last : 'asc'
191
224
  else
192
- ids = $redis.zrangebyscore(prepared_index, 0, Time.now.to_f)
193
- records += model_name.to_s.camelize.constantize.find(ids)
194
- end
195
- records
225
+ ids_key = prepared_index
226
+ options[:order]
227
+ end
228
+ else
229
+ ids_key = prepared_index
230
+ 'asc'
231
+ end
232
+
233
+ if index && index[:options][:unique]
234
+ id = $redis.get prepared_index
235
+ model_name.to_s.camelize.constantize.find(id)
196
236
  else
197
- if options[:order].to_s == 'desc'
198
- $redis.zrevrangebyscore("#{model_name}:ids", Time.now.to_f, 0, :limit => limit).compact.collect{|id| find(id)}
237
+ if direction.to_s == 'desc'
238
+ $redis.zrevrangebyscore(ids_key, order_max_limit, 0, :limit => limit).compact.collect{|id| find(id)}
199
239
  else
200
- $redis.zrangebyscore("#{model_name}:ids", 0, Time.now.to_f, :limit => limit).compact.collect{|id| find(id)}
240
+ $redis.zrangebyscore(ids_key, 0, order_max_limit, :limit => limit).compact.collect{|id| find(id)}
201
241
  end
202
242
  end
203
243
  end
@@ -235,6 +275,15 @@ module RedisOrm
235
275
  end
236
276
  end
237
277
 
278
+ def find!(*args)
279
+ result = find(*args)
280
+ if result.nil?
281
+ raise RecordNotFound
282
+ else
283
+ result
284
+ end
285
+ end
286
+
238
287
  def after_save(callback)
239
288
  @@callbacks[model_name][:after_save] << callback
240
289
  end
@@ -262,9 +311,19 @@ module RedisOrm
262
311
  def create(options = {})
263
312
  obj = new(options, nil, false)
264
313
  obj.save
314
+
315
+ # make possible binding related models while creating class instance
316
+ options.each do |k, v|
317
+ if @@associations[model_name].detect{|h| h[:foreign_model] == k || h[:options][:as] == k}
318
+ obj.send("#{k}=", v)
319
+ end
320
+ end
321
+
265
322
  obj
266
323
  end
267
324
 
325
+ alias :create! :create
326
+
268
327
  # dynamic finders
269
328
  def method_missing(method_name, *args, &block)
270
329
  if method_name =~ /^find_(all_)?by_(\w*)/
@@ -276,7 +335,7 @@ module RedisOrm
276
335
  properties.each_with_index do |prop, i|
277
336
  properties_hash.merge!({prop.to_sym => args[i]})
278
337
  end
279
- find_index(properties)
338
+ find_indices(properties, :first => true)
280
339
  end
281
340
 
282
341
  raise NotIndexFound if !index
@@ -314,7 +373,7 @@ module RedisOrm
314
373
  def to_a
315
374
  [self]
316
375
  end
317
-
376
+
318
377
  # is called from RedisOrm::Associations::HasMany to save backlinks to saved records
319
378
  def get_associations
320
379
  @@associations[self.model_name]
@@ -328,6 +387,7 @@ module RedisOrm
328
387
  def initialize(attributes = {}, id = nil, persisted = false)
329
388
  @persisted = persisted
330
389
 
390
+ # if this model uses uuid then id is a string otherwise it should be casted to Integer class
331
391
  id = @@use_uuid_as_id[model_name] ? id : id.to_i
332
392
 
333
393
  instance_variable_set(:"@id", id) if id
@@ -353,6 +413,31 @@ module RedisOrm
353
413
  @id
354
414
  end
355
415
 
416
+ alias :to_key :id
417
+
418
+ def to_s
419
+ inspected = "<#{model_name.capitalize} id: #{@id}, "
420
+ inspected += @@properties[model_name].inject([]) do |sum, prop|
421
+ property_value = instance_variable_get(:"@#{prop[:name]}")
422
+ property_value = '"' + property_value.to_s + '"' if prop[:class].eql?("String")
423
+ property_value = 'nil' if property_value.nil?
424
+ sum << "#{prop[:name]}: " + property_value.to_s
425
+ end.join(', ')
426
+ inspected += ">"
427
+ inspected
428
+ end
429
+
430
+ def ==(other)
431
+ raise "this object could be comparable only with object of the same class" if other.class != self.class
432
+ same = true
433
+ @@properties[model_name].each do |prop|
434
+ self_var = instance_variable_get(:"@#{prop[:name]}")
435
+ same = false if other.send(prop[:name]).to_s != self_var.to_s
436
+ end
437
+ same = false if self.id != other.id
438
+ same
439
+ end
440
+
356
441
  def persisted?
357
442
  @persisted
358
443
  end
@@ -380,6 +465,14 @@ module RedisOrm
380
465
  prev_prop_value = instance_variable_get(:"@#{prop[:name]}_changes").first
381
466
  prop_value = instance_variable_get(:"@#{prop[:name]}")
382
467
 
468
+ if prop[:options][:sortable]
469
+ $redis.zrem "#{model_name}:#{prop[:name]}_ids", @id
470
+ # remove id from every indexed property
471
+ @@indices[model_name].each do |index|
472
+ $redis.zrem "#{construct_prepared_index(index)}:#{prop[:name]}_ids", @id
473
+ end
474
+ end
475
+
383
476
  indices = @@indices[model_name].inject([]) do |sum, models_index|
384
477
  if models_index[:name].is_a?(Array)
385
478
  if models_index[:name].include?(prop[:name])
@@ -475,6 +568,23 @@ module RedisOrm
475
568
  if prop_changes && prop_changes.size > 2
476
569
  instance_variable_set :"@#{prop[:name]}_changes", [prop_changes.last]
477
570
  end
571
+
572
+ # if some property need to be sortable add id of the record to the appropriate sorted set
573
+ if prop[:options][:sortable]
574
+ property_value = instance_variable_get(:"@#{prop[:name]}")
575
+ score = case prop[:class]
576
+ when "Integer"; property_value.to_f
577
+ when "Float"; property_value.to_f
578
+ when "String"; calculate_key_for_zset(property_value)
579
+ when "RedisOrm::Boolean"; (property_value == true ? 1.0 : 0.0)
580
+ when "Time"; property_value.to_f
581
+ end
582
+ $redis.zadd "#{model_name}:#{prop[:name]}_ids", score, @id
583
+ # add to every indexed property
584
+ @@indices[model_name].each do |index|
585
+ $redis.zadd "#{construct_prepared_index(index)}:#{prop[:name]}_ids", score, @id
586
+ end
587
+ end
478
588
  end
479
589
 
480
590
  # save new indices in order to sort by finders
@@ -531,13 +641,16 @@ module RedisOrm
531
641
  if !@@associations[model_name].empty?
532
642
  @@associations[model_name].each do |assoc|
533
643
  if :belongs_to == assoc[:type]
534
- if !self.send(assoc[:foreign_model]).nil?
644
+ # if assoc has :as option
645
+ foreign_model_name = assoc[:options][:as] ? assoc[:options][:as].to_sym : assoc[:foreign_model].to_sym
646
+
647
+ if !self.send(foreign_model_name).nil?
535
648
  @@indices[model_name].each do |index|
536
649
  keys_to_delete = if index[:name].is_a?(Array)
537
650
  full_index = index[:name].inject([]){|sum, index_part| sum << index_part}.join(':')
538
- $redis.keys "#{assoc[:foreign_model]}:#{self.send(assoc[:foreign_model]).id}:#{model_name.to_s.pluralize}:#{full_index}:*"
651
+ $redis.keys "#{foreign_model_name}:#{self.send(foreign_model_name).id}:#{model_name.to_s.pluralize}:#{full_index}:*"
539
652
  else
540
- ["#{assoc[:foreign_model]}:#{self.send(assoc[:foreign_model]).id}:#{model_name.to_s.pluralize}:#{index[:name]}:#{self.send(index[:name])}"]
653
+ ["#{foreign_model_name}:#{self.send(foreign_model_name).id}:#{model_name.to_s.pluralize}:#{index[:name]}:#{self.send(index[:name])}"]
541
654
  end
542
655
  keys_to_delete.each do |key|
543
656
  index[:options][:unique] ? $redis.del(key) : $redis.zrem(key, @id)
@@ -0,0 +1,12 @@
1
+ module RedisOrm
2
+ module Utils
3
+ def calculate_key_for_zset(string)
4
+ return 0.0 if string.nil?
5
+ sum = ""
6
+ string.codepoints.each do |codepoint|
7
+ sum += ("%05i" % codepoint.to_s) # 5 because 65536 => 2 bytes UTF-8
8
+ end
9
+ "0.#{sum}".to_f
10
+ end
11
+ end
12
+ end
data/redis_orm.gemspec CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{redis_orm}
5
- s.version = "0.5.1"
5
+ s.version = "0.6"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Dmitrii Samoilov"]
9
- s.date = %q{2011-07-27}
9
+ s.date = %q{2011-09-12}
10
10
  s.description = %q{ORM for Redis (advanced key-value storage) with ActiveRecord API}
11
11
  s.email = %q{germaninthetown@gmail.com}
12
- s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb"]
13
- s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb", "redis_orm.gemspec", "test/association_indices_test.rb", "test/associations_test.rb", "test/atomicity_test.rb", "test/basic_functionality_test.rb", "test/callbacks_test.rb", "test/changes_array_test.rb", "test/dynamic_finders_test.rb", "test/exceptions_test.rb", "test/has_one_has_many_test.rb", "test/indices_test.rb", "test/options_test.rb", "test/polymorphic_test.rb", "test/redis.conf", "test/test_helper.rb", "test/uuid_as_id_test.rb", "test/validations_test.rb"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb", "lib/redis_orm/utils.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb", "lib/redis_orm/utils.rb", "redis_orm.gemspec", "test/association_indices_test.rb", "test/associations_test.rb", "test/atomicity_test.rb", "test/basic_functionality_test.rb", "test/callbacks_test.rb", "test/changes_array_test.rb", "test/dynamic_finders_test.rb", "test/exceptions_test.rb", "test/has_one_has_many_test.rb", "test/indices_test.rb", "test/options_test.rb", "test/order_test.rb", "test/polymorphic_test.rb", "test/redis.conf", "test/test_helper.rb", "test/uuid_as_id_test.rb", "test/validations_test.rb"]
14
14
  s.homepage = %q{https://github.com/german/redis_orm}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Redis_orm", "--main", "README.md"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{redis_orm}
18
18
  s.rubygems_version = %q{1.6.2}
19
19
  s.summary = %q{ORM for Redis (advanced key-value storage) with ActiveRecord API}
20
- s.test_files = ["test/options_test.rb", "test/dynamic_finders_test.rb", "test/associations_test.rb", "test/validations_test.rb", "test/test_helper.rb", "test/polymorphic_test.rb", "test/uuid_as_id_test.rb", "test/atomicity_test.rb", "test/exceptions_test.rb", "test/association_indices_test.rb", "test/has_one_has_many_test.rb", "test/indices_test.rb", "test/changes_array_test.rb", "test/callbacks_test.rb", "test/basic_functionality_test.rb"]
20
+ s.test_files = ["test/options_test.rb", "test/dynamic_finders_test.rb", "test/associations_test.rb", "test/validations_test.rb", "test/test_helper.rb", "test/polymorphic_test.rb", "test/uuid_as_id_test.rb", "test/atomicity_test.rb", "test/exceptions_test.rb", "test/association_indices_test.rb", "test/has_one_has_many_test.rb", "test/order_test.rb", "test/indices_test.rb", "test/changes_array_test.rb", "test/callbacks_test.rb", "test/basic_functionality_test.rb"]
21
21
 
22
22
  if s.respond_to? :specification_version then
23
23
  s.specification_version = 3
@@ -10,6 +10,27 @@ class Comment < RedisOrm::Base
10
10
  property :body, String
11
11
 
12
12
  belongs_to :article
13
+ has_many :comments, :as => :replies
14
+ belongs_to :comment, :as => :reply_to
15
+ end
16
+
17
+ module BelongsToModelWithinModule
18
+ class Reply < RedisOrm::Base
19
+ property :body, String, :default => "test"
20
+ belongs_to :article, :as => :essay
21
+ end
22
+ end
23
+
24
+ module HasManyModelWithinModule
25
+ class SpecialComment < RedisOrm::Base
26
+ property :body, String, :default => "test"
27
+ belongs_to :brochure, :as => :book
28
+ end
29
+
30
+ class Brochure < RedisOrm::Base
31
+ property :title, String
32
+ has_many :special_comments
33
+ end
13
34
  end
14
35
 
15
36
  class Profile < RedisOrm::Base
@@ -205,9 +226,9 @@ describe "check associations" do
205
226
  @article.categories << [@cat1, @cat2]
206
227
 
207
228
  @cat1.articles.count.should == 1
208
- @cat1.articles[0].id.should == @article.id
229
+ @cat1.articles[0].should == @article
209
230
  @cat2.articles.count.should == 1
210
- @cat2.articles[0].id.should == @article.id
231
+ @cat2.articles[0].should == @article
211
232
 
212
233
  @article.categories.size.should == 2
213
234
  @article.categories.count.should == 2
@@ -218,10 +239,10 @@ describe "check associations" do
218
239
  @article.categories.map{|c| c.id}.include?(@cat3.id).should be
219
240
 
220
241
  @cat1.articles.count.should == 1
221
- @cat1.articles[0].id.should == @article.id
242
+ @cat1.articles[0].should == @article
222
243
 
223
244
  @cat3.articles.count.should == 1
224
- @cat3.articles[0].id.should == @article.id
245
+ @cat3.articles[0].should == @article
225
246
 
226
247
  @cat2.articles.count.should == 0
227
248
 
@@ -303,4 +324,30 @@ describe "check associations" do
303
324
  rf.replay_to.should be
304
325
  rf.replay_to.id.should == Message.first.id
305
326
  end
327
+
328
+ it "should find associations within modules" do
329
+ BelongsToModelWithinModule::Reply.count.should == 0
330
+ essay = Article.create :title => "Red is cluster"
331
+ BelongsToModelWithinModule::Reply.create :essay => essay
332
+ BelongsToModelWithinModule::Reply.count.should == 1
333
+ reply = BelongsToModelWithinModule::Reply.last
334
+ reply.essay.should == essay
335
+
336
+ HasManyModelWithinModule::SpecialComment.count.should == 0
337
+ book = HasManyModelWithinModule::Brochure.create :title => "Red is unstable"
338
+ HasManyModelWithinModule::SpecialComment.create :book => book
339
+ HasManyModelWithinModule::Brochure.count.should == 1
340
+ HasManyModelWithinModule::SpecialComment.count.should == 1
341
+ end
342
+
343
+ it "should properly handle self-referencing model both belongs_to and has_many/has_one associations" do
344
+ comment1 = Comment.create :body => "comment1"
345
+ comment11 = Comment.create :body => "comment1.1"
346
+ comment12 = Comment.create :body => "comment1.2"
347
+
348
+ comment1.replies = [comment11, comment12]
349
+ comment1.replies.count.should == 2
350
+ comment11.reply_to.should == comment1
351
+ comment12.reply_to.should == comment1
352
+ end
306
353
  end
@@ -1,50 +1,30 @@
1
1
  require File.dirname(File.expand_path(__FILE__)) + '/test_helper.rb'
2
2
 
3
3
  class Article < RedisOrm::Base
4
+ use_uuid_as_id
5
+
4
6
  property :title, String
5
7
  property :karma, Integer
6
8
  end
7
9
 
8
10
  describe "check atomicity" do
9
- =begin
10
11
  it "should properly increment property's value" do
11
- @article = Article.new :title => "Simple test atomicity with multiple threads", :karma => 1
12
- @article.save
12
+ article = Article.new :title => "Simple test atomicity with multiple threads", :karma => 1
13
+ article.save
13
14
 
14
- @threads = []
15
-
16
- 50.times do |i|
17
- @threads << Thread.new(i) do
18
- sleep(0.2)
19
- @article.update_attribute :karma, (@article.karma + 1)
20
- end
21
- end
22
-
23
- @threads.each{|thread| thread.join}
24
-
25
- Article.first.karma.should == 51
26
- end
27
- =end
28
- it "should properly increment property's value" do
29
15
  threads = []
30
16
 
31
17
  50.times do |i|
32
- id = i
33
18
  threads << Thread.new(i) do
34
- if id % 2 == 0
35
- art = Article.create :title => "article ##{id}", :karma => id
36
- puts "article.last.id - #{art.id}, article.last.karma - #{art.karma}"
37
- else
38
- puts "id - #{id}, (id / 2) + 1 - #{(id / 2) + 1}"
39
- Article.find((id / 2) + 1).destroy
40
- end
19
+ article.update_attribute :karma, (article.karma + 1)
41
20
  end
42
21
  end
43
22
 
44
23
  threads.each{|thread| thread.join}
45
- Article.count.should == 0
24
+
25
+ Article.first.karma.should == 51
46
26
  end
47
- =begin
27
+
48
28
  it "should properly increment/decrement property's value" do
49
29
  article = Article.create :title => "article #1", :karma => 10
50
30
  threads = []
@@ -60,5 +40,4 @@ describe "check atomicity" do
60
40
  threads.each{|thread| thread.join}
61
41
  article.karma.should == 15
62
42
  end
63
- =end
64
43
  end
@@ -25,7 +25,23 @@ class TimeStamp < RedisOrm::Base
25
25
  timestamps
26
26
  end
27
27
 
28
+ class Person;end
29
+
28
30
  describe "check basic functionality" do
31
+ it "should have 3 models in descendants" do
32
+ RedisOrm::Base.descendants.should include(User, DefaultUser, TimeStamp)
33
+ RedisOrm::Base.descendants.should_not include(Person)
34
+ end
35
+
36
+ it "should return the same user" do
37
+ user = User.new :name => "german"
38
+ user.save
39
+ User.first.should == user
40
+
41
+ user.name = "Anderson"
42
+ User.first.should_not == user
43
+ end
44
+
29
45
  it "test_simple_creation" do
30
46
  User.count.should == 0
31
47
 
@@ -41,5 +41,10 @@ describe "exceptions test" do
41
41
 
42
42
  # RedisOrm::TypeMismatchError
43
43
  lambda { user.profile = jigsaw }.should raise_error
44
- end
44
+ end
45
+
46
+ it "should raise an exception if there is no such record in the storage" do
47
+ User.find(12).should == nil
48
+ lambda{ User.find! 12 }.should raise_error(RedisOrm::RecordNotFound)
49
+ end
45
50
  end
data/test/options_test.rb CHANGED
@@ -59,6 +59,17 @@ describe "test options" do
59
59
  @photo2.image_type.should == "png"
60
60
  end
61
61
 
62
+ it "should behave like expected for #find and #find! methods (nb exceptions with #find! are tested in exceptions_test.rb file)" do
63
+ Album.find(@album.id).should == @album
64
+ Album.find!(@album.id).should == @album
65
+
66
+ Album.find(:first).should == @album
67
+ Album.find!(:first).should == @album
68
+
69
+ Album.find(:all, :limit => 1).size.should == 1
70
+ Album.find!(:all, :limit => 1).size.should == 1
71
+ end
72
+
62
73
  it "should return correct array when :limit and :offset options are provided" do
63
74
  @album.photos.count.should == 0
64
75
 
@@ -99,6 +110,14 @@ describe "test options" do
99
110
  Photo.find(:last, :conditions => {:image => "boobs.png", :image_type => "png"}).id.should == @photo2.id
100
111
  end
101
112
 
113
+ it "should accept options for #first and #last methods" do
114
+ Photo.first(:conditions => {:image => "facepalm.jpg"}).id.should == @photo1.id
115
+ Photo.first(:conditions => {:image => "boobs.png"}).id.should == @photo2.id
116
+
117
+ Photo.last(:conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).id.should == @photo1.id
118
+ Photo.last(:conditions => {:image => "boobs.png", :image_type => "png"}).id.should == @photo2.id
119
+ end
120
+
102
121
  it "should correctly save boolean values" do
103
122
  $redis.hgetall("photo:#{@photo1.id}")["inverted"].should == "true"
104
123
  $redis.hgetall("photo:#{@photo2.id}")["inverted"].should == "false"
@@ -0,0 +1,69 @@
1
+ require File.dirname(File.expand_path(__FILE__)) + '/test_helper.rb'
2
+
3
+ class User < RedisOrm::Base
4
+ property :name, String, :sortable => true
5
+ property :age, Integer, :sortable => true
6
+ property :wage, Float, :sortable => true
7
+
8
+ property :address, String
9
+
10
+ index :name
11
+ index :age
12
+ end
13
+
14
+ describe "test options" do
15
+ before(:each) do
16
+ @dan = User.create :name => "Daniel", :age => 26, :wage => 40000.0, :address => "Bellevue"
17
+ @abe = User.create :name => "Abe", :age => 30, :wage => 100000.0, :address => "Bellevue"
18
+ @michael = User.create :name => "Michael", :age => 25, :wage => 60000.0, :address => "Bellevue"
19
+ @todd = User.create :name => "Todd", :age => 22, :wage => 30000.0, :address => "Bellevue"
20
+ end
21
+
22
+ it "should return records in specified order" do
23
+ $redis.zcard("user:name_ids").to_i.should == User.count
24
+ $redis.zcard("user:age_ids").to_i.should == User.count
25
+ $redis.zcard("user:wage_ids").to_i.should == User.count
26
+
27
+ User.find(:all, :order => [:name, :asc]).should == [@abe, @dan, @michael, @todd]
28
+ User.find(:all, :order => [:name, :desc]).should == [@todd, @michael, @dan, @abe]
29
+
30
+ User.find(:all, :order => [:age, :asc]).should == [@todd, @michael, @dan, @abe]
31
+ User.find(:all, :order => [:age, :desc]).should == [@abe, @dan, @michael, @todd]
32
+
33
+ User.find(:all, :order => [:wage, :asc]).should == [@todd, @dan, @michael, @abe]
34
+ User.find(:all, :order => [:wage, :desc]).should == [@abe, @michael, @dan, @todd]
35
+ end
36
+
37
+ it "should return records which met specified conditions in specified order" do
38
+ @abe2 = User.create :name => "Abe", :age => 12, :wage => 10.0, :address => "Santa Fe"
39
+
40
+ # :asc should be default value for property in :order clause
41
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage]).should == [@abe2, @abe]
42
+
43
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :desc]).should == [@abe, @abe2]
44
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :asc]).should == [@abe2, @abe]
45
+
46
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:age, :desc]).should == [@abe, @abe2]
47
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:age, :asc]).should == [@abe2, @abe]
48
+
49
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :desc]).should == [@abe, @abe2]
50
+ User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :asc]).should == [@abe2, @abe]
51
+ end
52
+
53
+ it "should update keys after the persisted object was edited and sort properly" do
54
+ @abe.update_attributes :name => "Zed", :age => 12, :wage => 10.0, :address => "Santa Fe"
55
+
56
+ $redis.zcard("user:name_ids").to_i.should == User.count
57
+ $redis.zcard("user:age_ids").to_i.should == User.count
58
+ $redis.zcard("user:wage_ids").to_i.should == User.count
59
+
60
+ User.find(:all, :order => [:name, :asc]).should == [@dan, @michael, @todd, @abe]
61
+ User.find(:all, :order => [:name, :desc]).should == [@abe, @todd, @michael, @dan]
62
+
63
+ User.find(:all, :order => [:age, :asc]).should == [@abe, @todd, @michael, @dan]
64
+ User.find(:all, :order => [:age, :desc]).should == [@dan, @michael, @todd, @abe]
65
+
66
+ User.find(:all, :order => [:wage, :asc]).should == [@abe, @todd, @dan, @michael]
67
+ User.find(:all, :order => [:wage, :desc]).should == [@michael, @dan, @todd, @abe]
68
+ end
69
+ end
data/test/test_helper.rb CHANGED
@@ -8,7 +8,12 @@ RSpec.configure do |config|
8
8
  $redis_pid = spawn 'redis-server ' + path_to_conf, :out => "/dev/null"
9
9
  sleep(0.3) # must be some delay otherwise "Connection refused - Unable to connect to Redis"
10
10
  path_to_socket = File.dirname(File.expand_path(__FILE__)) + "/../redis.sock"
11
- $redis = Redis.new(:host => 'localhost', :path => path_to_socket)
11
+ begin
12
+ $redis = Redis.new(:host => 'localhost', :path => path_to_socket)
13
+ rescue => e
14
+ puts 'Unable to create connection to the redis server: ' + e.message.inspect
15
+ Process.kill 9, $redis_pid.to_i if $redis_pid
16
+ end
12
17
  end
13
18
 
14
19
  config.after(:all) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_orm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-27 00:00:00.000000000 +03:00
12
+ date: 2011-09-12 00:00:00.000000000 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
- requirement: &87829630 !ruby/object:Gem::Requirement
17
+ requirement: &74101100 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 3.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *87829630
25
+ version_requirements: *74101100
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
28
- requirement: &87829290 !ruby/object:Gem::Requirement
28
+ requirement: &74100700 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 3.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *87829290
36
+ version_requirements: *74100700
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: redis
39
- requirement: &87828950 !ruby/object:Gem::Requirement
39
+ requirement: &74100190 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 2.2.0
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *87828950
47
+ version_requirements: *74100190
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: uuid
50
- requirement: &87828600 !ruby/object:Gem::Requirement
50
+ requirement: &74099680 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 2.3.2
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *87828600
58
+ version_requirements: *74099680
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: rspec
61
- requirement: &87828250 !ruby/object:Gem::Requirement
61
+ requirement: &74099250 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: 2.5.0
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *87828250
69
+ version_requirements: *74099250
70
70
  description: ORM for Redis (advanced key-value storage) with ActiveRecord API
71
71
  email: germaninthetown@gmail.com
72
72
  executables: []
@@ -83,6 +83,7 @@ extra_rdoc_files:
83
83
  - lib/redis_orm/associations/has_many_proxy.rb
84
84
  - lib/redis_orm/associations/has_one.rb
85
85
  - lib/redis_orm/redis_orm.rb
86
+ - lib/redis_orm/utils.rb
86
87
  files:
87
88
  - CHANGELOG
88
89
  - LICENSE
@@ -97,6 +98,7 @@ files:
97
98
  - lib/redis_orm/associations/has_many_proxy.rb
98
99
  - lib/redis_orm/associations/has_one.rb
99
100
  - lib/redis_orm/redis_orm.rb
101
+ - lib/redis_orm/utils.rb
100
102
  - redis_orm.gemspec
101
103
  - test/association_indices_test.rb
102
104
  - test/associations_test.rb
@@ -109,6 +111,7 @@ files:
109
111
  - test/has_one_has_many_test.rb
110
112
  - test/indices_test.rb
111
113
  - test/options_test.rb
114
+ - test/order_test.rb
112
115
  - test/polymorphic_test.rb
113
116
  - test/redis.conf
114
117
  - test/test_helper.rb
@@ -157,6 +160,7 @@ test_files:
157
160
  - test/exceptions_test.rb
158
161
  - test/association_indices_test.rb
159
162
  - test/has_one_has_many_test.rb
163
+ - test/order_test.rb
160
164
  - test/indices_test.rb
161
165
  - test/changes_array_test.rb
162
166
  - test/callbacks_test.rb