datamapper 0.1.1 → 0.2.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.
Files changed (131) hide show
  1. data/CHANGELOG +65 -0
  2. data/README +193 -1
  3. data/do_performance.rb +153 -0
  4. data/environment.rb +45 -0
  5. data/example.rb +119 -22
  6. data/lib/data_mapper.rb +36 -16
  7. data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
  8. data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
  9. data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
  10. data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
  11. data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
  12. data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
  14. data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
  15. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
  16. data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
  17. data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
  18. data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
  19. data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
  20. data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
  21. data/lib/data_mapper/associations.rb +21 -7
  22. data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
  23. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
  24. data/lib/data_mapper/associations/has_many_association.rb +96 -78
  25. data/lib/data_mapper/associations/has_n_association.rb +64 -0
  26. data/lib/data_mapper/associations/has_one_association.rb +49 -79
  27. data/lib/data_mapper/associations/reference.rb +47 -0
  28. data/lib/data_mapper/base.rb +216 -50
  29. data/lib/data_mapper/callbacks.rb +71 -24
  30. data/lib/data_mapper/{session.rb → context.rb} +20 -8
  31. data/lib/data_mapper/database.rb +176 -45
  32. data/lib/data_mapper/embedded_value.rb +65 -0
  33. data/lib/data_mapper/identity_map.rb +12 -4
  34. data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
  35. data/lib/data_mapper/support/enumerable.rb +8 -0
  36. data/lib/data_mapper/support/serialization.rb +13 -0
  37. data/lib/data_mapper/support/string.rb +1 -12
  38. data/lib/data_mapper/support/symbol.rb +3 -0
  39. data/lib/data_mapper/validations/unique_validator.rb +1 -2
  40. data/lib/data_mapper/validations/validation_helper.rb +18 -1
  41. data/performance.rb +109 -34
  42. data/plugins/can_has_sphinx/LICENSE +23 -0
  43. data/plugins/can_has_sphinx/README +4 -0
  44. data/plugins/can_has_sphinx/REVISION +1 -0
  45. data/plugins/can_has_sphinx/Rakefile +22 -0
  46. data/plugins/can_has_sphinx/init.rb +1 -0
  47. data/plugins/can_has_sphinx/install.rb +1 -0
  48. data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
  49. data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
  50. data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
  51. data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
  52. data/plugins/dataobjects/REVISION +1 -0
  53. data/plugins/dataobjects/Rakefile +7 -0
  54. data/plugins/dataobjects/do.rb +246 -0
  55. data/plugins/dataobjects/do_mysql.rb +179 -0
  56. data/plugins/dataobjects/do_postgres.rb +181 -0
  57. data/plugins/dataobjects/do_sqlite3.rb +153 -0
  58. data/plugins/dataobjects/spec/do_spec.rb +150 -0
  59. data/plugins/dataobjects/spec/spec_helper.rb +81 -0
  60. data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
  61. data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
  62. data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
  63. data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
  64. data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
  65. data/plugins/dataobjects/swig_postgres/Makefile +146 -0
  66. data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
  67. data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
  68. data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
  69. data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
  70. data/plugins/dataobjects/swig_sqlite/db +0 -0
  71. data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
  72. data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
  73. data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
  74. data/rakefile.rb +45 -23
  75. data/spec/acts_as_tree_spec.rb +39 -0
  76. data/spec/associations_spec.rb +220 -0
  77. data/spec/attributes_spec.rb +15 -0
  78. data/spec/base_spec.rb +44 -0
  79. data/spec/callbacks_spec.rb +45 -0
  80. data/spec/can_has_sphinx.rb +6 -0
  81. data/spec/coersion_spec.rb +34 -0
  82. data/spec/conditions_spec.rb +49 -0
  83. data/spec/conversions_to_yaml_spec.rb +17 -0
  84. data/spec/count_command_spec.rb +11 -0
  85. data/spec/delete_command_spec.rb +1 -1
  86. data/spec/embedded_value_spec.rb +23 -0
  87. data/spec/fixtures/animals_exhibits.yaml +2 -0
  88. data/spec/fixtures/people.yaml +18 -1
  89. data/spec/{legacy.rb → legacy_spec.rb} +3 -3
  90. data/spec/load_command_spec.rb +157 -20
  91. data/spec/magic_columns_spec.rb +9 -0
  92. data/spec/mock_adapter.rb +20 -0
  93. data/spec/models/animal.rb +1 -1
  94. data/spec/models/animals_exhibit.rb +6 -0
  95. data/spec/models/exhibit.rb +2 -0
  96. data/spec/models/person.rb +26 -1
  97. data/spec/models/project.rb +19 -0
  98. data/spec/models/sales_person.rb +1 -0
  99. data/spec/models/section.rb +6 -0
  100. data/spec/models/zoo.rb +3 -1
  101. data/spec/query_spec.rb +9 -0
  102. data/spec/save_command_spec.rb +65 -1
  103. data/spec/schema_spec.rb +89 -0
  104. data/spec/single_table_inheritance_spec.rb +27 -0
  105. data/spec/spec_helper.rb +9 -55
  106. data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
  107. data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
  108. data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
  109. data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
  110. data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
  111. data/spec/{validations.rb → validations_spec.rb} +24 -6
  112. data/tasks/drivers.rb +20 -0
  113. data/tasks/fixtures.rb +42 -0
  114. metadata +181 -42
  115. data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
  116. data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
  117. data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
  118. data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
  119. data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
  120. data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
  121. data/lib/data_mapper/support/blank_slate.rb +0 -3
  122. data/lib/data_mapper/support/proc.rb +0 -69
  123. data/lib/data_mapper/support/struct.rb +0 -26
  124. data/lib/data_mapper/unit_of_work.rb +0 -38
  125. data/spec/basic_finder.rb +0 -67
  126. data/spec/belongs_to.rb +0 -47
  127. data/spec/has_and_belongs_to_many.rb +0 -25
  128. data/spec/has_many.rb +0 -34
  129. data/spec/new_record.rb +0 -24
  130. data/spec/sub_select.rb +0 -16
  131. 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,6 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+ describe DataMapper::Plugins::CanHasSphinx do
5
+
6
+ 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
@@ -0,0 +1,11 @@
1
+ describe DataMapper::Adapters::AbstractAdapter do
2
+
3
+ before(:all) do
4
+ fixtures(:zoos)
5
+ end
6
+
7
+ it "should return a count of the selected table" do
8
+ Zoo.count.should be_a_kind_of(Integer)
9
+ Zoo.count.should == Zoo.all.size
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
- describe DataMapper::Adapters::Sql::Commands::DeleteCommand do
1
+ describe "Delete Command" do
2
2
 
3
3
  it "should drop and create the table" do
4
4
  database.schema[Zoo].drop!.should == true
@@ -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
@@ -0,0 +1,2 @@
1
+ - animal_id: 1
2
+ exhibit_id: 5
@@ -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
- context 'Legacy Database' do
1
+ describe 'Legacy mappings' do
2
2
 
3
- specify('should allow models to map with custom attribute names') do
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
- specify('should allow custom foreign-key mappings') do
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']
@@ -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 == DataMapper::Support::Struct
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).to_sql.should == 'SELECT `id`, `name` FROM `zoos`'
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]).to_sql.should == 'SELECT `name` FROM `zoos`'
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).to_sql.should == 'SELECT `id`, `name`, `notes` FROM `zoos`'
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 => :exhibits2).to_sql.should == <<-EOS.compress_lines
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`.`cow_id` = `zoos`.`id`
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
- end if ENV['ADAPTER'].nil? || ENV['ADAPTER'] == 'mysql'
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