datamapper 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/CHANGELOG +5 -1
  2. data/FAQ +96 -0
  3. data/QUICKLINKS +12 -0
  4. data/README +57 -155
  5. data/environment.rb +61 -43
  6. data/example.rb +30 -12
  7. data/lib/data_mapper.rb +6 -1
  8. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -57
  9. data/lib/data_mapper/adapters/data_object_adapter.rb +203 -97
  10. data/lib/data_mapper/adapters/mysql_adapter.rb +4 -0
  11. data/lib/data_mapper/adapters/postgresql_adapter.rb +7 -1
  12. data/lib/data_mapper/adapters/sql/coersion.rb +3 -2
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +29 -10
  14. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +4 -0
  15. data/lib/data_mapper/adapters/sql/mappings/column.rb +13 -9
  16. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +172 -0
  17. data/lib/data_mapper/adapters/sql/mappings/table.rb +43 -17
  18. data/lib/data_mapper/adapters/sqlite3_adapter.rb +9 -2
  19. data/lib/data_mapper/associations.rb +75 -3
  20. data/lib/data_mapper/associations/belongs_to_association.rb +70 -36
  21. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +195 -86
  22. data/lib/data_mapper/associations/has_many_association.rb +168 -61
  23. data/lib/data_mapper/associations/has_n_association.rb +23 -3
  24. data/lib/data_mapper/attributes.rb +73 -0
  25. data/lib/data_mapper/auto_migrations.rb +2 -6
  26. data/lib/data_mapper/base.rb +5 -9
  27. data/lib/data_mapper/database.rb +4 -3
  28. data/lib/data_mapper/embedded_value.rb +66 -30
  29. data/lib/data_mapper/identity_map.rb +1 -3
  30. data/lib/data_mapper/is/tree.rb +121 -0
  31. data/lib/data_mapper/migration.rb +155 -0
  32. data/lib/data_mapper/persistence.rb +532 -218
  33. data/lib/data_mapper/property.rb +306 -0
  34. data/lib/data_mapper/query.rb +164 -0
  35. data/lib/data_mapper/support/blank.rb +2 -2
  36. data/lib/data_mapper/support/connection_pool.rb +5 -6
  37. data/lib/data_mapper/support/enumerable.rb +3 -3
  38. data/lib/data_mapper/support/errors.rb +10 -1
  39. data/lib/data_mapper/support/inflector.rb +174 -238
  40. data/lib/data_mapper/support/object.rb +54 -0
  41. data/lib/data_mapper/support/serialization.rb +19 -1
  42. data/lib/data_mapper/support/string.rb +7 -16
  43. data/lib/data_mapper/support/symbol.rb +3 -15
  44. data/lib/data_mapper/support/typed_set.rb +68 -0
  45. data/lib/data_mapper/types/base.rb +44 -0
  46. data/lib/data_mapper/types/string.rb +34 -0
  47. data/lib/data_mapper/validations/number_validator.rb +40 -0
  48. data/lib/data_mapper/validations/string_validator.rb +20 -0
  49. data/lib/data_mapper/validations/validator.rb +13 -0
  50. data/performance.rb +26 -1
  51. data/profile_data_mapper.rb +1 -1
  52. data/rakefile.rb +42 -2
  53. data/spec/acts_as_tree_spec.rb +11 -3
  54. data/spec/adapters/data_object_adapter_spec.rb +31 -0
  55. data/spec/associations/belongs_to_association_spec.rb +98 -0
  56. data/spec/associations/has_and_belongs_to_many_association_spec.rb +377 -0
  57. data/spec/associations/has_many_association_spec.rb +337 -0
  58. data/spec/attributes_spec.rb +23 -1
  59. data/spec/auto_migrations_spec.rb +86 -29
  60. data/spec/callbacks_spec.rb +107 -0
  61. data/spec/column_spec.rb +5 -2
  62. data/spec/count_command_spec.rb +33 -1
  63. data/spec/database_spec.rb +18 -0
  64. data/spec/dependency_spec.rb +4 -2
  65. data/spec/embedded_value_spec.rb +8 -8
  66. data/spec/fixtures/people.yaml +1 -1
  67. data/spec/fixtures/projects.yaml +10 -1
  68. data/spec/fixtures/tasks.yaml +6 -0
  69. data/spec/fixtures/tasks_tasks.yaml +2 -0
  70. data/spec/fixtures/tomatoes.yaml +1 -0
  71. data/spec/is_a_tree_spec.rb +149 -0
  72. data/spec/load_command_spec.rb +71 -9
  73. data/spec/magic_columns_spec.rb +17 -2
  74. data/spec/migration_spec.rb +267 -0
  75. data/spec/models/animal.rb +1 -1
  76. data/spec/models/candidate.rb +8 -0
  77. data/spec/models/career.rb +1 -1
  78. data/spec/models/chain.rb +8 -0
  79. data/spec/models/comment.rb +1 -1
  80. data/spec/models/exhibit.rb +1 -1
  81. data/spec/models/fence.rb +7 -0
  82. data/spec/models/fruit.rb +2 -2
  83. data/spec/models/job.rb +8 -0
  84. data/spec/models/person.rb +2 -3
  85. data/spec/models/post.rb +1 -1
  86. data/spec/models/project.rb +21 -1
  87. data/spec/models/section.rb +1 -1
  88. data/spec/models/serializer.rb +1 -1
  89. data/spec/models/task.rb +9 -0
  90. data/spec/models/tomato.rb +27 -0
  91. data/spec/models/user.rb +8 -2
  92. data/spec/models/zoo.rb +2 -7
  93. data/spec/paranoia_spec.rb +1 -1
  94. data/spec/{base_spec.rb → persistence_spec.rb} +207 -18
  95. data/spec/postgres_spec.rb +48 -6
  96. data/spec/property_spec.rb +90 -9
  97. data/spec/query_spec.rb +71 -5
  98. data/spec/save_command_spec.rb +11 -0
  99. data/spec/spec_helper.rb +14 -11
  100. data/spec/support/blank_spec.rb +8 -0
  101. data/spec/support/inflector_spec.rb +41 -0
  102. data/spec/support/object_spec.rb +9 -0
  103. data/spec/{serialization_spec.rb → support/serialization_spec.rb} +1 -1
  104. data/spec/support/silence_spec.rb +15 -0
  105. data/spec/{support_spec.rb → support/string_spec.rb} +3 -3
  106. data/spec/support/struct_spec.rb +12 -0
  107. data/spec/support/typed_set_spec.rb +66 -0
  108. data/spec/table_spec.rb +3 -3
  109. data/spec/types/string.rb +81 -0
  110. data/spec/validates_uniqueness_of_spec.rb +17 -0
  111. data/spec/validations/number_validator.rb +59 -0
  112. data/spec/validations/string_validator.rb +14 -0
  113. metadata +59 -17
  114. data/do_performance.rb +0 -153
  115. data/lib/data_mapper/support/active_record_impersonation.rb +0 -103
  116. data/lib/data_mapper/support/weak_hash.rb +0 -46
  117. data/spec/active_record_impersonation_spec.rb +0 -129
  118. data/spec/associations_spec.rb +0 -232
  119. data/spec/conditions_spec.rb +0 -49
  120. data/spec/has_many_association_spec.rb +0 -173
  121. data/spec/models/animals_exhibit.rb +0 -8
@@ -1,153 +0,0 @@
1
- require 'benchmark'
2
- require 'lib/data_mapper'
3
-
4
- DataMapper::Database.setup({
5
- :adapter => 'do_mysql',
6
- :database => 'data_mapper_1',
7
- :username => 'root'
8
- })
9
-
10
- class DMAnimal < DataMapper::Base
11
- set_table_name 'animals'
12
- property :name, :string
13
- property :notes, :string
14
- end
15
-
16
- class DMPerson < DataMapper::Base
17
- set_table_name 'people'
18
- property :name, :string
19
- property :age, :integer
20
- property :occupation, :string
21
- property :notes, :text
22
- property :street, :string
23
- property :city, :string
24
- property :state, :string, :size => 2
25
- property :zip_code, :string, :size => 10
26
- end
27
-
28
- class Exhibit < DataMapper::Base
29
- property :name, :string
30
- belongs_to :zoo
31
- end
32
-
33
- class Zoo < DataMapper::Base
34
- property :name, :string
35
- has_many :exhibits
36
- end
37
-
38
- N = (ENV['N'] || 1000).to_i
39
-
40
- # 4.times do
41
- # [DMAnimal, Zoo, Exhibit].each do |klass|
42
- # klass.all.each do |instance|
43
- # klass.create(instance.attributes.reject { |k,v| k == :id })
44
- # end
45
- # end
46
- # end
47
-
48
- Benchmark::send(ENV['BM'] || :bmbm, 40) do |x|
49
-
50
- x.report('DataMapper:id') do
51
- N.times { DMAnimal[1] }
52
- end
53
-
54
- x.report('DataMapper:id:in-session') do
55
- database do
56
- N.times { DMAnimal[1] }
57
- end
58
- end
59
-
60
- x.report('DataMapper:all') do
61
- N.times { DMAnimal.all }
62
- end
63
-
64
- x.report('DataMapper:all:in-session') do
65
- database do
66
- N.times { DMAnimal.all }
67
- end
68
- end
69
-
70
- x.report('DataMapper:conditions:short') do
71
- N.times { Zoo[:name => 'Galveston'] }
72
- end
73
-
74
- x.report('DataMapper:conditions:short:in-session') do
75
- database do
76
- N.times { Zoo[:name => 'Galveston'] }
77
- end
78
- end
79
-
80
- x.report('DataMapper:conditions:long') do
81
- N.times { Zoo.find(:first, :conditions => ['name = ?', 'Galveston']) }
82
- end
83
-
84
- x.report('DataMapper:conditions:long:in-session') do
85
- database do
86
- N.times { Zoo.find(:first, :conditions => ['name = ?', 'Galveston']) }
87
- end
88
- end
89
-
90
- people = [
91
- ['Sam', 29, 'Programmer', 'A slow text field'],
92
- ['Amy', 28, 'Business Analyst Manager', 'A slow text field'],
93
- ['Scott', 25, 'Programmer', 'A slow text field'],
94
- ['Josh', 23, 'Supervisor', 'A slow text field'],
95
- ['Bob', 40, 'Peon', 'A slow text field']
96
- ]
97
-
98
- DMPerson.truncate!
99
-
100
- x.report('DataMapper:insert') do
101
- N.times do
102
- people.each do |a|
103
- DMPerson::create(:name => a[0], :age => a[1], :occupation => a[2], :notes => a[3])
104
- end
105
- end
106
- end
107
-
108
- x.report('DataMapper:update') do
109
- N.times do
110
- bob = DMAnimal.first(:name => 'Elephant')
111
- bob.notes = 'Updated by DataMapper'
112
- bob.save
113
- end
114
- end
115
-
116
- x.report('DataMapper:associations') do
117
- N.times do
118
- Zoo.all.each { |zoo| zoo.exhibits.entries }
119
- end
120
- end
121
-
122
- x.report('DataMapper:associations:in-session') do
123
- database do
124
- N.times do
125
- Zoo.all.each { |zoo| zoo.exhibits.entries }
126
- end
127
- end
128
- end
129
-
130
- x.report('DataMapper:find_by_sql') do
131
- N.times do
132
- database.query("SELECT * FROM zoos")
133
- end
134
- end
135
-
136
- x.report('DataMapper:accessors') do
137
- person = DMPerson.first
138
-
139
- N.times do
140
- <<-VCARD
141
- #{person.name} (#{person.age})
142
- #{person.occupation}
143
-
144
- #{person.street}
145
- #{person.city}, #{person.state} #{person.zip_code}
146
-
147
- #{person.notes}
148
- VCARD
149
- end
150
- end
151
-
152
-
153
- end
@@ -1,103 +0,0 @@
1
- module DataMapper
2
- module Support
3
-
4
- module ActiveRecordImpersonation
5
-
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- def save
11
- database_context.save(self)
12
- end
13
-
14
- def reload!
15
- database_context.first(self.class, key, :select => original_values.keys, :reload => true)
16
- self.loaded_associations.each { |association| association.reload! }
17
- self
18
- end
19
-
20
- def reload
21
- reload!
22
- end
23
-
24
- def destroy!
25
- database_context.destroy(self)
26
- end
27
-
28
- module ClassMethods
29
-
30
- def find_or_create(search_attributes, create_attributes = {})
31
- first(search_attributes) || create(search_attributes.merge(create_attributes))
32
- end
33
-
34
- def all(options = {})
35
- database.all(self, options)
36
- end
37
-
38
- def each(options = {}, &b)
39
- raise ArgumentError.new(":offset is not supported with the #each method") if options.has_key?(:offset)
40
-
41
- offset = 0
42
- limit = options[:limit] || (self::const_defined?('DEFAULT_LIMIT') ? self::DEFAULT_LIMIT : 500)
43
-
44
- until (results = all(options.merge(:limit => limit, :offset => offset))).empty?
45
- results.each(&b)
46
- offset += limit
47
- end
48
- end
49
-
50
- def first(*args)
51
- database.first(self, *args)
52
- end
53
-
54
- def count(*args)
55
- database.count(self, *args)
56
- end
57
-
58
- def delete_all
59
- database.delete_all(self)
60
- end
61
-
62
- def truncate!
63
- database.truncate(self)
64
- end
65
-
66
- def find(type_or_id, options = {})
67
- case type_or_id
68
- when :first then first(options)
69
- when :all then all(options)
70
- else first(type_or_id, options)
71
- end
72
- end
73
-
74
- def find_by_sql(*args)
75
- DataMapper::database.query(*args)
76
- end
77
-
78
- def get(*keys)
79
- database.get(self, keys)
80
- end
81
-
82
- def [](*keys)
83
- raise ArgumentError.new('Hash is not a valid key') if keys.size == 1 && keys.first.is_a?(Hash)
84
- database.get(self, keys)
85
- end
86
-
87
- def create(attributes)
88
- instance = self.new(attributes)
89
- instance.save
90
- instance
91
- end
92
-
93
- def create!(attributes)
94
- instance = self.new(attributes)
95
- instance.save
96
- raise InvalidRecord.new(instance) if instance.new_record?
97
- instance
98
- end
99
- end
100
- end
101
-
102
- end
103
- end
@@ -1,46 +0,0 @@
1
- module DataMapper
2
- module Support
3
- class WeakHash
4
- attr_reader :cache
5
- def initialize( cache = Hash.new )
6
- @cache = cache
7
- @key_map = {}
8
- @rev_cache = Hash.new{|h,k| h[k] = {}}
9
- @reclaim_value = lambda do |value_id|
10
- if @rev_cache.has_key? value_id
11
- @rev_cache[value_id].each_key{|key| @cache.delete key}
12
- @rev_cache.delete value_id
13
- end
14
- end
15
- @reclaim_key = lambda do |key_id|
16
- if @key_map.has_key? key_id
17
- @cache.delete @key_map[key_id]
18
- end
19
- end
20
- end
21
-
22
- def []( key )
23
- value_id = @cache[key]
24
- return ObjectSpace._id2ref(value_id) unless value_id.nil?
25
- nil
26
- rescue RangeError
27
- nil
28
- end
29
-
30
- def []=( key, value )
31
- case key
32
- when Fixnum, Symbol, true, false
33
- key2 = key
34
- else
35
- key2 = key.dup
36
- end
37
- @rev_cache[value.object_id][key2] = true
38
- @cache[key2] = value.object_id
39
- @key_map[key.object_id] = key2
40
-
41
- ObjectSpace.define_finalizer(value, @reclaim_value)
42
- ObjectSpace.define_finalizer(key, @reclaim_key)
43
- end
44
- end # class WeakHash
45
- end # module Support
46
- end # module DataMapper
@@ -1,129 +0,0 @@
1
- require File.dirname(__FILE__) + "/spec_helper"
2
-
3
- describe DataMapper::Support::ActiveRecordImpersonation do
4
-
5
- before(:all) do
6
- fixtures(:animals)
7
- fixtures(:exhibits)
8
- end
9
-
10
- describe 'A record' do
11
- it 'should save and return true if validations pass' do
12
- count = Exhibit.count
13
- bugs_and_more_bugs = Exhibit.new(:name => 'Bugs And More Bugs')
14
- bugs_and_more_bugs.save.should be_true
15
- Exhibit.count.should == count + 1
16
- end
17
-
18
- it 'should return false on save if validations fail' do
19
- count = Exhibit.count
20
- bugs_and_more_bugs = Exhibit.new
21
- bugs_and_more_bugs.save.should be_false
22
- Exhibit.count.should == count
23
- end
24
-
25
- it 'should reload its attributes' do
26
- frog = Animal.first(:name => 'Frog')
27
- frog.name = 'MegaFrog'
28
- frog.name.should == 'MegaFrog'
29
- frog.reload!
30
- frog.name.should == 'Frog'
31
- end
32
-
33
- it "should prepare it's associations for reload" do
34
- chippy = Animal.first(:name => 'Cup')
35
- amazonia = Exhibit.first(:name => 'Amazonia')
36
- amazonia.animals << chippy
37
- amazonia.animals.should include(chippy)
38
- amazonia.reload!
39
- amazonia.animals.should_not include(chippy)
40
- end
41
-
42
- it 'should be destroyed!' do
43
- capybara = Animal.create(:name => 'Capybara')
44
- count = Animal.count
45
- capybara.destroy!
46
- Animal.first(:name => 'Capybara').should be_nil
47
- Animal.count.should == count - 1
48
- end
49
- end
50
-
51
- it 'should return the first match using find_or_create' do
52
- count = Animal.count
53
- frog = Animal.find_or_create(:name => 'Frog')
54
- frog.name.should == 'Frog'
55
- Animal.count.should == count
56
- end
57
-
58
- it 'should create a record if a match is not found with find_or_create' do
59
- count = Animal.count
60
- capybara = Animal.find_or_create(:name => 'Capybara')
61
- capybara.name.should == 'Capybara'
62
- Animal.count.should == count + 1
63
- end
64
-
65
- it 'should return all records' do
66
- all_animals = Animal.all
67
- all_animals.length.should == Animal.count
68
- all_animals.each do |animal|
69
- animal.class.should == Animal
70
- end
71
- end
72
-
73
- it 'should return the first record' do
74
- Animal.first.should == Animal.find(:first)
75
- end
76
-
77
- it 'should return a count of the records' do
78
- Animal.count.should == Animal.find_by_sql("SELECT COUNT(*) FROM animals")[0]
79
- end
80
-
81
- it 'should delete all records' do
82
- Animal.delete_all
83
- Animal.count.should == 0
84
-
85
- fixtures(:animals)
86
- end
87
-
88
- #it 'should be truncated' do
89
- # Animal.truncate!
90
- # Animal.count.should == 0
91
- #
92
- # fixtures(:animals)
93
- #end
94
-
95
- it 'should find a matching record given an id' do
96
- Animal.find(1).name.should == 'Frog'
97
- end
98
-
99
- it 'should find all records' do
100
- Animal.find(:all).length.should == Animal.count
101
- end
102
-
103
- it 'should find all matching records given some condition' do
104
- Animal.find(:all, :conditions => ["name = ?", "Frog"])[0].name.should == 'Frog'
105
- end
106
-
107
- it 'should find the first matching record' do
108
- Animal.find(:first).name.should == 'Frog'
109
- end
110
-
111
- it 'should find the first matching record given some condition' do
112
- Animal.find(:first, :conditions => ["name = ?", "Frog"]).name.should == 'Frog'
113
- end
114
-
115
- it 'should select records using the supplied sql fragment' do
116
- Animal.find_by_sql("SELECT name FROM animals WHERE name='Frog'")[0].should == 'Frog'
117
- end
118
-
119
- it 'should retrieve the indexed element' do
120
- Animal[1].id.should == 1
121
- end
122
-
123
- it 'should create a new record' do
124
- count = Animal.count
125
- capybara = Animal.create(:name => 'Capybara')
126
- capybara.name.should == 'Capybara'
127
- Animal.count.should == count + 1
128
- end
129
- end
@@ -1,232 +0,0 @@
1
- require File.dirname(__FILE__) + "/spec_helper"
2
-
3
- describe DataMapper::Associations::BelongsToAssociation do
4
- before(:all) do
5
- fixtures(:zoos)
6
- end
7
-
8
- before(:each) do
9
- @aviary = Exhibit.first(:name => 'Monkey Mayhem')
10
- end
11
-
12
- it 'has a zoo association' do
13
- @aviary.zoo.class.should == Zoo
14
- Exhibit.new.zoo.should == nil
15
- end
16
-
17
- it 'belongs to a zoo' do
18
- @aviary.zoo.should == @aviary.database_context.first(Zoo, :name => 'San Diego')
19
- end
20
-
21
- it "is assigned a zoo_id" do
22
- zoo = Zoo.first
23
- exhibit = Exhibit.new(:name => 'bob')
24
- exhibit.zoo = zoo
25
- exhibit.instance_variable_get("@zoo_id").should == zoo.id
26
-
27
- exhibit.save.should eql(true)
28
-
29
- zoo2 = Zoo.first
30
- zoo2.exhibits.should include(exhibit)
31
-
32
- exhibit.destroy!
33
-
34
- zoo = Zoo.new(:name => 'bob')
35
- bob = Exhibit.new(:name => 'bob')
36
- zoo.exhibits << bob
37
- zoo.save.should eql(true)
38
-
39
- zoo.exhibits.first.should_not be_a_new_record
40
-
41
- bob.destroy!
42
- zoo.destroy!
43
- end
44
-
45
- it 'can build its zoo' do
46
- database do |db|
47
- e = Exhibit.new({:name => 'Super Extra Crazy Monkey Cage'})
48
- e.zoo.should == nil
49
- e.build_zoo({:name => 'Monkey Zoo'})
50
- e.zoo.class == Zoo
51
- e.zoo.new_record?.should == true
52
-
53
- e.save
54
- end
55
- end
56
-
57
- it 'can build its zoo' do
58
- database do |db|
59
- e = Exhibit.new({:name => 'Super Extra Crazy Monkey Cage'})
60
- e.zoo.should == nil
61
- e.create_zoo({:name => 'Monkey Zoo'})
62
- e.zoo.class == Zoo
63
- e.zoo.new_record?.should == false
64
- e.save
65
- end
66
- end
67
-
68
- after(:all) do
69
- fixtures('zoos')
70
- fixtures('exhibits')
71
- end
72
- end
73
-
74
- describe DataMapper::Associations::HasAndBelongsToManyAssociation do
75
-
76
- before(:all) do
77
- fixtures(:animals)
78
- fixtures(:exhibits)
79
- end
80
-
81
- before(:each) do
82
- @amazonia = Exhibit.first :name => 'Amazonia'
83
- end
84
-
85
- it "should generate the SQL for a join statement" do
86
- animals_association = database(:mock).schema[Exhibit].associations.find { |a| a.name == :animals }
87
-
88
- animals_association.to_sql.should == <<-EOS.compress_lines
89
- JOIN `animals_exhibits` ON `animals_exhibits`.`exhibit_id` = `exhibits`.`id`
90
- JOIN `animals` ON `animals`.`id` = `animals_exhibits`.`animal_id`
91
- EOS
92
- end
93
-
94
- it "should load associations" do
95
- database do
96
- froggy = Animal.first(:name => 'Frog')
97
- froggy.exhibits.size.should == 1
98
- froggy.exhibits.entries.first.should == Exhibit.first(:name => 'Amazonia')
99
- end
100
- end
101
-
102
- it 'has an animals association' do
103
- [@amazonia, Exhibit.new].each do |exhibit|
104
- exhibit.animals.class.should == DataMapper::Associations::HasAndBelongsToManyAssociation::Set
105
- end
106
- end
107
-
108
- it 'has many animals' do
109
- @amazonia.animals.size.should == 1
110
- end
111
-
112
- it 'should load associations magically' do
113
- Exhibit.all.each do |exhibit|
114
- exhibit.animals.each do |animal|
115
- animal.exhibits.should include(exhibit)
116
- end
117
- end
118
- end
119
-
120
- it 'should allow association of additional objects' do
121
- @amazonia.animals << Animal.new(:name => "Buffalo")
122
- @amazonia.animals.size.should == 2
123
- @amazonia.reload
124
- end
125
-
126
- it "should allow association of additional objects (CLEAN)" do
127
- pending "http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/92"
128
- @amazonia.should_not be_dirty
129
-
130
- animal = Animal[2]
131
- animal.should_not be_dirty
132
-
133
- @amazonia.animals << animal
134
- @amazonia.animals.size.should == 2
135
- @amazonia.reload
136
- end
137
-
138
- it 'should allow you to fill and clear an association' do
139
- marcy = Exhibit.create(:name => 'marcy')
140
-
141
- Animal.all.each do |animal|
142
- marcy.animals << animal
143
- end
144
-
145
- marcy.save.should eql(true)
146
- marcy.should have(Animal.count).animals
147
-
148
- marcy.animals.clear
149
- marcy.should have(0).animals
150
-
151
- marcy.save.should eql(true)
152
-
153
- marcys_stand_in = Exhibit[marcy.id]
154
- marcys_stand_in.should have(0).animals
155
-
156
- marcy.destroy!
157
- end
158
-
159
- it 'should allow you to delete a specific association member' do
160
- walter = Exhibit.create(:name => 'walter')
161
-
162
- Animal.all.each do |animal|
163
- walter.animals << animal
164
- end
165
-
166
- walter.save.should eql(true)
167
- walter.should have(Animal.count).animals
168
-
169
- delete_me = walter.animals.entries.first
170
- walter.animals.delete(delete_me).should eql(delete_me)
171
- walter.animals.delete(delete_me).should eql(nil)
172
-
173
- walter.should have(Animal.count - 1).animals
174
- walter.save.should eql(true)
175
-
176
- walters_stand_in = Exhibit[walter.id]
177
- walters_stand_in.animals.size.should eql(walter.animals.size)
178
-
179
- walter.destroy!
180
- end
181
-
182
- it "should allow updates to associations using association_ids[]" do
183
- pending "Awaiting implementation of association_ids[]"
184
- meerkat = Animal.new(:name => "Meerkat")
185
- @amazonia.animals.size.should == 1
186
-
187
- @amazonia.animal_ids << meerkat.id
188
- @amazonia.save
189
-
190
- @amazonia.animals.size.should == 2
191
- @amazonia.animals.should include?(meerkat)
192
- end
193
-
194
- it "Should handle setting complementary associations" do
195
- pending("some borkage here")
196
- u1 = User.create(:name => "u1")
197
- u1.comments.should be_empty
198
-
199
- c1 = Comment.create(:comment => "c", :author => u1)
200
- # p u1
201
- # p c1
202
-
203
- u1.comments.should_not be_empty
204
- u1.comments.should include(c1)
205
-
206
- u1.reload!
207
- u1.comments.should_not be_empty
208
- u1.comments.should include(c1)
209
- end
210
-
211
- it "should raise an error when attempting to associate an object not of the correct type (assuming added model doesn't inherit from the correct type)" do
212
- pending("see: http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/91")
213
- @amazonia.animals.should_not be_empty
214
- chuck = Person.new(:name => "Chuck")
215
-
216
- ## InvalidRecord isn't the error we should use here....needs to be changed
217
- lambda { @amazonia.animals << chuck }.should raise_error(WrongType)
218
-
219
- end
220
-
221
- it "should associate an object which has inherited from the correct type into an association" do
222
- pending("see: http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/91")
223
- programmer = Career.first(:name => 'Programmer')
224
- programmer.followers.should_not be_empty
225
-
226
- sales_person = SalesPerson.new(:name => 'Chuck')
227
-
228
- lambda { programmer.followers << sales_person }.should_not raise_error(WrongType)
229
-
230
- end
231
-
232
- end