redis_orm 0.6 → 0.6.1
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 +4 -0
- data/Gemfile +8 -0
- data/Manifest +3 -1
- data/README.md +15 -3
- data/Rakefile +1 -6
- data/benchmarks/sortable_benchmark.rb +45 -0
- data/lib/redis_orm/redis_orm.rb +130 -24
- data/redis_orm.gemspec +9 -9
- data/test/exceptions_test.rb +5 -0
- data/test/options_test.rb +16 -15
- data/test/{order_test.rb → sortable_test.rb} +65 -4
- metadata +26 -26
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
v0.6.1 [05-12-2011]
|
2
|
+
* rewritten sortable functionality for attributes which values are strings
|
3
|
+
* added Gemfile to the project, improved tests
|
4
|
+
|
1
5
|
v0.6 [12-09-2011]
|
2
6
|
* added equality operator for object, #to_s method for inspecting objects, #find! which could throw RecordNotFound error
|
3
7
|
* added self.descendants class method which returns all inherited from RedisOrm::Base classes
|
data/Gemfile
ADDED
data/Manifest
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
CHANGELOG
|
2
|
+
Gemfile
|
2
3
|
LICENSE
|
3
4
|
Manifest
|
4
5
|
README.md
|
5
6
|
Rakefile
|
7
|
+
benchmarks/sortable_benchmark.rb
|
6
8
|
lib/redis_orm.rb
|
7
9
|
lib/redis_orm/active_model_behavior.rb
|
8
10
|
lib/redis_orm/associations/belongs_to.rb
|
@@ -24,9 +26,9 @@ test/exceptions_test.rb
|
|
24
26
|
test/has_one_has_many_test.rb
|
25
27
|
test/indices_test.rb
|
26
28
|
test/options_test.rb
|
27
|
-
test/order_test.rb
|
28
29
|
test/polymorphic_test.rb
|
29
30
|
test/redis.conf
|
31
|
+
test/sortable_test.rb
|
30
32
|
test/test_helper.rb
|
31
33
|
test/uuid_as_id_test.rb
|
32
34
|
test/validations_test.rb
|
data/README.md
CHANGED
@@ -29,15 +29,25 @@ end
|
|
29
29
|
|
30
30
|
## Installing redis_orm
|
31
31
|
|
32
|
+
stable release:
|
33
|
+
|
34
|
+
```sh
|
32
35
|
gem install redis_orm
|
36
|
+
```
|
33
37
|
|
34
|
-
or
|
38
|
+
or edge version:
|
35
39
|
|
40
|
+
```sh
|
36
41
|
git clone git://github.com/german/redis_orm.git
|
37
|
-
|
38
42
|
cd redis_orm
|
39
|
-
|
40
43
|
bundle install
|
44
|
+
```
|
45
|
+
|
46
|
+
To run the tests you should have redis installed already. Please check [Redis download/installation page](http://redis.io/download).
|
47
|
+
|
48
|
+
```sh
|
49
|
+
rake test
|
50
|
+
```
|
41
51
|
|
42
52
|
## Setting up a connection to the redis server
|
43
53
|
|
@@ -84,6 +94,8 @@ Following options are available in property declaration:
|
|
84
94
|
|
85
95
|
if *true* is specified then you could sort records by this property later
|
86
96
|
|
97
|
+
*Note* that when you're using :sortable option redis_orm maintains one additional list per attribute. Also note that the #create method could be 3 times slower in some cases (this will be improved in future releases), while the #find performance is basically the same (see the "benchmarks/sortable_benchmark.rb").
|
98
|
+
|
87
99
|
## Searching records by the value
|
88
100
|
|
89
101
|
Usually it's done via declaring an index and using *:conditions* hash or dynamic finders. For example:
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake'
|
|
4
4
|
#=begin
|
5
5
|
require 'echoe'
|
6
6
|
|
7
|
-
Echoe.new('redis_orm', '0.6') do |p|
|
7
|
+
Echoe.new('redis_orm', '0.6.1') 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,13 +26,8 @@ Rake::TestTask.new(:test) do |t|
|
|
26
26
|
end
|
27
27
|
=end
|
28
28
|
|
29
|
-
#require 'rspec/core/rake_task'
|
30
29
|
task :test do |t|
|
31
30
|
Dir['test/**/*_test.rb'].each do |file|
|
32
31
|
puts `ruby -I./lib #{file}`
|
33
32
|
end
|
34
33
|
end
|
35
|
-
#task :default => :test
|
36
|
-
#RSpec::Core::RakeTask.new(:spec) do |t|
|
37
|
-
# t.pattern = 'test/**/*_test.rb'
|
38
|
-
#end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/redis_orm')
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
class User < RedisOrm::Base
|
5
|
+
property :name, String
|
6
|
+
property :age, Integer
|
7
|
+
property :wage, Float
|
8
|
+
|
9
|
+
index :name
|
10
|
+
index :age
|
11
|
+
end
|
12
|
+
|
13
|
+
class SortableUser < RedisOrm::Base
|
14
|
+
property :name, String, :sortable => true
|
15
|
+
property :age, Integer, :sortable => true
|
16
|
+
property :wage, Float, :sortable => true
|
17
|
+
|
18
|
+
index :name
|
19
|
+
index :age
|
20
|
+
end
|
21
|
+
|
22
|
+
path_to_conf = File.dirname(File.expand_path(__FILE__)) + "/../test/redis.conf"
|
23
|
+
$redis_pid = spawn 'redis-server ' + path_to_conf, :out => "/dev/null"
|
24
|
+
sleep(0.3) # must be some delay otherwise "Connection refused - Unable to connect to Redis"
|
25
|
+
path_to_socket = File.dirname(File.expand_path(__FILE__)) + "/../redis.sock"
|
26
|
+
begin
|
27
|
+
$redis = Redis.new(:host => 'localhost', :path => path_to_socket)
|
28
|
+
rescue => e
|
29
|
+
puts 'Unable to create connection to the redis server: ' + e.message.inspect
|
30
|
+
Process.kill 9, $redis_pid.to_i if $redis_pid
|
31
|
+
end
|
32
|
+
|
33
|
+
n = 100
|
34
|
+
Benchmark.bmbm do |x|
|
35
|
+
x.report("creating regular user:") { for i in 1..n; u = User.create(:name => "user#{i}", :age => i, :wage => 100*i); end}
|
36
|
+
x.report("creating user w/ sortable attrs:") { for i in 1..n; u = SortableUser.create(:name => "user#{i}", :age => i, :wage => 100*i); end }
|
37
|
+
end
|
38
|
+
|
39
|
+
Benchmark.bmbm do |x|
|
40
|
+
x.report("finding regular users:") { User.find(:all, :limit => 5, :offset => 10) }
|
41
|
+
x.report("finding users w/ sortable attrs:") { SortableUser.find(:all, :limit => 5, :offset => 10, :order => [:name, :asc]) }
|
42
|
+
end
|
43
|
+
|
44
|
+
$redis.flushall if $redis
|
45
|
+
Process.kill 9, $redis_pid.to_i if $redis_pid
|
data/lib/redis_orm/redis_orm.rb
CHANGED
@@ -193,6 +193,8 @@ module RedisOrm
|
|
193
193
|
[options[:offset].to_i, options[:limit].to_i]
|
194
194
|
elsif options[:limit]
|
195
195
|
[0, options[:limit].to_i]
|
196
|
+
else
|
197
|
+
[0, -1]
|
196
198
|
end
|
197
199
|
|
198
200
|
order_max_limit = Time.now.to_f
|
@@ -214,30 +216,66 @@ module RedisOrm
|
|
214
216
|
end
|
215
217
|
end
|
216
218
|
|
219
|
+
order_by_property_is_string = false
|
220
|
+
|
217
221
|
# if not array => created_at native order (in which ids were pushed to "#{model_name}:ids" set by default)
|
218
222
|
direction = if !options[:order].blank?
|
219
|
-
|
223
|
+
property = {}
|
224
|
+
dir = if options[:order].is_a?(Array)
|
225
|
+
property = @@properties[model_name].detect{|prop| prop[:name].to_s == options[:order].first.to_s}
|
220
226
|
# for String values max limit for search key could be 1.0, but for Numeric values there's actually no limit
|
221
227
|
order_max_limit = 100_000_000_000
|
222
228
|
ids_key = "#{prepared_index}:#{options[:order].first}_ids"
|
223
229
|
options[:order].size == 2 ? options[:order].last : 'asc'
|
224
230
|
else
|
231
|
+
property = @@properties[model_name].detect{|prop| prop[:name].to_s == options[:order].to_s}
|
225
232
|
ids_key = prepared_index
|
226
233
|
options[:order]
|
227
234
|
end
|
235
|
+
if property && property[:class].eql?("String") && property[:options][:sortable]
|
236
|
+
order_by_property_is_string = true
|
237
|
+
end
|
238
|
+
dir
|
228
239
|
else
|
229
240
|
ids_key = prepared_index
|
230
241
|
'asc'
|
231
242
|
end
|
232
243
|
|
233
|
-
if
|
234
|
-
id = $redis.get prepared_index
|
235
|
-
model_name.to_s.camelize.constantize.find(id)
|
236
|
-
else
|
244
|
+
if order_by_property_is_string
|
237
245
|
if direction.to_s == 'desc'
|
238
|
-
$redis.
|
246
|
+
ids_length = $redis.llen(ids_key)
|
247
|
+
limit = if options[:offset] && options[:limit]
|
248
|
+
[(ids_length - options[:offset].to_i - options[:limit].to_i), (ids_length - options[:offset].to_i - 1)]
|
249
|
+
elsif options[:limit]
|
250
|
+
[ids_length - options[:limit].to_i, ids_length]
|
251
|
+
elsif options[:offset]
|
252
|
+
[0, (ids_length - options[:offset].to_i - 1)]
|
253
|
+
else
|
254
|
+
[0, -1]
|
255
|
+
end
|
256
|
+
$redis.lrange(ids_key, *limit).reverse.compact.collect{|id| find(id.split(':').last)}
|
257
|
+
else
|
258
|
+
limit = if options[:offset] && options[:limit]
|
259
|
+
[options[:offset].to_i, (options[:offset].to_i + options[:limit].to_i)]
|
260
|
+
elsif options[:limit]
|
261
|
+
[0, options[:limit].to_i - 1]
|
262
|
+
elsif options[:offset]
|
263
|
+
[options[:offset].to_i, -1]
|
264
|
+
else
|
265
|
+
[0, -1]
|
266
|
+
end
|
267
|
+
$redis.lrange(ids_key, *limit).compact.collect{|id| find(id.split(':').last)}
|
268
|
+
end
|
269
|
+
else
|
270
|
+
if index && index[:options][:unique]
|
271
|
+
id = $redis.get prepared_index
|
272
|
+
model_name.to_s.camelize.constantize.find(id)
|
239
273
|
else
|
240
|
-
|
274
|
+
if direction.to_s == 'desc'
|
275
|
+
$redis.zrevrangebyscore(ids_key, order_max_limit, 0, :limit => limit).compact.collect{|id| find(id)}
|
276
|
+
else
|
277
|
+
$redis.zrangebyscore(ids_key, 0, order_max_limit, :limit => limit).compact.collect{|id| find(id)}
|
278
|
+
end
|
241
279
|
end
|
242
280
|
end
|
243
281
|
end
|
@@ -464,12 +502,20 @@ module RedisOrm
|
|
464
502
|
|
465
503
|
prev_prop_value = instance_variable_get(:"@#{prop[:name]}_changes").first
|
466
504
|
prop_value = instance_variable_get(:"@#{prop[:name]}")
|
467
|
-
|
505
|
+
# TODO DRY in destroy also
|
468
506
|
if prop[:options][:sortable]
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
507
|
+
if prop[:class].eql?("String")
|
508
|
+
$redis.lrem "#{model_name}:#{prop[:name]}_ids", 1, "#{prev_prop_value}:#{@id}"
|
509
|
+
# remove id from every indexed property
|
510
|
+
@@indices[model_name].each do |index|
|
511
|
+
$redis.lrem "#{construct_prepared_index(index)}:#{prop[:name]}_ids", 1, "#{prop_value}:#{@id}"
|
512
|
+
end
|
513
|
+
else
|
514
|
+
$redis.zrem "#{model_name}:#{prop[:name]}_ids", @id
|
515
|
+
# remove id from every indexed property
|
516
|
+
@@indices[model_name].each do |index|
|
517
|
+
$redis.zrem "#{construct_prepared_index(index)}:#{prop[:name]}_ids", @id
|
518
|
+
end
|
473
519
|
end
|
474
520
|
end
|
475
521
|
|
@@ -571,18 +617,28 @@ module RedisOrm
|
|
571
617
|
|
572
618
|
# if some property need to be sortable add id of the record to the appropriate sorted set
|
573
619
|
if prop[:options][:sortable]
|
574
|
-
property_value = instance_variable_get(:"@#{prop[:name]}")
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
620
|
+
property_value = instance_variable_get(:"@#{prop[:name]}").to_s
|
621
|
+
if prop[:class].eql?("String")
|
622
|
+
sortable_key = "#{model_name}:#{prop[:name]}_ids"
|
623
|
+
el_or_position_to_insert = find_position_to_insert(sortable_key, property_value)
|
624
|
+
el_or_position_to_insert == 0 ? $redis.lpush(sortable_key, "#{property_value}:#{@id}") : $redis.linsert(sortable_key, "AFTER", el_or_position_to_insert, "#{property_value}:#{@id}")
|
625
|
+
# add to every indexed property
|
626
|
+
@@indices[model_name].each do |index|
|
627
|
+
sortable_key = "#{construct_prepared_index(index)}:#{prop[:name]}_ids"
|
628
|
+
el_or_position_to_insert == 0 ? $redis.lpush(sortable_key, "#{property_value}:#{@id}") : $redis.linsert(sortable_key, "AFTER", el_or_position_to_insert, "#{property_value}:#{@id}")
|
629
|
+
end
|
630
|
+
else
|
631
|
+
score = case prop[:class]
|
632
|
+
when "Integer"; property_value.to_f
|
633
|
+
when "Float"; property_value.to_f
|
634
|
+
when "RedisOrm::Boolean"; (property_value == true ? 1.0 : 0.0)
|
635
|
+
when "Time"; property_value.to_f
|
636
|
+
end
|
637
|
+
$redis.zadd "#{model_name}:#{prop[:name]}_ids", score, @id
|
638
|
+
# add to every indexed property
|
639
|
+
@@indices[model_name].each do |index|
|
640
|
+
$redis.zadd "#{construct_prepared_index(index)}:#{prop[:name]}_ids", score, @id
|
641
|
+
end
|
586
642
|
end
|
587
643
|
end
|
588
644
|
end
|
@@ -612,6 +668,47 @@ module RedisOrm
|
|
612
668
|
true # if there were no errors just return true, so *if* conditions would work
|
613
669
|
end
|
614
670
|
|
671
|
+
def find_position_to_insert(sortable_key, value)
|
672
|
+
end_index = $redis.llen(sortable_key)
|
673
|
+
|
674
|
+
return 0 if end_index == 0
|
675
|
+
|
676
|
+
start_index = 0
|
677
|
+
pivot_index = end_index / 2
|
678
|
+
|
679
|
+
start_el = $redis.lindex(sortable_key, start_index)
|
680
|
+
end_el = $redis.lindex(sortable_key, end_index - 1)
|
681
|
+
pivot_el = $redis.lindex(sortable_key, pivot_index)
|
682
|
+
|
683
|
+
while start_index != end_index
|
684
|
+
# aa..ab..ac..bd <- ad
|
685
|
+
if start_el.split(':').first > value # Michael > Abe
|
686
|
+
return 0
|
687
|
+
elsif end_el.split(':').first < value # Abe < Todd
|
688
|
+
return end_el
|
689
|
+
elsif start_el.split(':').first == value # Abe == Abe
|
690
|
+
return start_el
|
691
|
+
elsif pivot_el.split(':').first == value # Todd == Todd
|
692
|
+
return pivot_el
|
693
|
+
elsif end_el.split(':').first == value
|
694
|
+
return end_el
|
695
|
+
elsif (start_el.split(':').first < value) && (pivot_el.split(':').first > value)
|
696
|
+
start_index = start_index
|
697
|
+
prev_pivot_index = pivot_index
|
698
|
+
pivot_index = start_index + ((end_index - pivot_index) / 2)
|
699
|
+
end_index = prev_pivot_index
|
700
|
+
elsif (pivot_el.split(':').first < value) && (end_el.split(':').first > value) # M < V && Y > V
|
701
|
+
start_index = pivot_index
|
702
|
+
pivot_index = pivot_index + ((end_index - pivot_index) / 2)
|
703
|
+
end_index = end_index
|
704
|
+
end
|
705
|
+
start_el = $redis.lindex(sortable_key, start_index)
|
706
|
+
end_el = $redis.lindex(sortable_key, end_index - 1)
|
707
|
+
pivot_el = $redis.lindex(sortable_key, pivot_index)
|
708
|
+
end
|
709
|
+
start_el
|
710
|
+
end
|
711
|
+
|
615
712
|
def update_attributes(attributes)
|
616
713
|
if attributes.is_a?(Hash)
|
617
714
|
attributes.each do |key, value|
|
@@ -632,7 +729,16 @@ module RedisOrm
|
|
632
729
|
end
|
633
730
|
|
634
731
|
@@properties[model_name].each do |prop|
|
732
|
+
property_value = instance_variable_get(:"@#{prop[:name]}").to_s
|
635
733
|
$redis.hdel("#{model_name}:#{@id}", prop[:name].to_s)
|
734
|
+
|
735
|
+
if prop[:options][:sortable]
|
736
|
+
if prop[:class].eql?("String")
|
737
|
+
$redis.lrem "#{model_name}:#{prop[:name]}_ids", 1, "#{property_value}:#{@id}"
|
738
|
+
else
|
739
|
+
$redis.zrem "#{model_name}:#{prop[:name]}_ids", @id
|
740
|
+
end
|
741
|
+
end
|
636
742
|
end
|
637
743
|
|
638
744
|
$redis.zrem "#{model_name}:ids", @id
|
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.6"
|
5
|
+
s.version = "0.6.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = [
|
9
|
-
s.date = %q{2011-
|
8
|
+
s.authors = [%q{Dmitrii Samoilov}]
|
9
|
+
s.date = %q{2011-12-05}
|
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 = [
|
13
|
-
s.files = [
|
12
|
+
s.extra_rdoc_files = [%q{CHANGELOG}, %q{LICENSE}, %q{README.md}, %q{lib/redis_orm.rb}, %q{lib/redis_orm/active_model_behavior.rb}, %q{lib/redis_orm/associations/belongs_to.rb}, %q{lib/redis_orm/associations/has_many.rb}, %q{lib/redis_orm/associations/has_many_helper.rb}, %q{lib/redis_orm/associations/has_many_proxy.rb}, %q{lib/redis_orm/associations/has_one.rb}, %q{lib/redis_orm/redis_orm.rb}, %q{lib/redis_orm/utils.rb}]
|
13
|
+
s.files = [%q{CHANGELOG}, %q{Gemfile}, %q{LICENSE}, %q{Manifest}, %q{README.md}, %q{Rakefile}, %q{benchmarks/sortable_benchmark.rb}, %q{lib/redis_orm.rb}, %q{lib/redis_orm/active_model_behavior.rb}, %q{lib/redis_orm/associations/belongs_to.rb}, %q{lib/redis_orm/associations/has_many.rb}, %q{lib/redis_orm/associations/has_many_helper.rb}, %q{lib/redis_orm/associations/has_many_proxy.rb}, %q{lib/redis_orm/associations/has_one.rb}, %q{lib/redis_orm/redis_orm.rb}, %q{lib/redis_orm/utils.rb}, %q{redis_orm.gemspec}, %q{test/association_indices_test.rb}, %q{test/associations_test.rb}, %q{test/atomicity_test.rb}, %q{test/basic_functionality_test.rb}, %q{test/callbacks_test.rb}, %q{test/changes_array_test.rb}, %q{test/dynamic_finders_test.rb}, %q{test/exceptions_test.rb}, %q{test/has_one_has_many_test.rb}, %q{test/indices_test.rb}, %q{test/options_test.rb}, %q{test/polymorphic_test.rb}, %q{test/redis.conf}, %q{test/sortable_test.rb}, %q{test/test_helper.rb}, %q{test/uuid_as_id_test.rb}, %q{test/validations_test.rb}]
|
14
14
|
s.homepage = %q{https://github.com/german/redis_orm}
|
15
|
-
s.rdoc_options = [
|
16
|
-
s.require_paths = [
|
15
|
+
s.rdoc_options = [%q{--line-numbers}, %q{--inline-source}, %q{--title}, %q{Redis_orm}, %q{--main}, %q{README.md}]
|
16
|
+
s.require_paths = [%q{lib}]
|
17
17
|
s.rubyforge_project = %q{redis_orm}
|
18
|
-
s.rubygems_version = %q{1.6
|
18
|
+
s.rubygems_version = %q{1.8.6}
|
19
19
|
s.summary = %q{ORM for Redis (advanced key-value storage) with ActiveRecord API}
|
20
|
-
s.test_files = [
|
20
|
+
s.test_files = [%q{test/atomicity_test.rb}, %q{test/indices_test.rb}, %q{test/sortable_test.rb}, %q{test/uuid_as_id_test.rb}, %q{test/test_helper.rb}, %q{test/options_test.rb}, %q{test/callbacks_test.rb}, %q{test/exceptions_test.rb}, %q{test/associations_test.rb}, %q{test/validations_test.rb}, %q{test/basic_functionality_test.rb}, %q{test/dynamic_finders_test.rb}, %q{test/changes_array_test.rb}, %q{test/polymorphic_test.rb}, %q{test/association_indices_test.rb}, %q{test/has_one_has_many_test.rb}]
|
21
21
|
|
22
22
|
if s.respond_to? :specification_version then
|
23
23
|
s.specification_version = 3
|
data/test/exceptions_test.rb
CHANGED
@@ -47,4 +47,9 @@ describe "exceptions test" do
|
|
47
47
|
User.find(12).should == nil
|
48
48
|
lambda{ User.find! 12 }.should raise_error(RedisOrm::RecordNotFound)
|
49
49
|
end
|
50
|
+
|
51
|
+
it "should throw an exception if there was an error while creating object with #create! method" do
|
52
|
+
jigsaw = Jigsaw.create :title => "jigsaw"
|
53
|
+
lambda { User.create!(:name => "John", :age => 44, :profile => jigsaw) }.should raise_error(RedisOrm::TypeMismatchError)
|
54
|
+
end
|
50
55
|
end
|
data/test/options_test.rb
CHANGED
@@ -69,7 +69,7 @@ describe "test options" do
|
|
69
69
|
Album.find(:all, :limit => 1).size.should == 1
|
70
70
|
Album.find!(:all, :limit => 1).size.should == 1
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
it "should return correct array when :limit and :offset options are provided" do
|
74
74
|
@album.photos.count.should == 0
|
75
75
|
|
@@ -88,8 +88,9 @@ describe "test options" do
|
|
88
88
|
@album.photos.find(:all, :limit => 1, :offset => 1).size.should == 1
|
89
89
|
|
90
90
|
Photo.find(:all).size.should == 2
|
91
|
-
|
92
|
-
Photo.find(:
|
91
|
+
|
92
|
+
Photo.find(:first).should == @photo1
|
93
|
+
Photo.find(:last).should == @photo2
|
93
94
|
|
94
95
|
Photo.find(:all, :conditions => {:image => "facepalm.jpg"}).size.should == 1
|
95
96
|
Photo.find(:all, :conditions => {:image => "boobs.png"}).size.should == 1
|
@@ -97,25 +98,25 @@ describe "test options" do
|
|
97
98
|
Photo.find(:all, :conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).size.should == 1
|
98
99
|
Photo.find(:all, :conditions => {:image => "boobs.png", :image_type => "png"}).size.should == 1
|
99
100
|
|
100
|
-
Photo.find(:first, :conditions => {:image => "facepalm.jpg"}).
|
101
|
-
Photo.find(:first, :conditions => {:image => "boobs.png"}).
|
101
|
+
Photo.find(:first, :conditions => {:image => "facepalm.jpg"}).should == @photo1
|
102
|
+
Photo.find(:first, :conditions => {:image => "boobs.png"}).should == @photo2
|
102
103
|
|
103
|
-
Photo.find(:first, :conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).
|
104
|
-
Photo.find(:first, :conditions => {:image => "boobs.png", :image_type => "png"}).
|
104
|
+
Photo.find(:first, :conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).should == @photo1
|
105
|
+
Photo.find(:first, :conditions => {:image => "boobs.png", :image_type => "png"}).should == @photo2
|
105
106
|
|
106
|
-
Photo.find(:last, :conditions => {:image => "facepalm.jpg"}).
|
107
|
-
Photo.find(:last, :conditions => {:image => "boobs.png"}).
|
107
|
+
Photo.find(:last, :conditions => {:image => "facepalm.jpg"}).should == @photo1
|
108
|
+
Photo.find(:last, :conditions => {:image => "boobs.png"}).should == @photo2
|
108
109
|
|
109
|
-
Photo.find(:last, :conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).
|
110
|
-
Photo.find(:last, :conditions => {:image => "boobs.png", :image_type => "png"}).
|
110
|
+
Photo.find(:last, :conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).should == @photo1
|
111
|
+
Photo.find(:last, :conditions => {:image => "boobs.png", :image_type => "png"}).should == @photo2
|
111
112
|
end
|
112
113
|
|
113
114
|
it "should accept options for #first and #last methods" do
|
114
|
-
Photo.first(:conditions => {:image => "facepalm.jpg"}).
|
115
|
-
Photo.first(:conditions => {:image => "boobs.png"}).
|
115
|
+
Photo.first(:conditions => {:image => "facepalm.jpg"}).should == @photo1
|
116
|
+
Photo.first(:conditions => {:image => "boobs.png"}).should == @photo2
|
116
117
|
|
117
|
-
Photo.last(:conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).
|
118
|
-
Photo.last(:conditions => {:image => "boobs.png", :image_type => "png"}).
|
118
|
+
Photo.last(:conditions => {:image => "facepalm.jpg", :image_type => "jpg"}).should == @photo1
|
119
|
+
Photo.last(:conditions => {:image => "boobs.png", :image_type => "png"}).should == @photo2
|
119
120
|
end
|
120
121
|
|
121
122
|
it "should correctly save boolean values" do
|
@@ -11,6 +11,11 @@ class User < RedisOrm::Base
|
|
11
11
|
index :age
|
12
12
|
end
|
13
13
|
|
14
|
+
class SortableUser < RedisOrm::Base
|
15
|
+
property :name, String, :sortable => true
|
16
|
+
index :name
|
17
|
+
end
|
18
|
+
|
14
19
|
describe "test options" do
|
15
20
|
before(:each) do
|
16
21
|
@dan = User.create :name => "Daniel", :age => 26, :wage => 40000.0, :address => "Bellevue"
|
@@ -18,9 +23,9 @@ describe "test options" do
|
|
18
23
|
@michael = User.create :name => "Michael", :age => 25, :wage => 60000.0, :address => "Bellevue"
|
19
24
|
@todd = User.create :name => "Todd", :age => 22, :wage => 30000.0, :address => "Bellevue"
|
20
25
|
end
|
21
|
-
|
26
|
+
|
22
27
|
it "should return records in specified order" do
|
23
|
-
$redis.
|
28
|
+
$redis.llen("user:name_ids").to_i.should == User.count
|
24
29
|
$redis.zcard("user:age_ids").to_i.should == User.count
|
25
30
|
$redis.zcard("user:wage_ids").to_i.should == User.count
|
26
31
|
|
@@ -49,11 +54,11 @@ describe "test options" do
|
|
49
54
|
User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :desc]).should == [@abe, @abe2]
|
50
55
|
User.find(:all, :conditions => {:name => "Abe"}, :order => [:wage, :asc]).should == [@abe2, @abe]
|
51
56
|
end
|
52
|
-
|
57
|
+
|
53
58
|
it "should update keys after the persisted object was edited and sort properly" do
|
54
59
|
@abe.update_attributes :name => "Zed", :age => 12, :wage => 10.0, :address => "Santa Fe"
|
55
60
|
|
56
|
-
$redis.
|
61
|
+
$redis.llen("user:name_ids").to_i.should == User.count
|
57
62
|
$redis.zcard("user:age_ids").to_i.should == User.count
|
58
63
|
$redis.zcard("user:wage_ids").to_i.should == User.count
|
59
64
|
|
@@ -66,4 +71,60 @@ describe "test options" do
|
|
66
71
|
User.find(:all, :order => [:wage, :asc]).should == [@abe, @todd, @dan, @michael]
|
67
72
|
User.find(:all, :order => [:wage, :desc]).should == [@michael, @dan, @todd, @abe]
|
68
73
|
end
|
74
|
+
|
75
|
+
it "should update keys after the persisted object was deleted and sort properly" do
|
76
|
+
user_count = User.count
|
77
|
+
@abe.destroy
|
78
|
+
|
79
|
+
$redis.llen("user:name_ids").to_i.should == user_count - 1
|
80
|
+
$redis.zcard("user:age_ids").to_i.should == user_count - 1
|
81
|
+
$redis.zcard("user:wage_ids").to_i.should == user_count - 1
|
82
|
+
|
83
|
+
User.find(:all, :order => [:name, :asc]).should == [@dan, @michael, @todd]
|
84
|
+
User.find(:all, :order => [:name, :desc]).should == [@todd, @michael, @dan]
|
85
|
+
|
86
|
+
User.find(:all, :order => [:age, :asc]).should == [@todd, @michael, @dan]
|
87
|
+
User.find(:all, :order => [:age, :desc]).should == [@dan, @michael, @todd]
|
88
|
+
|
89
|
+
User.find(:all, :order => [:wage, :asc]).should == [@todd, @dan, @michael]
|
90
|
+
User.find(:all, :order => [:wage, :desc]).should == [@michael, @dan, @todd]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should sort objects with more than 3-4 symbols" do
|
94
|
+
vladislav = User.create :name => "Vladislav", :age => 19, :wage => 120.0
|
95
|
+
vladimir = User.create :name => "Vladimir", :age => 22, :wage => 220.5
|
96
|
+
vlad = User.create :name => "Vlad", :age => 29, :wage => 1200.0
|
97
|
+
|
98
|
+
User.find(:all, :order => [:name, :desc], :limit => 3).should == [vladislav, vladimir, vlad]
|
99
|
+
User.find(:all, :order => [:name, :desc], :limit => 2, :offset => 4).should == [@michael, @dan]
|
100
|
+
User.find(:all, :order => [:name, :desc], :offset => 3).should == [@todd, @michael, @dan, @abe]
|
101
|
+
User.find(:all, :order => [:name, :desc]).should == [vladislav, vladimir, vlad, @todd, @michael, @dan, @abe]
|
102
|
+
|
103
|
+
User.find(:all, :order => [:name, :asc], :limit => 3, :offset => 4).should == [vlad, vladimir, vladislav]
|
104
|
+
User.find(:all, :order => [:name, :asc], :offset => 3).should == [@todd, vlad, vladimir, vladislav]
|
105
|
+
User.find(:all, :order => [:name, :asc], :limit => 3).should == [@abe, @dan, @michael]
|
106
|
+
User.find(:all, :order => [:name, :asc]).should == [@abe, @dan, @michael, @todd, vlad, vladimir, vladislav]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should properly handle multiple users with almost the same names" do
|
110
|
+
users = []
|
111
|
+
20.times{|i| users << SortableUser.create(:name => "user#{i}") }
|
112
|
+
SortableUser.all(:order => [:name, :asc]).should == users.sort{|n,m| n.name <=> m.name}
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should properly handle multiple users with almost the same names (descending order)" do
|
116
|
+
rev_users = []
|
117
|
+
20.times{|i| rev_users << SortableUser.create(:name => "user#{i}") }
|
118
|
+
SortableUser.all(:order => [:name, :desc]).should == rev_users.sort{|n,m| n.name <=> m.name}.reverse
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should properly store records with the same names" do
|
122
|
+
users = []
|
123
|
+
users << SortableUser.create(:name => "user#1")
|
124
|
+
users << SortableUser.create(:name => "user#2")
|
125
|
+
users << SortableUser.create(:name => "user#1")
|
126
|
+
users << SortableUser.create(:name => "user#2")
|
127
|
+
SortableUser.all(:order => [:name, :desc]).should == users.sort{|n,m| n.name <=> m.name}.reverse
|
128
|
+
SortableUser.all(:order => [:name, :asc]).should == users.sort{|n,m| n.name <=> m.name}
|
129
|
+
end
|
69
130
|
end
|
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:
|
4
|
+
version: 0.6.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-12-05 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: activesupport
|
17
|
-
requirement: &
|
16
|
+
requirement: &17352020 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: 3.0.0
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *17352020
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: activemodel
|
28
|
-
requirement: &
|
27
|
+
requirement: &17367880 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: 3.0.0
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *17367880
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: redis
|
39
|
-
requirement: &
|
38
|
+
requirement: &17367380 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: 2.2.0
|
45
44
|
type: :runtime
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *17367380
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: uuid
|
50
|
-
requirement: &
|
49
|
+
requirement: &17366880 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,10 +54,10 @@ dependencies:
|
|
55
54
|
version: 2.3.2
|
56
55
|
type: :runtime
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *17366880
|
59
58
|
- !ruby/object:Gem::Dependency
|
60
59
|
name: rspec
|
61
|
-
requirement: &
|
60
|
+
requirement: &17366380 !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ! '>='
|
@@ -66,7 +65,7 @@ dependencies:
|
|
66
65
|
version: 2.5.0
|
67
66
|
type: :development
|
68
67
|
prerelease: false
|
69
|
-
version_requirements: *
|
68
|
+
version_requirements: *17366380
|
70
69
|
description: ORM for Redis (advanced key-value storage) with ActiveRecord API
|
71
70
|
email: germaninthetown@gmail.com
|
72
71
|
executables: []
|
@@ -86,10 +85,12 @@ extra_rdoc_files:
|
|
86
85
|
- lib/redis_orm/utils.rb
|
87
86
|
files:
|
88
87
|
- CHANGELOG
|
88
|
+
- Gemfile
|
89
89
|
- LICENSE
|
90
90
|
- Manifest
|
91
91
|
- README.md
|
92
92
|
- Rakefile
|
93
|
+
- benchmarks/sortable_benchmark.rb
|
93
94
|
- lib/redis_orm.rb
|
94
95
|
- lib/redis_orm/active_model_behavior.rb
|
95
96
|
- lib/redis_orm/associations/belongs_to.rb
|
@@ -111,13 +112,12 @@ files:
|
|
111
112
|
- test/has_one_has_many_test.rb
|
112
113
|
- test/indices_test.rb
|
113
114
|
- test/options_test.rb
|
114
|
-
- test/order_test.rb
|
115
115
|
- test/polymorphic_test.rb
|
116
116
|
- test/redis.conf
|
117
|
+
- test/sortable_test.rb
|
117
118
|
- test/test_helper.rb
|
118
119
|
- test/uuid_as_id_test.rb
|
119
120
|
- test/validations_test.rb
|
120
|
-
has_rdoc: true
|
121
121
|
homepage: https://github.com/german/redis_orm
|
122
122
|
licenses: []
|
123
123
|
post_install_message:
|
@@ -144,24 +144,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
144
|
version: '1.2'
|
145
145
|
requirements: []
|
146
146
|
rubyforge_project: redis_orm
|
147
|
-
rubygems_version: 1.6
|
147
|
+
rubygems_version: 1.8.6
|
148
148
|
signing_key:
|
149
149
|
specification_version: 3
|
150
150
|
summary: ORM for Redis (advanced key-value storage) with ActiveRecord API
|
151
151
|
test_files:
|
152
|
+
- test/atomicity_test.rb
|
153
|
+
- test/indices_test.rb
|
154
|
+
- test/sortable_test.rb
|
155
|
+
- test/uuid_as_id_test.rb
|
156
|
+
- test/test_helper.rb
|
152
157
|
- test/options_test.rb
|
153
|
-
- test/
|
158
|
+
- test/callbacks_test.rb
|
159
|
+
- test/exceptions_test.rb
|
154
160
|
- test/associations_test.rb
|
155
161
|
- test/validations_test.rb
|
156
|
-
- test/
|
162
|
+
- test/basic_functionality_test.rb
|
163
|
+
- test/dynamic_finders_test.rb
|
164
|
+
- test/changes_array_test.rb
|
157
165
|
- test/polymorphic_test.rb
|
158
|
-
- test/uuid_as_id_test.rb
|
159
|
-
- test/atomicity_test.rb
|
160
|
-
- test/exceptions_test.rb
|
161
166
|
- test/association_indices_test.rb
|
162
167
|
- test/has_one_has_many_test.rb
|
163
|
-
- test/order_test.rb
|
164
|
-
- test/indices_test.rb
|
165
|
-
- test/changes_array_test.rb
|
166
|
-
- test/callbacks_test.rb
|
167
|
-
- test/basic_functionality_test.rb
|