datamapper 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/MIT-LICENSE +22 -0
- data/README +1 -0
- data/example.rb +25 -0
- data/lib/data_mapper.rb +30 -0
- data/lib/data_mapper/adapters/abstract_adapter.rb +229 -0
- data/lib/data_mapper/adapters/mysql_adapter.rb +171 -0
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +189 -0
- data/lib/data_mapper/associations.rb +19 -0
- data/lib/data_mapper/associations/belongs_to_association.rb +111 -0
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +100 -0
- data/lib/data_mapper/associations/has_many_association.rb +101 -0
- data/lib/data_mapper/associations/has_one_association.rb +107 -0
- data/lib/data_mapper/base.rb +160 -0
- data/lib/data_mapper/callbacks.rb +47 -0
- data/lib/data_mapper/database.rb +134 -0
- data/lib/data_mapper/extensions/active_record_impersonation.rb +69 -0
- data/lib/data_mapper/extensions/callback_helpers.rb +35 -0
- data/lib/data_mapper/identity_map.rb +21 -0
- data/lib/data_mapper/loaded_set.rb +45 -0
- data/lib/data_mapper/mappings/column.rb +78 -0
- data/lib/data_mapper/mappings/schema.rb +28 -0
- data/lib/data_mapper/mappings/table.rb +99 -0
- data/lib/data_mapper/queries/conditions.rb +141 -0
- data/lib/data_mapper/queries/connection.rb +34 -0
- data/lib/data_mapper/queries/create_table_statement.rb +38 -0
- data/lib/data_mapper/queries/delete_statement.rb +17 -0
- data/lib/data_mapper/queries/drop_table_statement.rb +17 -0
- data/lib/data_mapper/queries/insert_statement.rb +29 -0
- data/lib/data_mapper/queries/reader.rb +42 -0
- data/lib/data_mapper/queries/result.rb +19 -0
- data/lib/data_mapper/queries/select_statement.rb +103 -0
- data/lib/data_mapper/queries/table_exists_statement.rb +17 -0
- data/lib/data_mapper/queries/truncate_table_statement.rb +17 -0
- data/lib/data_mapper/queries/update_statement.rb +25 -0
- data/lib/data_mapper/session.rb +240 -0
- data/lib/data_mapper/support/blank_slate.rb +3 -0
- data/lib/data_mapper/support/connection_pool.rb +117 -0
- data/lib/data_mapper/support/enumerable.rb +27 -0
- data/lib/data_mapper/support/inflector.rb +329 -0
- data/lib/data_mapper/support/proc.rb +69 -0
- data/lib/data_mapper/support/string.rb +23 -0
- data/lib/data_mapper/support/symbol.rb +91 -0
- data/lib/data_mapper/support/weak_hash.rb +46 -0
- data/lib/data_mapper/unit_of_work.rb +38 -0
- data/lib/data_mapper/validations/confirmation_validator.rb +55 -0
- data/lib/data_mapper/validations/contextual_validations.rb +50 -0
- data/lib/data_mapper/validations/format_validator.rb +85 -0
- data/lib/data_mapper/validations/formats/email.rb +78 -0
- data/lib/data_mapper/validations/generic_validator.rb +27 -0
- data/lib/data_mapper/validations/length_validator.rb +75 -0
- data/lib/data_mapper/validations/required_field_validator.rb +47 -0
- data/lib/data_mapper/validations/unique_validator.rb +65 -0
- data/lib/data_mapper/validations/validation_errors.rb +34 -0
- data/lib/data_mapper/validations/validation_helper.rb +60 -0
- data/performance.rb +156 -0
- data/profile_data_mapper.rb +18 -0
- data/rakefile.rb +80 -0
- data/spec/basic_finder.rb +67 -0
- data/spec/belongs_to.rb +47 -0
- data/spec/fixtures/animals.yaml +32 -0
- data/spec/fixtures/exhibits.yaml +90 -0
- data/spec/fixtures/fruit.yaml +6 -0
- data/spec/fixtures/people.yaml +15 -0
- data/spec/fixtures/zoos.yaml +20 -0
- data/spec/has_and_belongs_to_many.rb +25 -0
- data/spec/has_many.rb +34 -0
- data/spec/legacy.rb +14 -0
- data/spec/models/animal.rb +7 -0
- data/spec/models/exhibit.rb +6 -0
- data/spec/models/fruit.rb +6 -0
- data/spec/models/person.rb +7 -0
- data/spec/models/post.rb +4 -0
- data/spec/models/sales_person.rb +4 -0
- data/spec/models/zoo.rb +5 -0
- data/spec/new_record.rb +24 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/sub_select.rb +16 -0
- data/spec/symbolic_operators.rb +21 -0
- data/spec/validates_confirmation_of.rb +36 -0
- data/spec/validates_format_of.rb +61 -0
- data/spec/validates_length_of.rb +101 -0
- data/spec/validates_uniqueness_of.rb +45 -0
- data/spec/validations.rb +63 -0
- metadata +134 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
# http://www.faqs.org/rfcs/rfc2822.html
|
2
|
+
module DataMapper
|
3
|
+
module Validations
|
4
|
+
module Helpers
|
5
|
+
module Email
|
6
|
+
|
7
|
+
module RFC2822
|
8
|
+
EmailAddress = begin
|
9
|
+
alpha = "a-zA-Z"
|
10
|
+
digit = "0-9"
|
11
|
+
atext = "[#{alpha}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
|
12
|
+
dot_atom_text = "#{atext}+([.]#{atext}*)*"
|
13
|
+
dot_atom = "#{dot_atom_text}"
|
14
|
+
qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
|
15
|
+
text = "[\\x01-\\x09\\x11\\x12\\x14-\\x7f]"
|
16
|
+
quoted_pair = "(\\x5c#{text})"
|
17
|
+
qcontent = "(?:#{qtext}|#{quoted_pair})"
|
18
|
+
quoted_string = "[\"]#{qcontent}+[\"]"
|
19
|
+
atom = "#{atext}+"
|
20
|
+
word = "(?:#{atom}|#{quoted_string})"
|
21
|
+
obs_local_part = "#{word}([.]#{word})*"
|
22
|
+
local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
|
23
|
+
no_ws_ctl = "\\x01-\\x08\\x11\\x12\\x14-\\x1f\\x7f"
|
24
|
+
dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
|
25
|
+
dcontent = "(?:#{dtext}|#{quoted_pair})"
|
26
|
+
domain_literal = "\\[#{dcontent}+\\]"
|
27
|
+
obs_domain = "#{atom}([.]#{atom})*"
|
28
|
+
domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
|
29
|
+
addr_spec = "#{local_part}\@#{domain}"
|
30
|
+
pattern = /^#{addr_spec}$/
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
=begin
|
40
|
+
addresses = [
|
41
|
+
'-- dave --@example.com', # (spaces are invalid unless enclosed in quotation marks)
|
42
|
+
'[dave]@example.com', # (square brackets are invalid, unless contained within quotation marks)
|
43
|
+
'.dave@example.com', # (the local part of a domain name cannot start with a period)
|
44
|
+
'Max@Job 3:14',
|
45
|
+
'Job@Book of Job',
|
46
|
+
'J. P. \'s-Gravezande, a.k.a. The Hacker!@example.com',
|
47
|
+
]
|
48
|
+
addresses.each do |address|
|
49
|
+
if address =~ RFC2822::EmailAddress
|
50
|
+
puts "#{address} deveria ter sido rejeitado, ERRO"
|
51
|
+
else
|
52
|
+
puts "#{address} rejeitado, OK"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
addresses = [
|
58
|
+
'+1~1+@example.com',
|
59
|
+
'{_dave_}@example.com',
|
60
|
+
'"[[ dave ]]"@example.com',
|
61
|
+
'dave."dave"@example.com',
|
62
|
+
'test@localhost',
|
63
|
+
'test@example.com',
|
64
|
+
'test@example.co.uk',
|
65
|
+
'test@example.com.br',
|
66
|
+
'"J. P. \'s-Gravezande, a.k.a. The Hacker!"@example.com',
|
67
|
+
'me@[187.223.45.119]',
|
68
|
+
'someone@123.com',
|
69
|
+
'simon&garfunkel@songs.com'
|
70
|
+
]
|
71
|
+
addresses.each do |address|
|
72
|
+
if address =~ RFC2822::EmailAddress
|
73
|
+
puts "#{address} aceito, OK"
|
74
|
+
else
|
75
|
+
puts "#{address} deveria ser aceito, ERRO"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
=end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
# All Validators should inherit from the GenericValidator.
|
5
|
+
class GenericValidator
|
6
|
+
|
7
|
+
# Adds an error message to the target class.
|
8
|
+
def add_error(target, message, attribute = :base)
|
9
|
+
target.errors.add(attribute, message)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets the proper error message
|
13
|
+
def validation_error_message(default, custom_message, validation_binding)
|
14
|
+
eval("\"#{(custom_message || default)}\"", validation_binding)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Call the validator. We use "call" so the operation
|
18
|
+
# is BoundMethod and Block compatible.
|
19
|
+
# The result should always be TRUE or FALSE.
|
20
|
+
def call(target)
|
21
|
+
raise 'You must overwrite this method'
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
class LengthValidator < GenericValidator
|
5
|
+
|
6
|
+
ERROR_MESSAGES = {
|
7
|
+
:range => '#{field} must be between #{min} and #{max} characters long',
|
8
|
+
:min => '#{field} must be more than #{min} characters long',
|
9
|
+
:max => '#{field} must be less than #{max} characters long',
|
10
|
+
:equals => '#{field} must be #{equal} characters long'
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(field_name, options)
|
14
|
+
@field_name = field_name
|
15
|
+
@options = options
|
16
|
+
|
17
|
+
@min = options[:minimum] || options[:min]
|
18
|
+
@max = options[:maximum] || options[:max]
|
19
|
+
@equal = options[:is] || options[:equals]
|
20
|
+
@range = options[:within] || options[:in]
|
21
|
+
|
22
|
+
@validation_method ||= :range if @range
|
23
|
+
@validation_method ||= :min if @min && @max.nil?
|
24
|
+
@validation_method ||= :max if @max && @min.nil?
|
25
|
+
@validation_method ||= :equals unless @equal.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(target)
|
29
|
+
field_value = target.instance_variable_get("@#{@field_name}").to_s
|
30
|
+
return true if @options[:allow_nil] && field_value.nil?
|
31
|
+
|
32
|
+
# HACK seems hacky to do this on every validation, probably should do this elsewhere?
|
33
|
+
field = Inflector.humanize(@field_name)
|
34
|
+
min = @range ? @range.min : @min
|
35
|
+
max = @range ? @range.max : @max
|
36
|
+
equal = @equal
|
37
|
+
|
38
|
+
error_message = validation_error_message(ERROR_MESSAGES[@validation_method], nil, binding)
|
39
|
+
|
40
|
+
valid = case @validation_method
|
41
|
+
when :range then
|
42
|
+
@range.include?(field_value.size)
|
43
|
+
when :min then
|
44
|
+
field_value.size >= min
|
45
|
+
when :max then
|
46
|
+
field_value.size <= max
|
47
|
+
when :equals then
|
48
|
+
field_value.size == equal
|
49
|
+
end
|
50
|
+
|
51
|
+
add_error(target, error_message, @field_name) unless valid
|
52
|
+
|
53
|
+
return valid
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
module ValidatesLengthOf
|
59
|
+
def self.included(base)
|
60
|
+
base.extend(ClassMethods)
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods
|
64
|
+
DEFAULT_VALIDATES_LENGTH_OF_OPTIONS = { :on => :save }
|
65
|
+
|
66
|
+
def validates_length_of(field, options = {})
|
67
|
+
opts = retrieve_options_from_arguments_for_validators([options], DEFAULT_VALIDATES_LENGTH_OF_OPTIONS)
|
68
|
+
validations.context(opts[:context]) << Validations::LengthValidator.new(field, opts)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
class RequiredFieldValidator < GenericValidator
|
5
|
+
|
6
|
+
ERROR_MESSAGES = {
|
7
|
+
:required => '#{field} must not be blank'
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(field_name)
|
11
|
+
@field_name = field_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(target)
|
15
|
+
field_value = !target.instance_variable_get("@#{@field_name}").nil?
|
16
|
+
return true if field_value
|
17
|
+
|
18
|
+
field = Inflector.humanize(@field_name)
|
19
|
+
|
20
|
+
error_message = validation_error_message(ERROR_MESSAGES[:required], nil, binding)
|
21
|
+
add_error(target, error_message , @field_name)
|
22
|
+
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
module ValidatesPresenceOf
|
29
|
+
def self.included(base)
|
30
|
+
base.extend(ClassMethods)
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
|
35
|
+
def validates_presence_of(*fields)
|
36
|
+
options = retrieve_options_from_arguments_for_validators(fields)
|
37
|
+
|
38
|
+
fields.each do |field|
|
39
|
+
validations.context(options[:context]) << Validations::RequiredFieldValidator.new(field)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
class UniqueValidator < GenericValidator
|
5
|
+
|
6
|
+
ERROR_MESSAGES = {
|
7
|
+
:unique => '#{field} has already been taken'
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(field_name, options = {})
|
11
|
+
@options = options
|
12
|
+
@field_name = field_name.to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(target)
|
16
|
+
field = Inflector.humanize(@field_name)
|
17
|
+
|
18
|
+
unless valid?(target)
|
19
|
+
error_message = validation_error_message(ERROR_MESSAGES[:unique], nil, binding)
|
20
|
+
add_error(target, error_message , @field_name)
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid?(target)
|
28
|
+
field_value = target.instance_variable_get("@#{@field_name}")
|
29
|
+
return true if @options[:allow_nil] && field_value.nil?
|
30
|
+
|
31
|
+
finder_options = { @field_name => field_value }
|
32
|
+
|
33
|
+
if @options[:scope]
|
34
|
+
scope_value = target.instance_variable_get("@#{@options[:scope]}")
|
35
|
+
finder_options.merge! @options[:scope] => scope_value
|
36
|
+
end
|
37
|
+
|
38
|
+
finder_options.merge!({ target.session.mappings[target.class].key.name.not => target.key }) unless target.new_record?
|
39
|
+
|
40
|
+
# HACK: gotta make sure we're using the same database that this instance was
|
41
|
+
# found with unless new_record?
|
42
|
+
target.session.find(target.class, :first, finder_options).nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
module ValidatesUniquenessOf
|
48
|
+
def self.included(base)
|
49
|
+
base.extend(ClassMethods)
|
50
|
+
end
|
51
|
+
|
52
|
+
module ClassMethods
|
53
|
+
# No bueno?
|
54
|
+
DEFAULT_OPTIONS = { :on => :save }
|
55
|
+
|
56
|
+
def validates_uniqueness_of(field, options = {})
|
57
|
+
opts = retrieve_options_from_arguments_for_validators([options], DEFAULT_OPTIONS)
|
58
|
+
validations.context(opts[:context]) << Validations::UniqueValidator.new(field, opts)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module DataMapper
|
2
|
+
|
3
|
+
class ValidationErrors
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@errors = Hash.new { |h,k| h[k.to_sym] = [] }
|
7
|
+
end
|
8
|
+
|
9
|
+
# Clear existing validation errors.
|
10
|
+
def clear!
|
11
|
+
@errors.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
# Add a validation error. Use the attribute :general if
|
15
|
+
# the error doesn't apply to a specific attribute.
|
16
|
+
def add(attribute, message)
|
17
|
+
@errors[attribute] << message
|
18
|
+
end
|
19
|
+
|
20
|
+
# Collect all errors into a single list.
|
21
|
+
def full_messages
|
22
|
+
@errors.inject([]) do |list,pair|
|
23
|
+
list += pair.last
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Are any errors present?
|
28
|
+
def empty?
|
29
|
+
@errors.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
dirname = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require dirname + '/validation_errors'
|
4
|
+
require dirname + '/contextual_validations'
|
5
|
+
require dirname + '/generic_validator'
|
6
|
+
|
7
|
+
Dir[dirname + '/*_validator.rb'].reject do |path|
|
8
|
+
path =~ /\/generic_validator/
|
9
|
+
end.each do |validator|
|
10
|
+
load validator
|
11
|
+
end
|
12
|
+
|
13
|
+
module DataMapper
|
14
|
+
module Extensions
|
15
|
+
|
16
|
+
module ValidationHelper
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
base.class_eval do
|
21
|
+
include DataMapper::Validations::ValidatesPresenceOf
|
22
|
+
include DataMapper::Validations::ValidatesLengthOf
|
23
|
+
include DataMapper::Validations::ValidatesConfirmationOf
|
24
|
+
include DataMapper::Validations::ValidatesUniquenessOf
|
25
|
+
include DataMapper::Validations::ValidatesFormatOf
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def errors
|
30
|
+
@errors ||= ValidationErrors.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def valid?(context = :general)
|
34
|
+
self.class.validations.execute(context, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
|
39
|
+
def validations
|
40
|
+
@validations ||= ContextualValidations.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def retrieve_options_from_arguments_for_validators(args, defaults = nil)
|
44
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
45
|
+
|
46
|
+
context = :general
|
47
|
+
context = options[:context] if options.has_key?(:context)
|
48
|
+
context = options.delete(:on) if options.has_key?(:on)
|
49
|
+
options[:context] = context
|
50
|
+
|
51
|
+
options.merge!(defaults) unless defaults.nil?
|
52
|
+
return options
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/performance.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection :adapter => 'mysql',
|
4
|
+
:host => 'localhost',
|
5
|
+
:username => 'root',
|
6
|
+
:password => '',
|
7
|
+
:database => 'data_mapper_1'
|
8
|
+
|
9
|
+
class ARAnimal < ActiveRecord::Base
|
10
|
+
set_table_name 'animals'
|
11
|
+
end
|
12
|
+
|
13
|
+
class ARPerson < ActiveRecord::Base
|
14
|
+
set_table_name 'people'
|
15
|
+
end
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift('lib')
|
18
|
+
require 'data_mapper'
|
19
|
+
|
20
|
+
log_path = File.dirname(__FILE__) + '/development.log'
|
21
|
+
|
22
|
+
require 'fileutils'
|
23
|
+
FileUtils::rm log_path if File.exists?(log_path)
|
24
|
+
|
25
|
+
DataMapper::Database.setup do
|
26
|
+
adapter 'mysql'
|
27
|
+
username 'root'
|
28
|
+
database 'data_mapper_1'
|
29
|
+
log_stream 'development.log'
|
30
|
+
log_level Logger::DEBUG
|
31
|
+
end
|
32
|
+
|
33
|
+
class DMAnimal < DataMapper::Base
|
34
|
+
set_table_name 'animals'
|
35
|
+
property :name, :string
|
36
|
+
property :notes, :string, :lazy => true
|
37
|
+
end
|
38
|
+
|
39
|
+
class DMPerson < DataMapper::Base
|
40
|
+
set_table_name 'people'
|
41
|
+
property :name, :string
|
42
|
+
property :age, :integer
|
43
|
+
property :occupation, :string
|
44
|
+
property :notes, :text, :lazy => true
|
45
|
+
end
|
46
|
+
|
47
|
+
class Exhibit < DataMapper::Base
|
48
|
+
property :name, :string
|
49
|
+
belongs_to :zoo
|
50
|
+
end
|
51
|
+
|
52
|
+
class Zoo < DataMapper::Base
|
53
|
+
property :name, :string
|
54
|
+
has_many :exhibits
|
55
|
+
end
|
56
|
+
|
57
|
+
class ARZoo < ActiveRecord::Base
|
58
|
+
set_table_name 'zoos'
|
59
|
+
has_many :exhibits, :class_name => 'ARExhibit', :foreign_key => 'zoo_id'
|
60
|
+
end
|
61
|
+
|
62
|
+
class ARExhibit < ActiveRecord::Base
|
63
|
+
set_table_name 'exhibits'
|
64
|
+
belongs_to :zoo, :class_name => 'ARZoo', :foreign_key => 'zoo_id'
|
65
|
+
end
|
66
|
+
|
67
|
+
N = (ENV['N'] || 1000).to_i
|
68
|
+
|
69
|
+
Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
|
70
|
+
|
71
|
+
x.report('ActiveRecord:id') do
|
72
|
+
N.times { ARAnimal.find(1) }
|
73
|
+
end
|
74
|
+
|
75
|
+
x.report('DataMapper:id') do
|
76
|
+
N.times { DMAnimal[1] }
|
77
|
+
end
|
78
|
+
|
79
|
+
x.report('ActiveRecord:conditions') do
|
80
|
+
N.times { ARZoo.find(:first, :conditions => ['name = ?', 'Galveston']) }
|
81
|
+
end
|
82
|
+
|
83
|
+
x.report('DataMapper:conditions:short') do
|
84
|
+
N.times { Zoo[:name => 'Galveston'] }
|
85
|
+
end
|
86
|
+
|
87
|
+
x.report('DataMapper:conditions:long') do
|
88
|
+
N.times { Zoo.find(:first, :conditions => ['name = ?', 'Galveston']) }
|
89
|
+
end
|
90
|
+
|
91
|
+
people = [
|
92
|
+
['Sam', 29, 'Programmer'],
|
93
|
+
['Amy', 28, 'Business Analyst Manager'],
|
94
|
+
['Scott', 25, 'Programmer'],
|
95
|
+
['Josh', 23, 'Supervisor'],
|
96
|
+
['Bob', 40, 'Peon']
|
97
|
+
]
|
98
|
+
|
99
|
+
DMPerson.truncate!
|
100
|
+
|
101
|
+
x.report('ActiveRecord:insert') do
|
102
|
+
N.times do
|
103
|
+
people.each do |a|
|
104
|
+
ARPerson::create(:name => a[0], :age => a[1], :occupation => a[2])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
DMPerson.truncate!
|
110
|
+
|
111
|
+
x.report('DataMapper:insert') do
|
112
|
+
N.times do
|
113
|
+
people.each do |a|
|
114
|
+
DMPerson::create(:name => a[0], :age => a[1], :occupation => a[2])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
x.report('ActiveRecord:update') do
|
120
|
+
N.times do
|
121
|
+
bob = ARAnimal.find(:first, :conditions => ["name = ?", 'elephant'])
|
122
|
+
bob.notes = 'Updated by ActiveRecord'
|
123
|
+
bob.save
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
x.report('DataMapper:update') do
|
128
|
+
N.times do
|
129
|
+
bob = DMAnimal.first(:name => 'elephant')
|
130
|
+
bob.notes = 'Updated by DataMapper'
|
131
|
+
bob.save
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
x.report('ActiveRecord:associations:lazy') do
|
136
|
+
N.times do
|
137
|
+
zoos = ARZoo.find(:all)
|
138
|
+
zoos.each { |zoo| zoo.exhibits.entries }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
x.report('ActiveRecord:associations:included') do
|
143
|
+
N.times do
|
144
|
+
zoos = ARZoo.find(:all, :include => [:exhibits])
|
145
|
+
zoos.each { |zoo| zoo.exhibits.entries }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
x.report('DataMapper:associations') do
|
150
|
+
N.times do
|
151
|
+
database do
|
152
|
+
Zoo.all.each { |zoo| zoo.exhibits.entries }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|