diff options
-rw-r--r-- | activerecord/examples/.gitignore | 1 | ||||
-rwxr-xr-x | activerecord/examples/performance.rb | 162 | ||||
-rw-r--r-- | activeresource/lib/active_resource/base.rb | 22 | ||||
-rw-r--r-- | activeresource/test/cases/finder_test.rb | 38 |
4 files changed, 223 insertions, 0 deletions
diff --git a/activerecord/examples/.gitignore b/activerecord/examples/.gitignore new file mode 100644 index 0000000000..0dfc1cb7fb --- /dev/null +++ b/activerecord/examples/.gitignore @@ -0,0 +1 @@ +performance.sql diff --git a/activerecord/examples/performance.rb b/activerecord/examples/performance.rb new file mode 100755 index 0000000000..12153b490a --- /dev/null +++ b/activerecord/examples/performance.rb @@ -0,0 +1,162 @@ +#!/usr/bin/env ruby -KU + +TIMES = (ENV['N'] || 10000).to_i + +require 'rubygems' +gem 'addressable', '~>2.0' +gem 'faker', '~>0.3.1' +gem 'rbench', '~>0.2.3' +require 'addressable/uri' +require 'faker' +require 'rbench' + +__DIR__ = File.dirname(__FILE__) +$:.unshift "#{__DIR__}/../lib" +require 'active_record' + +conn = { :adapter => 'mysql', + :database => 'activerecord_unittest', + :username => 'rails', :password => '', + :encoding => 'utf8' } + +conn[:socket] = Pathname.glob(%w[ + /opt/local/var/run/mysql5/mysqld.sock + /tmp/mysqld.sock + /tmp/mysql.sock + /var/mysql/mysql.sock + /var/run/mysqld/mysqld.sock +]).find { |path| path.socket? } + +ActiveRecord::Base.establish_connection(conn) + +class User < ActiveRecord::Base + connection.create_table :users, :force => true do |t| + t.string :name, :email + t.timestamps + end + + has_many :exhibits +end + +class Exhibit < ActiveRecord::Base + connection.create_table :exhibits, :force => true do |t| + t.belongs_to :user + t.string :name + t.text :notes + t.timestamps + end + + belongs_to :user + + def look; attributes end + def feel; look; user.name end + + def self.look(exhibits) exhibits.each { |e| e.look } end + def self.feel(exhibits) exhibits.each { |e| e.feel } end +end + +sqlfile = "#{__DIR__}/performance.sql" + +if File.exists?(sqlfile) + mysql_bin = %w[mysql mysql5].select { |bin| `which #{bin}`.length > 0 } + `#{mysql_bin} -u #{conn[:username]} #{"-p#{conn[:password]}" unless conn[:password].blank?} #{conn[:database]} < #{sqlfile}` +else + puts 'Generating data...' + + # pre-compute the insert statements and fake data compilation, + # so the benchmarks below show the actual runtime for the execute + # method, minus the setup steps + + # Using the same paragraph for all exhibits because it is very slow + # to generate unique paragraphs for all exhibits. + notes = Faker::Lorem.paragraphs.join($/) + today = Date.today + + puts 'Inserting 10,000 users and exhibits...' + 10_000.times do + user = User.create( + :created_on => today, + :name => Faker::Name.name, + :email => Faker::Internet.email + ) + + Exhibit.create( + :created_on => today, + :name => Faker::Company.name, + :user => user, + :notes => notes + ) + end + + mysqldump_bin = %w[mysqldump mysqldump5].select { |bin| `which #{bin}`.length > 0 } + `#{mysqldump_bin} -u #{conn[:username]} #{"-p#{conn[:password]}" unless conn[:password].blank?} #{conn[:database]} exhibits users > #{sqlfile}` +end + +RBench.run(TIMES) do + column :times + column :ar + + report 'Model#id', (TIMES * 100).ceil do + ar_obj = Exhibit.find(1) + + ar { ar_obj.id } + end + + report 'Model.new (instantiation)' do + ar { Exhibit.new } + end + + report 'Model.new (setting attributes)' do + attrs = { :name => 'sam' } + ar { Exhibit.new(attrs) } + end + + report 'Model.first' do + ar { Exhibit.first.look } + end + + report 'Model.all limit(100)', (TIMES / 10).ceil do + ar { Exhibit.look Exhibit.all(:limit => 100) } + end + + report 'Model.all limit(100) with relationship', (TIMES / 10).ceil do + ar { Exhibit.feel Exhibit.all(:limit => 100, :include => :user) } + end + + report 'Model.all limit(10,000)', (TIMES / 1000).ceil do + ar { Exhibit.look Exhibit.all(:limit => 10000) } + end + + exhibit = { + :name => Faker::Company.name, + :notes => Faker::Lorem.paragraphs.join($/), + :created_on => Date.today + } + + report 'Model.create' do + ar { Exhibit.create(exhibit) } + end + + report 'Resource#attributes=' do + attrs_first = { :name => 'sam' } + attrs_second = { :name => 'tom' } + ar { exhibit = Exhibit.new(attrs_first); exhibit.attributes = attrs_second } + end + + report 'Resource#update' do + ar { Exhibit.first.update_attributes(:name => 'bob') } + end + + report 'Resource#destroy' do + ar { Exhibit.first.destroy } + end + + report 'Model.transaction' do + ar { Exhibit.transaction { Exhibit.new } } + end + + summary 'Total' +end + +ActiveRecord::Migration.drop_table "exhibits" +ActiveRecord::Migration.drop_table "users" diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index f27febb7ef..e5b8589fb3 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -611,6 +611,28 @@ module ActiveResource end end + + # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass + # in all the same arguments to this method as you can to + # <tt>find(:first)</tt>. + def first(*args) + find(:first, *args) + end + + # A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass + # in all the same arguments to this method as you can to + # <tt>find(:last)</tt>. + def last(*args) + find(:last, *args) + end + + # This is an alias for find(:all). You can pass in all the same + # arguments to this method as you can to <tt>find(:all)</tt> + def all(*args) + find(:all, *args) + end + + # Deletes the resources with the ID in the +id+ parameter. # # ==== Options diff --git a/activeresource/test/cases/finder_test.rb b/activeresource/test/cases/finder_test.rb index 38f7de96ac..535b6f4198 100644 --- a/activeresource/test/cases/finder_test.rb +++ b/activeresource/test/cases/finder_test.rb @@ -126,18 +126,56 @@ class FinderTest < Test::Unit::TestCase assert_equal "David", all.last.name end + def test_all + all = Person.all + assert_equal 2, all.size + assert_kind_of Person, all.first + assert_equal "Matz", all.first.name + assert_equal "David", all.last.name + end + + def test_all_with_params + all = StreetAddress.all(:params => { :person_id => 1 }) + assert_equal 1, all.size + assert_kind_of StreetAddress, all.first + end + def test_find_first matz = Person.find(:first) assert_kind_of Person, matz assert_equal "Matz", matz.name end + def test_first + matz = Person.first + assert_kind_of Person, matz + assert_equal "Matz", matz.name + end + + def test_first_with_params + addy = StreetAddress.first(:params => { :person_id => 1 }) + assert_kind_of StreetAddress, addy + assert_equal '12345 Street', addy.street + end + def test_find_last david = Person.find(:last) assert_kind_of Person, david assert_equal 'David', david.name end + def test_last + david = Person.last + assert_kind_of Person, david + assert_equal 'David', david.name + end + + def test_last_with_params + addy = StreetAddress.last(:params => { :person_id => 1 }) + assert_kind_of StreetAddress, addy + assert_equal '12345 Street', addy.street + end + def test_find_by_id_not_found assert_raise(ActiveResource::ResourceNotFound) { Person.find(99) } assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1) } |