alvarobp-inverse_sortable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest +11 -0
- data/README.rdoc +33 -0
- data/Rakefile +12 -0
- data/TODO +1 -0
- data/benchmark/benchmark.rb +65 -0
- data/benchmark/schema.rb +13 -0
- data/init.rb +1 -0
- data/lib/inverse_sortable.rb +34 -0
- data/test/inverse_sortable_test.rb +40 -0
- data/test/schema.rb +25 -0
- data/test/test_helper.rb +25 -0
- metadata +66 -0
data/Manifest
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
= inverse_sortable
|
2
|
+
|
3
|
+
Sets negative timestamps on Active Record models for efficiently sort in reverse order.
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
sudo gem install alvarobp-inverse_sortable --source http://gems.github.com
|
8
|
+
|
9
|
+
Add to environment.rb:
|
10
|
+
|
11
|
+
config.gem "alvarobp-inverse_sortable", :lib => "inverse_sortable"
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
As a very simple plugin, using it is simple. Just add an integer attribute called "created_at_inverse" to your model. Afterwards you can make that model inverse sortable, for example:
|
16
|
+
|
17
|
+
class Film < ActiveRecord::Base
|
18
|
+
acts_as_inverse_sortable
|
19
|
+
end
|
20
|
+
|
21
|
+
Therefore, you can get an inverse sorted array of Films with Film.find(:all, :order => 'created_at_inverse') working on an efficient way.
|
22
|
+
|
23
|
+
== Test
|
24
|
+
|
25
|
+
Just do
|
26
|
+
|
27
|
+
rake test
|
28
|
+
|
29
|
+
== Benchmarks
|
30
|
+
|
31
|
+
I ran some benchmarks to see how efficient is this method. Well, most of the times benchmarks showed that this method is more efficient than "ORDER BY created_at DESC" as the table grows.
|
32
|
+
|
33
|
+
Just in case you want to run these benchmarks, you will need a mysql database (maybe other engines as well) and configure it at the top of benchmark/benchmark.rb file.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('inverse_sortable', '0.1.0') do |p|
|
6
|
+
p.description = "Sets negative timestamps on Active Record models for efficiently sort in reverse order."
|
7
|
+
p.url = "http://github.com/alvarobp/inverse_sortable"
|
8
|
+
p.author = "Alvaro Bautista Pino"
|
9
|
+
p.email = "alvarobp@gmail.com"
|
10
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
11
|
+
p.development_dependencies = []
|
12
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
- Go deep in the fact that in Rails 2.3 on before_create record attributes information is not available.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection({
|
7
|
+
:adapter => "mysql",
|
8
|
+
:database => "testing_dates",
|
9
|
+
:username => "root",
|
10
|
+
:password => "",
|
11
|
+
:host => "localhost"
|
12
|
+
})
|
13
|
+
|
14
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
15
|
+
|
16
|
+
class WithCreatedModel < ActiveRecord::Base
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_rows(ntimes)
|
20
|
+
tdate = Time.now-100.days
|
21
|
+
ntimes.times do |n|
|
22
|
+
wcm = WithCreatedModel.create(:something => "Model #{n}")
|
23
|
+
tdate += (rand(5)+1).days
|
24
|
+
wcm.update_attribute(:created_at, tdate)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def do_benchmark
|
29
|
+
Benchmark.bm(10) do |x|
|
30
|
+
x.report("normal") {WithCreatedModel.find(:all, :order => "created_at DESC")}
|
31
|
+
x.report("inverse") {WithCreatedModel.find(:all, :order => "created_at_inverse")}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
puts
|
36
|
+
puts
|
37
|
+
puts "-- Benchmark for 5000 rows --"
|
38
|
+
puts
|
39
|
+
|
40
|
+
add_rows(5000)
|
41
|
+
do_benchmark
|
42
|
+
|
43
|
+
puts
|
44
|
+
puts
|
45
|
+
puts "-- Benchmark for 10000 rows --"
|
46
|
+
puts
|
47
|
+
|
48
|
+
add_rows(5000)
|
49
|
+
do_benchmark
|
50
|
+
|
51
|
+
puts
|
52
|
+
puts
|
53
|
+
puts "-- Benchmark for 15000 rows --"
|
54
|
+
puts
|
55
|
+
|
56
|
+
add_rows(5000)
|
57
|
+
do_benchmark
|
58
|
+
|
59
|
+
puts
|
60
|
+
puts
|
61
|
+
puts "-- Benchmark for 20000 rows --"
|
62
|
+
puts
|
63
|
+
|
64
|
+
add_rows(5000)
|
65
|
+
do_benchmark
|
data/benchmark/schema.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
begin
|
3
|
+
drop_table :with_created_models
|
4
|
+
rescue
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table :with_created_models, :force => true do |t|
|
8
|
+
t.column :something, :string
|
9
|
+
t.column :created_at, :datetime
|
10
|
+
t.column :updated_at, :datetime
|
11
|
+
t.column :created_at_inverse, :integer
|
12
|
+
end
|
13
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'inverse_sortable'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module InverseSortable
|
2
|
+
def self.included(base)
|
3
|
+
super
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def acts_as_inverse_sortable
|
9
|
+
include InverseSortable::InstanceMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module InstanceMethods
|
14
|
+
def set_created_at_inverse
|
15
|
+
self.update_attribute(:created_at_inverse, -self.created_at.to_i)
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_updated_at_inverse
|
19
|
+
self.updated_at_inverse = -Time.now.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
def after_create
|
23
|
+
set_created_at_inverse if self.respond_to?(:created_at_inverse)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def before_save
|
28
|
+
set_updated_at_inverse if self.respond_to?(:updated_at_inverse)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
ActiveRecord::Base.send :include, InverseSortable
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class WithCreatedModel
|
4
|
+
acts_as_inverse_sortable
|
5
|
+
end
|
6
|
+
|
7
|
+
class WithUpdatedModel
|
8
|
+
acts_as_inverse_sortable
|
9
|
+
end
|
10
|
+
|
11
|
+
class WithBothModel
|
12
|
+
acts_as_inverse_sortable
|
13
|
+
end
|
14
|
+
|
15
|
+
class ActsAsInverseSortableTest < Test::Unit::TestCase
|
16
|
+
context "A model that acts as an inverse sortable" do
|
17
|
+
should "have the inverse of its created_at time when is created if created_at_inverse is available" do
|
18
|
+
with_created = WithCreatedModel.create(:something => "Testing")
|
19
|
+
|
20
|
+
assert_not_nil with_created.created_at_inverse
|
21
|
+
assert_equal -with_created.created_at.to_i, with_created.created_at_inverse
|
22
|
+
end
|
23
|
+
|
24
|
+
should "have the inverse of its updated_at time when is created if updated_at_inverse is available" do
|
25
|
+
with_updated = WithUpdatedModel.create(:something => "Testing")
|
26
|
+
|
27
|
+
assert_not_nil with_updated.updated_at_inverse
|
28
|
+
assert_equal -with_updated.updated_at.to_i, with_updated.updated_at_inverse
|
29
|
+
end
|
30
|
+
|
31
|
+
should "update its updated_at_inverse value at update" do
|
32
|
+
with_updated = WithUpdatedModel.create(:something => "Testing")
|
33
|
+
before_updated = with_updated.updated_at_inverse
|
34
|
+
sleep 1
|
35
|
+
with_updated.update_attribute(:something, "Testing update")
|
36
|
+
|
37
|
+
assert with_updated.updated_at_inverse < before_updated
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :with_created_models, :force => true do |t|
|
3
|
+
t.column :something, :string
|
4
|
+
t.column :created_at, :datetime
|
5
|
+
t.column :updated_at, :datetime
|
6
|
+
t.column :created_at_inverse, :integer
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :with_created_models, :created_at_inverse
|
10
|
+
|
11
|
+
create_table :with_updated_models, :force => true do |t|
|
12
|
+
t.column :something, :string
|
13
|
+
t.column :created_at, :datetime
|
14
|
+
t.column :updated_at, :datetime
|
15
|
+
t.column :updated_at_inverse, :integer
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :with_both_models, :force => true do |t|
|
19
|
+
t.column :something, :string
|
20
|
+
t.column :created_at, :datetime
|
21
|
+
t.column :updated_at, :datetime
|
22
|
+
t.column :created_at_inverse, :integer
|
23
|
+
t.column :updated_at_inverse, :integer
|
24
|
+
end
|
25
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'active_record'
|
7
|
+
require 'shoulda'
|
8
|
+
|
9
|
+
require File.dirname(__FILE__) + '/../lib/inverse_sortable'
|
10
|
+
|
11
|
+
ActiveRecord::Base.establish_connection({
|
12
|
+
:adapter => "sqlite3",
|
13
|
+
:dbfile => "test/test.db"
|
14
|
+
})
|
15
|
+
|
16
|
+
class WithCreatedModel < ActiveRecord::Base
|
17
|
+
end
|
18
|
+
|
19
|
+
class WithUpdatedModel < ActiveRecord::Base
|
20
|
+
end
|
21
|
+
|
22
|
+
class WithBothModel < ActiveRecord::Base
|
23
|
+
end
|
24
|
+
|
25
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: alvarobp-inverse_sortable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alvaro Bautista Pino
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-19 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Sets negative timestamps on Active Record models for efficiently sort in reverse order.
|
17
|
+
email: alvarobp@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/inverse_sortable.rb
|
24
|
+
- README.rdoc
|
25
|
+
- TODO
|
26
|
+
files:
|
27
|
+
- benchmark/benchmark.rb
|
28
|
+
- benchmark/schema.rb
|
29
|
+
- init.rb
|
30
|
+
- lib/inverse_sortable.rb
|
31
|
+
- Manifest
|
32
|
+
- Rakefile
|
33
|
+
- README.rdoc
|
34
|
+
- test/inverse_sortable_test.rb
|
35
|
+
- test/schema.rb
|
36
|
+
- test/test_helper.rb
|
37
|
+
- TODO
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/alvarobp/inverse_sortable
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "1.2"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project: inverse_sortable
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Sets negative timestamps on Active Record models for efficiently sort in reverse order.
|
64
|
+
test_files:
|
65
|
+
- test/inverse_sortable_test.rb
|
66
|
+
- test/test_helper.rb
|