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 +9 -0
- data/Manifest +2 -0
- data/README.md +21 -1
- data/Rakefile +6 -1
- data/lib/redis_orm.rb +2 -0
- data/lib/redis_orm/active_model_behavior.rb +0 -2
- data/lib/redis_orm/associations/belongs_to.rb +13 -9
- data/lib/redis_orm/associations/has_many.rb +15 -16
- data/lib/redis_orm/associations/has_many_proxy.rb +1 -1
- data/lib/redis_orm/redis_orm.rb +146 -33
- data/lib/redis_orm/utils.rb +12 -0
- data/redis_orm.gemspec +5 -5
- data/test/associations_test.rb +51 -4
- data/test/atomicity_test.rb +8 -29
- data/test/basic_functionality_test.rb +16 -0
- data/test/exceptions_test.rb +6 -1
- data/test/options_test.rb +19 -0
- data/test/order_test.rb +69 -0
- data/test/test_helper.rb +6 -1
- metadata +16 -12
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
|
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.
|
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 =
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
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 =
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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.
|
85
|
+
index = @foreign_models.to_s.singularize.camelize.constantize.find_indices(properties, :first => true)
|
86
86
|
|
87
87
|
raise NotIndexFound if !index
|
88
88
|
|
data/lib/redis_orm/redis_orm.rb
CHANGED
@@ -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
|
-
|
131
|
-
|
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
|
-
|
136
|
-
|
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
|
156
|
+
|
157
|
+
def find_indices(properties, options = {})
|
140
158
|
properties.map!{|p| p.to_sym}
|
141
|
-
|
142
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
193
|
-
|
194
|
-
end
|
195
|
-
|
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
|
198
|
-
$redis.zrevrangebyscore(
|
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(
|
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
|
-
|
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
|
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 "#{
|
651
|
+
$redis.keys "#{foreign_model_name}:#{self.send(foreign_model_name).id}:#{model_name.to_s.pluralize}:#{full_index}:*"
|
539
652
|
else
|
540
|
-
["#{
|
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
|
+
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-
|
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
|
data/test/associations_test.rb
CHANGED
@@ -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].
|
229
|
+
@cat1.articles[0].should == @article
|
209
230
|
@cat2.articles.count.should == 1
|
210
|
-
@cat2.articles[0].
|
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].
|
242
|
+
@cat1.articles[0].should == @article
|
222
243
|
|
223
244
|
@cat3.articles.count.should == 1
|
224
|
-
@cat3.articles[0].
|
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
|
data/test/atomicity_test.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
24
|
+
|
25
|
+
Article.first.karma.should == 51
|
46
26
|
end
|
47
|
-
|
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
|
|
data/test/exceptions_test.rb
CHANGED
@@ -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"
|
data/test/order_test.rb
ADDED
@@ -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
|
-
|
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.
|
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-
|
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: &
|
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: *
|
25
|
+
version_requirements: *74101100
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: activemodel
|
28
|
-
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: *
|
36
|
+
version_requirements: *74100700
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: redis
|
39
|
-
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: *
|
47
|
+
version_requirements: *74100190
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: uuid
|
50
|
-
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: *
|
58
|
+
version_requirements: *74099680
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: rspec
|
61
|
-
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: *
|
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
|