datamapper 0.1.0 → 0.1.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 +31 -1
- data/MIT-LICENSE +1 -1
- data/README +9 -1
- data/example.rb +23 -15
- data/lib/data_mapper.rb +5 -0
- data/lib/data_mapper/adapters/abstract_adapter.rb +9 -207
- data/lib/data_mapper/adapters/mysql_adapter.rb +132 -108
- data/lib/data_mapper/adapters/postgresql_adapter.rb +242 -0
- data/lib/data_mapper/adapters/sql/coersion.rb +74 -0
- data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +140 -0
- data/lib/data_mapper/adapters/sql/commands/conditions.rb +161 -0
- data/lib/data_mapper/adapters/sql/commands/delete_command.rb +113 -0
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +296 -0
- data/lib/data_mapper/adapters/sql/commands/save_command.rb +141 -0
- data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +33 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +91 -0
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +30 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +143 -0
- data/lib/data_mapper/adapters/sql/quoting.rb +38 -0
- data/lib/data_mapper/adapters/sql_adapter.rb +163 -0
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +155 -116
- data/lib/data_mapper/associations.rb +2 -0
- data/lib/data_mapper/associations/advanced_has_many_association.rb +55 -0
- data/lib/data_mapper/associations/belongs_to_association.rb +2 -2
- data/lib/data_mapper/associations/has_many_association.rb +3 -3
- data/lib/data_mapper/associations/has_one_association.rb +2 -2
- data/lib/data_mapper/base.rb +30 -11
- data/lib/data_mapper/callbacks.rb +4 -1
- data/lib/data_mapper/database.rb +8 -41
- data/lib/data_mapper/identity_map.rb +23 -3
- data/lib/data_mapper/session.rb +34 -186
- data/lib/data_mapper/{extensions → support}/active_record_impersonation.rb +16 -12
- data/lib/data_mapper/support/blank.rb +35 -0
- data/lib/data_mapper/support/connection_pool.rb +2 -1
- data/lib/data_mapper/support/string.rb +27 -0
- data/lib/data_mapper/support/struct.rb +26 -0
- data/lib/data_mapper/validations/unique_validator.rb +1 -3
- data/lib/data_mapper/validations/validation_helper.rb +1 -1
- data/performance.rb +24 -7
- data/profile_data_mapper.rb +24 -2
- data/rakefile.rb +2 -2
- data/spec/basic_finder.rb +2 -2
- data/spec/belongs_to.rb +1 -1
- data/spec/delete_command_spec.rb +9 -0
- data/spec/fixtures/zoos.yaml +4 -0
- data/spec/has_many.rb +1 -1
- data/spec/load_command_spec.rb +44 -0
- data/spec/models/zoo.rb +2 -0
- data/spec/save_command_spec.rb +13 -0
- data/spec/spec_helper.rb +10 -1
- data/spec/support/string_spec.rb +7 -0
- data/spec/validates_confirmation_of.rb +1 -1
- data/spec/validates_format_of.rb +1 -1
- data/spec/validates_length_of.rb +1 -1
- data/spec/validations.rb +1 -1
- metadata +23 -20
- data/lib/data_mapper/extensions/callback_helpers.rb +0 -35
- data/lib/data_mapper/loaded_set.rb +0 -45
- data/lib/data_mapper/mappings/column.rb +0 -78
- data/lib/data_mapper/mappings/schema.rb +0 -28
- data/lib/data_mapper/mappings/table.rb +0 -99
- data/lib/data_mapper/queries/conditions.rb +0 -141
- data/lib/data_mapper/queries/connection.rb +0 -34
- data/lib/data_mapper/queries/create_table_statement.rb +0 -38
- data/lib/data_mapper/queries/delete_statement.rb +0 -17
- data/lib/data_mapper/queries/drop_table_statement.rb +0 -17
- data/lib/data_mapper/queries/insert_statement.rb +0 -29
- data/lib/data_mapper/queries/reader.rb +0 -42
- data/lib/data_mapper/queries/result.rb +0 -19
- data/lib/data_mapper/queries/select_statement.rb +0 -103
- data/lib/data_mapper/queries/table_exists_statement.rb +0 -17
- data/lib/data_mapper/queries/truncate_table_statement.rb +0 -17
- data/lib/data_mapper/queries/update_statement.rb +0 -25
@@ -1,5 +1,5 @@
|
|
1
1
|
module DataMapper
|
2
|
-
module
|
2
|
+
module Support
|
3
3
|
|
4
4
|
module ActiveRecordImpersonation
|
5
5
|
|
@@ -12,7 +12,7 @@ module DataMapper
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def reload!
|
15
|
-
session.
|
15
|
+
session.first(self.class, key, :select => session.mappings[self.class].columns.map(&:name), :reload => true)
|
16
16
|
end
|
17
17
|
|
18
18
|
def reload
|
@@ -25,12 +25,16 @@ module DataMapper
|
|
25
25
|
|
26
26
|
module ClassMethods
|
27
27
|
|
28
|
+
def find_or_create(search_attributes, create_attributes = nil)
|
29
|
+
first(search_attributes) || create(search_attributes.merge(create_attributes))
|
30
|
+
end
|
31
|
+
|
28
32
|
def all(options = {}, &b)
|
29
|
-
|
33
|
+
database.all(self, options, &b)
|
30
34
|
end
|
31
35
|
|
32
|
-
def first(
|
33
|
-
|
36
|
+
def first(*args, &b)
|
37
|
+
database.first(self, *args, &b)
|
34
38
|
end
|
35
39
|
|
36
40
|
def delete_all
|
@@ -41,8 +45,12 @@ module DataMapper
|
|
41
45
|
database.truncate(self)
|
42
46
|
end
|
43
47
|
|
44
|
-
def find(
|
45
|
-
|
48
|
+
def find(type_or_id, options = {}, &b)
|
49
|
+
case type_or_id
|
50
|
+
when :first then first(options, &b)
|
51
|
+
when :all then all(options, &b)
|
52
|
+
else first(type_or_id, options, &b)
|
53
|
+
end
|
46
54
|
end
|
47
55
|
|
48
56
|
def find_by_sql(*args)
|
@@ -50,11 +58,7 @@ module DataMapper
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def [](id_or_hash)
|
53
|
-
|
54
|
-
find(:first, id_or_hash)
|
55
|
-
else
|
56
|
-
find(id_or_hash)
|
57
|
-
end
|
61
|
+
first(id_or_hash)
|
58
62
|
end
|
59
63
|
|
60
64
|
def create(attributes)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Object
|
2
|
+
def blank?
|
3
|
+
nil? || (respond_to?(:empty?) && empty?)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Fixnum
|
8
|
+
def blank?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NilClass
|
14
|
+
def blank?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TrueClass
|
20
|
+
def blank?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class FalseClass
|
26
|
+
def blank?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class String
|
32
|
+
def blank?
|
33
|
+
empty? || self =~ /^\s*$/
|
34
|
+
end
|
35
|
+
end
|
@@ -2,6 +2,11 @@ module DataMapper
|
|
2
2
|
module Support
|
3
3
|
module String
|
4
4
|
|
5
|
+
# I set the constant on the String itself to avoid inheritance chain lookups.
|
6
|
+
def self.included(base)
|
7
|
+
base.const_set('EMPTY', ''.freeze)
|
8
|
+
end
|
9
|
+
|
5
10
|
def ensure_starts_with(part)
|
6
11
|
[0,1] == part ? self : (part + self)
|
7
12
|
end
|
@@ -14,10 +19,32 @@ module DataMapper
|
|
14
19
|
ensure_starts_with(a).ensure_ends_with(b || a)
|
15
20
|
end
|
16
21
|
|
22
|
+
# Matches any whitespace (including newline) and replaces with a single space
|
23
|
+
# EXAMPLE:
|
24
|
+
# <<QUERY.compress_lines
|
25
|
+
# SELECT name
|
26
|
+
# FROM users
|
27
|
+
# QUERY
|
28
|
+
# => "SELECT name FROM users"
|
29
|
+
def compress_lines
|
30
|
+
gsub(/\s+/, ' ').strip
|
31
|
+
end
|
32
|
+
|
17
33
|
end # module String
|
18
34
|
end # module Support
|
19
35
|
end # module DataMapper
|
20
36
|
|
21
37
|
class String #:nodoc:
|
22
38
|
include DataMapper::Support::String
|
39
|
+
|
40
|
+
def self.fragile_underscore(camel_cased_word)
|
41
|
+
camel_cased_word.gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
42
|
+
end
|
43
|
+
|
44
|
+
@underscore_cache = Hash.new { |h,k| h[k.freeze] = fragile_underscore(k) }
|
45
|
+
|
46
|
+
def self.memoized_underscore(camel_cased_word)
|
47
|
+
@underscore_cache[camel_cased_word]
|
48
|
+
end
|
49
|
+
|
23
50
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Support
|
3
|
+
class Struct
|
4
|
+
|
5
|
+
def self.define(raw_fields)
|
6
|
+
|
7
|
+
normalized_fields = raw_fields.map { |field| Inflector.underscore(field).to_sym }
|
8
|
+
|
9
|
+
Class.new(self) do
|
10
|
+
define_method(:fields) do
|
11
|
+
normalized_fields
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(values)
|
17
|
+
@values = values
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(sym, *args)
|
21
|
+
@values[fields.index(sym)]
|
22
|
+
end
|
23
|
+
|
24
|
+
end # class Struct
|
25
|
+
end # module Support
|
26
|
+
end # module DataMapper
|
@@ -37,9 +37,7 @@ module DataMapper
|
|
37
37
|
|
38
38
|
finder_options.merge!({ target.session.mappings[target.class].key.name.not => target.key }) unless target.new_record?
|
39
39
|
|
40
|
-
|
41
|
-
# found with unless new_record?
|
42
|
-
target.session.find(target.class, :first, finder_options).nil?
|
40
|
+
target.session.first(target.class, finder_options).nil?
|
43
41
|
end
|
44
42
|
|
45
43
|
end
|
data/performance.rb
CHANGED
@@ -14,8 +14,7 @@ class ARPerson < ActiveRecord::Base
|
|
14
14
|
set_table_name 'people'
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
require 'data_mapper'
|
17
|
+
require 'lib/data_mapper'
|
19
18
|
|
20
19
|
log_path = File.dirname(__FILE__) + '/development.log'
|
21
20
|
|
@@ -24,10 +23,8 @@ FileUtils::rm log_path if File.exists?(log_path)
|
|
24
23
|
|
25
24
|
DataMapper::Database.setup do
|
26
25
|
adapter 'mysql'
|
27
|
-
username 'root'
|
28
26
|
database 'data_mapper_1'
|
29
|
-
|
30
|
-
log_level Logger::DEBUG
|
27
|
+
username 'root'
|
31
28
|
end
|
32
29
|
|
33
30
|
class DMAnimal < DataMapper::Base
|
@@ -76,6 +73,14 @@ Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
|
|
76
73
|
N.times { DMAnimal[1] }
|
77
74
|
end
|
78
75
|
|
76
|
+
x.report('ActiveRecord:all') do
|
77
|
+
N.times { ARAnimal.find(:all) }
|
78
|
+
end
|
79
|
+
|
80
|
+
x.report('DataMapper:all') do
|
81
|
+
N.times { DMAnimal.all }
|
82
|
+
end
|
83
|
+
|
79
84
|
x.report('ActiveRecord:conditions') do
|
80
85
|
N.times { ARZoo.find(:first, :conditions => ['name = ?', 'Galveston']) }
|
81
86
|
end
|
@@ -118,7 +123,7 @@ Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
|
|
118
123
|
|
119
124
|
x.report('ActiveRecord:update') do
|
120
125
|
N.times do
|
121
|
-
bob = ARAnimal.find(:first, :conditions => ["name = ?", '
|
126
|
+
bob = ARAnimal.find(:first, :conditions => ["name = ?", 'Elephant'])
|
122
127
|
bob.notes = 'Updated by ActiveRecord'
|
123
128
|
bob.save
|
124
129
|
end
|
@@ -126,7 +131,7 @@ Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
|
|
126
131
|
|
127
132
|
x.report('DataMapper:update') do
|
128
133
|
N.times do
|
129
|
-
bob = DMAnimal.first(:name => '
|
134
|
+
bob = DMAnimal.first(:name => 'Elephant')
|
130
135
|
bob.notes = 'Updated by DataMapper'
|
131
136
|
bob.save
|
132
137
|
end
|
@@ -153,4 +158,16 @@ Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
|
|
153
158
|
end
|
154
159
|
end
|
155
160
|
end
|
161
|
+
|
162
|
+
x.report('ActiveRecord:find_by_sql') do
|
163
|
+
N.times do
|
164
|
+
ARZoo.find_by_sql("SELECT * FROM zoos")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
x.report('DataMapper:find_by_sql') do
|
169
|
+
N.times do
|
170
|
+
database.query("SELECT * FROM zoos")
|
171
|
+
end
|
172
|
+
end
|
156
173
|
end
|
data/profile_data_mapper.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
#!/opt/local/bin/ruby
|
2
|
+
|
3
|
+
ENV['LOGGER'] = 'false'
|
4
|
+
|
1
5
|
require 'example'
|
2
6
|
require 'ruby-prof'
|
3
7
|
|
@@ -13,6 +17,24 @@ end
|
|
13
17
|
|
14
18
|
profile do
|
15
19
|
1000.times do
|
16
|
-
Zoo
|
20
|
+
Zoo.all
|
17
21
|
end
|
18
|
-
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# require 'benchmark'
|
25
|
+
#
|
26
|
+
# N = 100_000
|
27
|
+
#
|
28
|
+
# Benchmark::bmbm do |x|
|
29
|
+
# x.report do
|
30
|
+
# N.times do
|
31
|
+
# Inflector.underscore('DataMapper')
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# x.report do
|
36
|
+
# N.times do
|
37
|
+
# String::memoized_underscore('DataMapper')
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# end
|
data/rakefile.rb
CHANGED
@@ -11,7 +11,7 @@ task :default => 'test'
|
|
11
11
|
desc "Run specifications"
|
12
12
|
Spec::Rake::SpecTask.new('test') do |t|
|
13
13
|
t.spec_opts = [ '-rspec/spec_helper' ]
|
14
|
-
t.spec_files = FileList[ENV['FILES'] || 'spec
|
14
|
+
t.spec_files = FileList['spec/*.rb', (ENV['FILES'] || 'spec/**/*_spec.rb')]
|
15
15
|
end
|
16
16
|
|
17
17
|
desc "Run comparison with ActiveRecord"
|
@@ -24,7 +24,7 @@ task :profile do
|
|
24
24
|
load 'profile_data_mapper.rb'
|
25
25
|
end
|
26
26
|
|
27
|
-
PACKAGE_VERSION = '0.1.
|
27
|
+
PACKAGE_VERSION = '0.1.1'
|
28
28
|
|
29
29
|
PACKAGE_FILES = FileList[
|
30
30
|
'README',
|
data/spec/basic_finder.rb
CHANGED
@@ -3,14 +3,14 @@ context 'Finder' do
|
|
3
3
|
specify 'database-specific load should not fail' do
|
4
4
|
|
5
5
|
DataMapper::database do |db|
|
6
|
-
froggy = db.
|
6
|
+
froggy = db.first(Animal, :conditions => ['name = ?', 'Frog'])
|
7
7
|
froggy.name.should == 'Frog'
|
8
8
|
end
|
9
9
|
|
10
10
|
end
|
11
11
|
|
12
12
|
specify 'current-database load should not fail' do
|
13
|
-
froggy = DataMapper::database.
|
13
|
+
froggy = DataMapper::database.first(Animal).name.should == 'Frog'
|
14
14
|
end
|
15
15
|
|
16
16
|
specify 'load through ActiveRecord impersonation should not fail' do
|
data/spec/belongs_to.rb
CHANGED
data/spec/fixtures/zoos.yaml
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
- name: Dallas
|
2
|
+
notes: Keep Dallas Pretentious?
|
2
3
|
- name: San Diego
|
3
4
|
- name: Miami
|
4
5
|
- name: Ft. Lauderdale
|
5
6
|
- name: Ft. Worth
|
6
7
|
- name: New Orleans
|
7
8
|
- name: San Antonio
|
9
|
+
notes: The most sprawling city I've ever seen. It's insane.
|
8
10
|
- name: Galveston
|
11
|
+
notes: A friendly place. It's like Hotel California for Houston's homeless though. (No way out without a car.)
|
9
12
|
- name: Austin
|
13
|
+
notes: People in Austin like to drive around with "Save Mother Earth" stickers on their SUVs and proclaim "Keep Austin Weird" while sipping on Starbucks.
|
10
14
|
- name: Brownsville
|
11
15
|
- name: Los Angeles
|
12
16
|
- name: Phillidelphia
|
data/spec/has_many.rb
CHANGED
@@ -18,7 +18,7 @@ describe DataMapper::Associations::HasManyAssociation do
|
|
18
18
|
it 'should lazily-load the association when Enumerable methods are called' do
|
19
19
|
database do |db|
|
20
20
|
@san_diego.exhibits.size.should == 2
|
21
|
-
@san_diego.exhibits.should include(@san_diego.session.
|
21
|
+
@san_diego.exhibits.should include(@san_diego.session.first(Exhibit, :name => 'Monkey Mayhem'))
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
2
|
+
|
3
|
+
before(:all) do
|
4
|
+
fixtures(:zoos)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should return a Struct for custom queries" do
|
8
|
+
results = database.query("SELECT * FROM zoos WHERE name = ?", 'Galveston')
|
9
|
+
zoo = results.first
|
10
|
+
zoo.class.superclass.should == DataMapper::Support::Struct
|
11
|
+
zoo.name.should == "Galveston"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe DataMapper::Adapters::Sql::Commands::AdvancedLoadCommand do
|
17
|
+
|
18
|
+
def loader_for(klass, options = {})
|
19
|
+
session = database
|
20
|
+
DataMapper::Adapters::Sql::Commands::AdvancedLoadCommand.new(session.adapter, session, klass, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a simple select statement for a given class" do
|
24
|
+
loader_for(Zoo).to_sql.should == 'SELECT `id`, `name` FROM `zoos`'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should include only the columns specified in the statement" do
|
28
|
+
loader_for(Zoo, :select => [:name]).to_sql.should == 'SELECT `name` FROM `zoos`'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should optionally include lazy-loaded columns in the statement" do
|
32
|
+
loader_for(Zoo, :include => :notes).to_sql.should == 'SELECT `id`, `name`, `notes` FROM `zoos`'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should join associations in the statement" do
|
36
|
+
loader_for(Zoo, :include => :exhibits2).to_sql.should == <<-EOS.compress_lines
|
37
|
+
SELECT `zoos`.`id`, `zoos`.`name`,
|
38
|
+
`exhibits`.`id`, `exhibits`.`name`, `exhibits`.`zoo_id`
|
39
|
+
FROM `zoos`
|
40
|
+
JOIN `exhibits` ON `exhibits`.`cow_id` = `zoos`.`id`
|
41
|
+
EOS
|
42
|
+
end
|
43
|
+
|
44
|
+
end if ENV['ADAPTER'].nil? || ENV['ADAPTER'] == 'mysql'
|