datamapper 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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