datamapper 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +65 -0
- data/README +193 -1
- data/do_performance.rb +153 -0
- data/environment.rb +45 -0
- data/example.rb +119 -22
- data/lib/data_mapper.rb +36 -16
- data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
- data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
- data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
- data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
- data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
- data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
- data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
- data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
- data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
- data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
- data/lib/data_mapper/associations.rb +21 -7
- data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
- data/lib/data_mapper/associations/has_many_association.rb +96 -78
- data/lib/data_mapper/associations/has_n_association.rb +64 -0
- data/lib/data_mapper/associations/has_one_association.rb +49 -79
- data/lib/data_mapper/associations/reference.rb +47 -0
- data/lib/data_mapper/base.rb +216 -50
- data/lib/data_mapper/callbacks.rb +71 -24
- data/lib/data_mapper/{session.rb → context.rb} +20 -8
- data/lib/data_mapper/database.rb +176 -45
- data/lib/data_mapper/embedded_value.rb +65 -0
- data/lib/data_mapper/identity_map.rb +12 -4
- data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
- data/lib/data_mapper/support/enumerable.rb +8 -0
- data/lib/data_mapper/support/serialization.rb +13 -0
- data/lib/data_mapper/support/string.rb +1 -12
- data/lib/data_mapper/support/symbol.rb +3 -0
- data/lib/data_mapper/validations/unique_validator.rb +1 -2
- data/lib/data_mapper/validations/validation_helper.rb +18 -1
- data/performance.rb +109 -34
- data/plugins/can_has_sphinx/LICENSE +23 -0
- data/plugins/can_has_sphinx/README +4 -0
- data/plugins/can_has_sphinx/REVISION +1 -0
- data/plugins/can_has_sphinx/Rakefile +22 -0
- data/plugins/can_has_sphinx/init.rb +1 -0
- data/plugins/can_has_sphinx/install.rb +1 -0
- data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
- data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
- data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
- data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
- data/plugins/dataobjects/REVISION +1 -0
- data/plugins/dataobjects/Rakefile +7 -0
- data/plugins/dataobjects/do.rb +246 -0
- data/plugins/dataobjects/do_mysql.rb +179 -0
- data/plugins/dataobjects/do_postgres.rb +181 -0
- data/plugins/dataobjects/do_sqlite3.rb +153 -0
- data/plugins/dataobjects/spec/do_spec.rb +150 -0
- data/plugins/dataobjects/spec/spec_helper.rb +81 -0
- data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
- data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
- data/plugins/dataobjects/swig_postgres/Makefile +146 -0
- data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
- data/plugins/dataobjects/swig_sqlite/db +0 -0
- data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
- data/rakefile.rb +45 -23
- data/spec/acts_as_tree_spec.rb +39 -0
- data/spec/associations_spec.rb +220 -0
- data/spec/attributes_spec.rb +15 -0
- data/spec/base_spec.rb +44 -0
- data/spec/callbacks_spec.rb +45 -0
- data/spec/can_has_sphinx.rb +6 -0
- data/spec/coersion_spec.rb +34 -0
- data/spec/conditions_spec.rb +49 -0
- data/spec/conversions_to_yaml_spec.rb +17 -0
- data/spec/count_command_spec.rb +11 -0
- data/spec/delete_command_spec.rb +1 -1
- data/spec/embedded_value_spec.rb +23 -0
- data/spec/fixtures/animals_exhibits.yaml +2 -0
- data/spec/fixtures/people.yaml +18 -1
- data/spec/{legacy.rb → legacy_spec.rb} +3 -3
- data/spec/load_command_spec.rb +157 -20
- data/spec/magic_columns_spec.rb +9 -0
- data/spec/mock_adapter.rb +20 -0
- data/spec/models/animal.rb +1 -1
- data/spec/models/animals_exhibit.rb +6 -0
- data/spec/models/exhibit.rb +2 -0
- data/spec/models/person.rb +26 -1
- data/spec/models/project.rb +19 -0
- data/spec/models/sales_person.rb +1 -0
- data/spec/models/section.rb +6 -0
- data/spec/models/zoo.rb +3 -1
- data/spec/query_spec.rb +9 -0
- data/spec/save_command_spec.rb +65 -1
- data/spec/schema_spec.rb +89 -0
- data/spec/single_table_inheritance_spec.rb +27 -0
- data/spec/spec_helper.rb +9 -55
- data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
- data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
- data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
- data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
- data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
- data/spec/{validations.rb → validations_spec.rb} +24 -6
- data/tasks/drivers.rb +20 -0
- data/tasks/fixtures.rb +42 -0
- metadata +181 -42
- data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
- data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
- data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
- data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
- data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
- data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
- data/lib/data_mapper/support/blank_slate.rb +0 -3
- data/lib/data_mapper/support/proc.rb +0 -69
- data/lib/data_mapper/support/struct.rb +0 -26
- data/lib/data_mapper/unit_of_work.rb +0 -38
- data/spec/basic_finder.rb +0 -67
- data/spec/belongs_to.rb +0 -47
- data/spec/has_and_belongs_to_many.rb +0 -25
- data/spec/has_many.rb +0 -34
- data/spec/new_record.rb +0 -24
- data/spec/sub_select.rb +0 -16
- data/spec/support/string_spec.rb +0 -7
@@ -0,0 +1,15 @@
|
|
1
|
+
describe DataMapper::Base do
|
2
|
+
|
3
|
+
it 'should allow mass-assignment of attributes' do
|
4
|
+
zoo = Zoo.new(:name => 'MassAssignment', :notes => 'This is a test.')
|
5
|
+
|
6
|
+
zoo.name.should eql('MassAssignment')
|
7
|
+
zoo.notes.should eql('This is a test.')
|
8
|
+
|
9
|
+
zoo.attributes = { :name => 'ThroughAttributesEqual', :notes => 'This is another test.' }
|
10
|
+
|
11
|
+
zoo.name.should eql('ThroughAttributesEqual')
|
12
|
+
zoo.notes.should eql('This is another test.')
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
describe DataMapper::Base do
|
2
|
+
|
3
|
+
it "attributes method should load all lazy-loaded values" do
|
4
|
+
Animal.first(:name => 'Cup').attributes[:notes].should == 'I am a Cup!'
|
5
|
+
end
|
6
|
+
|
7
|
+
it "mass assignment should call methods" do
|
8
|
+
class Animal
|
9
|
+
attr_reader :test
|
10
|
+
def test=(value)
|
11
|
+
@test = value + '!'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
a = Animal.new(:test => 'testing')
|
16
|
+
a.test.should == 'testing!'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'A new record' do
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
@bob = Person.new(:name => 'Bob', :age => 30, :occupation => 'Sales')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should be dirty' do
|
28
|
+
@bob.dirty?.should == true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'set attributes should be dirty' do
|
32
|
+
attributes = @bob.attributes.dup.reject { |k,v| k == :id }
|
33
|
+
@bob.dirty_attributes.should == { :name => 'Bob', :age => 30, :occupation => 'Sales' }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should be marked as new' do
|
37
|
+
@bob.new_record?.should == true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should have a nil id' do
|
41
|
+
@bob.id.should == nil
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
describe DataMapper::Callbacks do
|
2
|
+
|
3
|
+
it "should allow for a callback to be set, then called" do
|
4
|
+
|
5
|
+
example = Class.new do
|
6
|
+
include DataMapper::CallbacksHelper
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
before_save 'name = "bob"'
|
15
|
+
before_validation { |instance| instance.name = 'Barry White Returns!' }
|
16
|
+
|
17
|
+
end.new('Barry White')
|
18
|
+
|
19
|
+
example.class::callbacks.execute(:before_save, example)
|
20
|
+
example.name.should == 'Barry White'
|
21
|
+
|
22
|
+
example.class::callbacks.execute(:before_validation, example)
|
23
|
+
example.name.should == 'Barry White Returns!'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should allow method delegation by passing symbols to the callback definitions" do
|
27
|
+
|
28
|
+
example = Class.new do
|
29
|
+
include DataMapper::CallbacksHelper
|
30
|
+
|
31
|
+
attr_accessor :name
|
32
|
+
|
33
|
+
before_save :test
|
34
|
+
|
35
|
+
def test
|
36
|
+
@name = 'Walter'
|
37
|
+
end
|
38
|
+
end.new
|
39
|
+
|
40
|
+
example.class::callbacks.execute(:before_save, example)
|
41
|
+
example.name.should == 'Walter'
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
describe DataMapper::Adapters::Sql::Coersion do
|
2
|
+
|
3
|
+
before(:all) do
|
4
|
+
@coersive = Class.new do
|
5
|
+
include DataMapper::Adapters::Sql::Coersion
|
6
|
+
end.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should cast to a BigDecimal' do
|
10
|
+
target = BigDecimal.new('7.2')
|
11
|
+
@coersive.type_cast_decimal('7.2').should == target
|
12
|
+
@coersive.type_cast_decimal(7.2).should == target
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should store and load a date' do
|
16
|
+
dob = Date::today
|
17
|
+
bob = Person.create(:name => 'DateCoersionTest', :date_of_birth => dob)
|
18
|
+
|
19
|
+
bob2 = Person[:name => 'DateCoersionTest']
|
20
|
+
|
21
|
+
bob.date_of_birth.should eql(dob)
|
22
|
+
bob.date_of_birth.should eql(bob2.date_of_birth)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should cast to a Date' do
|
26
|
+
target = Date.civil(2001, 1, 1)
|
27
|
+
|
28
|
+
@coersive.type_cast_date('2001-1-1').should eql(target)
|
29
|
+
@coersive.type_cast_date(target.dup).should eql(target)
|
30
|
+
@coersive.type_cast_date(DateTime::parse('2001-1-1')).should eql(target)
|
31
|
+
@coersive.type_cast_date(Time::parse('2001-1-1')).should eql(target)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
describe DataMapper::Adapters::Sql::Commands::Conditions do
|
2
|
+
|
3
|
+
def conditions_for(klass, options = {})
|
4
|
+
session = database(:mock)
|
5
|
+
DataMapper::Adapters::Sql::Commands::LoadCommand.new(
|
6
|
+
session.adapter, session, klass, options
|
7
|
+
).conditions
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'empty? should be false if conditions are present' do
|
11
|
+
conditions_for(Zoo, :name => 'Galveston').empty?.should == false
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should map implicit option names to field names' do
|
15
|
+
conditions_for(Zoo, :name => 'Galveston').to_parameterized_sql.should == ["(`name` = ?)", 'Galveston']
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should qualify with table name when using a join' do
|
19
|
+
conditions = conditions_for(Zoo, :name => 'Galveston', :include => :exhibits)
|
20
|
+
conditions.to_parameterized_sql.should == ["(`zoos`.`name` = ?)", 'Galveston']
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should use Symbol::Operator to determine operator' do
|
24
|
+
conditions_for(Person, :age.gt => 28).to_parameterized_sql.should == ["(`age` > ?)", 28]
|
25
|
+
conditions_for(Person, :age.gte => 28).to_parameterized_sql.should == ["(`age` >= ?)", 28]
|
26
|
+
|
27
|
+
conditions_for(Person, :age.lt => 28).to_parameterized_sql.should == ["(`age` < ?)", 28]
|
28
|
+
conditions_for(Person, :age.lte => 28).to_parameterized_sql.should == ["(`age` <= ?)", 28]
|
29
|
+
|
30
|
+
conditions_for(Person, :age.not => 28).to_parameterized_sql.should == ["(`age` <> ?)", 28]
|
31
|
+
conditions_for(Person, :age.eql => 28).to_parameterized_sql.should == ["(`age` = ?)", 28]
|
32
|
+
|
33
|
+
conditions_for(Person, :name.like => 'S%').to_parameterized_sql.should == ["(`name` LIKE ?)", 'S%']
|
34
|
+
|
35
|
+
conditions_for(Person, :age.in => [ 28, 29 ]).to_parameterized_sql.should == ["(`age` IN ?)", [ 28, 29 ]]
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should use an IN clause for an Array' do
|
39
|
+
conditions = conditions_for(Person, :age => [ 28, 29 ])
|
40
|
+
conditions.to_parameterized_sql.should == ["(`age` IN ?)", [ 28, 29 ]]
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should use "not" for not-equal operations' do
|
44
|
+
conditions_for(Person, :name.not => 'Bob').to_parameterized_sql.should == ["(`name` <> ?)", 'Bob']
|
45
|
+
conditions_for(Person, :name.not => nil).to_parameterized_sql.should == ["(`name` IS NOT ?)", nil]
|
46
|
+
conditions_for(Person, :name.not => ['Sam', 'Bob']).to_parameterized_sql.should == ["(`name` NOT IN ?)", ['Sam', 'Bob']]
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe "Conversion to YAML" do
|
2
|
+
# check each model to see if the conversion *.to_yaml works.
|
3
|
+
Dir[File.dirname(__FILE__) + "/fixtures/*.yaml"].each do |path|
|
4
|
+
|
5
|
+
name = File::basename(path).sub(/\.yaml$/, '')
|
6
|
+
klass = Kernel::const_get(Inflector.classify(Inflector.singularize(name)))
|
7
|
+
|
8
|
+
it "the first #{klass} converted to YAML should match the YAML in the fixture" do
|
9
|
+
|
10
|
+
YAML::load(klass.first.to_yaml).to_a.reject do |pair|
|
11
|
+
pair.first == "updated_at" || pair.first == "id"
|
12
|
+
end.sort.should == YAML::load_file("./spec/fixtures/#{name}.yaml")[0].to_a.sort
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
data/spec/delete_command_spec.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
describe DataMapper::EmbeddedValue do
|
2
|
+
|
3
|
+
before(:all) do
|
4
|
+
@bob = Person[:name => 'Bob']
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'should proxy getting values for you' do
|
8
|
+
@bob.address.street.should == '123 Happy Ln.'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return a sub-class of the containing class' do
|
12
|
+
@bob.address.class.should be(Person::Address)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should allow definition of instance methods' do
|
16
|
+
@bob.address.city_state_zip_code.should == 'Dallas, TX 75000'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should allow you to use your own classes as well as long as they inherit from EmbeddedValue' do
|
20
|
+
@bob.location.to_s.should == 'Dallas, TX'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/fixtures/people.yaml
CHANGED
@@ -1,15 +1,32 @@
|
|
1
1
|
- name: Sam
|
2
2
|
age: 29
|
3
3
|
occupation: Programmer
|
4
|
+
type: Person
|
5
|
+
street: 1337 Duck Way
|
6
|
+
city: Galveston
|
7
|
+
state: TX
|
8
|
+
zip_code: "75000"
|
9
|
+
notes:
|
10
|
+
date_of_birth: 2007-10-24T22:48:51-05:00
|
4
11
|
- name: Amy
|
5
12
|
age: 28
|
6
13
|
occupation: Business Analyst Manager
|
14
|
+
type: Person
|
7
15
|
- name: Scott
|
8
16
|
age: 25
|
9
17
|
occupation: Programmer
|
18
|
+
type: SalesPerson
|
19
|
+
commission: 172
|
10
20
|
- name: Josh
|
11
21
|
age: 23
|
12
22
|
occupation: Supervisor
|
23
|
+
type:
|
13
24
|
- name: Bob
|
14
25
|
age: 29
|
15
|
-
occupation: Peon
|
26
|
+
occupation: Peon
|
27
|
+
street: 123 Happy Ln.
|
28
|
+
city: Dallas
|
29
|
+
state: TX
|
30
|
+
zip_code: 75000
|
31
|
+
type: SalesPerson
|
32
|
+
commission: 40
|
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
describe 'Legacy mappings' do
|
2
2
|
|
3
|
-
|
3
|
+
it('should allow models to map with custom attribute names') do
|
4
4
|
Fruit.first.name.should == 'Kiwi'
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
it('should allow custom foreign-key mappings') do
|
8
8
|
database do
|
9
9
|
Fruit[:name => 'Watermelon'].devourer_of_souls.should == Animal[:name => 'Cup']
|
10
10
|
Animal[:name => 'Cup'].favourite_fruit.should == Fruit[:name => 'Watermelon']
|
data/spec/load_command_spec.rb
CHANGED
@@ -4,41 +4,178 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
|
4
4
|
fixtures(:zoos)
|
5
5
|
end
|
6
6
|
|
7
|
+
def loader_for(klass, options = {})
|
8
|
+
session = database(:mock)
|
9
|
+
DataMapper::Adapters::Sql::Commands::LoadCommand.new(session.adapter, session, klass, options)
|
10
|
+
end
|
11
|
+
|
7
12
|
it "should return a Struct for custom queries" do
|
8
13
|
results = database.query("SELECT * FROM zoos WHERE name = ?", 'Galveston')
|
9
14
|
zoo = results.first
|
10
|
-
zoo.class.superclass.should ==
|
15
|
+
zoo.class.superclass.should == Struct
|
11
16
|
zoo.name.should == "Galveston"
|
12
17
|
end
|
13
|
-
|
14
|
-
end
|
15
18
|
|
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
19
|
it "should return a simple select statement for a given class" do
|
24
|
-
loader_for(Zoo).
|
20
|
+
loader_for(Zoo).to_parameterized_sql.first.should == 'SELECT `id`, `name`, `updated_at` FROM `zoos`'
|
25
21
|
end
|
26
|
-
|
22
|
+
|
27
23
|
it "should include only the columns specified in the statement" do
|
28
|
-
loader_for(Zoo, :select => [:name]).
|
24
|
+
loader_for(Zoo, :select => [:name]).to_parameterized_sql.first.should == 'SELECT `name` FROM `zoos`'
|
29
25
|
end
|
30
|
-
|
26
|
+
|
31
27
|
it "should optionally include lazy-loaded columns in the statement" do
|
32
|
-
loader_for(Zoo, :include => :notes).
|
28
|
+
loader_for(Zoo, :include => :notes).to_parameterized_sql.first.should == 'SELECT `id`, `name`, `updated_at`, `notes` FROM `zoos`'
|
33
29
|
end
|
34
|
-
|
30
|
+
|
35
31
|
it "should join associations in the statement" do
|
36
|
-
loader_for(Zoo, :include => :
|
37
|
-
SELECT `zoos`.`id`, `zoos`.`name`,
|
32
|
+
loader_for(Zoo, :include => :exhibits).to_parameterized_sql.first.should == <<-EOS.compress_lines
|
33
|
+
SELECT `zoos`.`id`, `zoos`.`name`, `zoos`.`updated_at`,
|
38
34
|
`exhibits`.`id`, `exhibits`.`name`, `exhibits`.`zoo_id`
|
39
35
|
FROM `zoos`
|
40
|
-
JOIN `exhibits` ON `exhibits`.`
|
36
|
+
JOIN `exhibits` ON `exhibits`.`zoo_id` = `zoos`.`id`
|
41
37
|
EOS
|
42
38
|
end
|
39
|
+
|
40
|
+
it "should join has and belongs to many associtions in the statement" do
|
41
|
+
loader_for(Animal, :include => :exhibits).to_parameterized_sql.first.should == <<-EOS.compress_lines
|
42
|
+
SELECT `animals`.`id`, `animals`.`name`,
|
43
|
+
`exhibits`.`id`, `exhibits`.`name`, `exhibits`.`zoo_id`,
|
44
|
+
`animals_exhibits`.`animal_id`, `animals_exhibits`.`exhibit_id`
|
45
|
+
FROM `animals`
|
46
|
+
JOIN `animals_exhibits` ON `animals_exhibits`.`animal_id` = `animals`.`id`
|
47
|
+
JOIN `exhibits` ON `exhibits`.`id` = `animals_exhibits`.`exhibit_id`
|
48
|
+
EOS
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should shallow-join unmapped tables for has-and-belongs-to-many in the statement" do
|
52
|
+
loader_for(Animal, :shallow_include => :exhibits).to_parameterized_sql.first.should == <<-EOS.compress_lines
|
53
|
+
SELECT `animals`.`id`, `animals`.`name`,
|
54
|
+
`animals_exhibits`.`animal_id`, `animals_exhibits`.`exhibit_id`
|
55
|
+
FROM `animals`
|
56
|
+
JOIN `animals_exhibits` ON `animals_exhibits`.`animal_id` = `animals`.`id`
|
57
|
+
EOS
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should allow multiple implicit conditions" do
|
61
|
+
expected_sql = <<-EOS.compress_lines
|
62
|
+
SELECT `id`, `name`, `age`, `occupation`,
|
63
|
+
`type`, `street`, `city`, `state`, `zip_code`
|
64
|
+
FROM `people`
|
65
|
+
WHERE (`name` = ?) AND (`age` = ?)
|
66
|
+
EOS
|
67
|
+
|
68
|
+
# NOTE: I'm actually not sure how to test this since the order of the parameters isn't gauranteed.
|
69
|
+
# Maybe an ugly OrderedHash passed as the options...
|
70
|
+
# loader_for(Person, :name => 'Sam', :age => 29).to_parameterized_sql.should == [expected_sql, 'Sam', 29]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should allow block-interception during load" do
|
74
|
+
result = false
|
75
|
+
Person.first(:intercept_load => lambda { result = true })
|
76
|
+
result.should == true
|
77
|
+
end
|
43
78
|
|
44
|
-
|
79
|
+
it 'database-specific load should not fail' do
|
80
|
+
|
81
|
+
DataMapper::database do |db|
|
82
|
+
froggy = db.first(Animal, :conditions => ['name = ?', 'Frog'])
|
83
|
+
froggy.name.should == 'Frog'
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'current-database load should not fail' do
|
89
|
+
froggy = DataMapper::database.first(Animal).name.should == 'Frog'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'load through ActiveRecord impersonation should not fail' do
|
93
|
+
Animal.find(:all).size.should == 16
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'load through Og impersonation should not fail' do
|
97
|
+
Animal.all.size.should == 16
|
98
|
+
end
|
99
|
+
|
100
|
+
it ':conditions option should accept a hash' do
|
101
|
+
Animal.all(:conditions => { :name => 'Frog' }).size.should == 1
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'non-standard options should be considered part of the conditions' do
|
105
|
+
database.log.debug { 'non-standard options should be considered part of the conditions' }
|
106
|
+
zebra = Animal.first(:name => 'Zebra')
|
107
|
+
zebra.name.should == 'Zebra'
|
108
|
+
|
109
|
+
elephant = Animal[:name => 'Elephant']
|
110
|
+
elephant.name.should == 'Elephant'
|
111
|
+
|
112
|
+
aged = Person.all(:age => 29)
|
113
|
+
aged.size.should == 2
|
114
|
+
aged.first.name.should == 'Sam'
|
115
|
+
aged.last.name.should == 'Bob'
|
116
|
+
|
117
|
+
fixtures(:animals)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should not find deleted objects' do
|
121
|
+
database do
|
122
|
+
wally = Animal[:name => 'Whale']
|
123
|
+
wally.new_record?.should == false
|
124
|
+
wally.destroy!.should == true
|
125
|
+
|
126
|
+
wallys_evil_twin = Animal[:name => 'Whale']
|
127
|
+
wallys_evil_twin.should == nil
|
128
|
+
|
129
|
+
wally.new_record?.should == true
|
130
|
+
wally.save
|
131
|
+
wally.new_record?.should == false
|
132
|
+
|
133
|
+
Animal[:name => 'Whale'].should == wally
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'lazy-loads should issue for whole sets' do
|
138
|
+
people = Person.all
|
139
|
+
|
140
|
+
people.each do |person|
|
141
|
+
person.notes
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should only query once" do
|
146
|
+
database do
|
147
|
+
zoo = Zoo.first
|
148
|
+
same_zoo = Zoo[zoo.id]
|
149
|
+
|
150
|
+
zoo.should == same_zoo
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should return a single object" do
|
155
|
+
Zoo.first.should be_a_kind_of(Zoo)
|
156
|
+
Zoo[1].should be_a_kind_of(Zoo)
|
157
|
+
Zoo.find(1).should be_a_kind_of(Zoo)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should be able to search on UTF-8 strings" do
|
161
|
+
Zoo.create(:name => 'Danish Vowels: Smøøt!')
|
162
|
+
Zoo.first(:name.like => '%Smøøt%').should be_a_kind_of(Zoo)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
=begin
|
167
|
+
context 'Sub-selection' do
|
168
|
+
|
169
|
+
specify 'should return a Cup' do
|
170
|
+
Animal[:id.select => { :name => 'cup' }].name.should == 'Cup'
|
171
|
+
end
|
172
|
+
|
173
|
+
specify 'should return all exhibits for Galveston zoo' do
|
174
|
+
Exhibit.all(:zoo_id.select(Zoo) => { :name => 'Galveston' }).size.should == 3
|
175
|
+
end
|
176
|
+
|
177
|
+
specify 'should allow a sub-select in the select-list' do
|
178
|
+
Animal[:select => [ :id.count ]]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
=end
|