datamapper-dm-core 0.9.11 → 0.10.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.
- data/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/lib/dm-core.rb +106 -110
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1723 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- data/spec/unit/type_spec.rb +0 -119
|
@@ -0,0 +1,924 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
share_examples_for 'it creates a one accessor' do
|
|
4
|
+
describe 'accessor' do
|
|
5
|
+
describe 'when there is no associated resource' do
|
|
6
|
+
describe 'without a query' do
|
|
7
|
+
before :all do
|
|
8
|
+
@return = @car.send(@name)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should return nil' do
|
|
12
|
+
@return.should be_nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'with a query' do
|
|
17
|
+
before :all do
|
|
18
|
+
@return = @car.send(@name, :id => 99)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should return nil' do
|
|
22
|
+
@return.should be_nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'when there is an associated resource' do
|
|
28
|
+
before :all do
|
|
29
|
+
@expected = @model.new
|
|
30
|
+
@car.send("#{@name}=", @expected)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe 'without a query' do
|
|
34
|
+
before :all do
|
|
35
|
+
@return = @car.send(@name)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'should return a Resource' do
|
|
39
|
+
@return.should be_kind_of(DataMapper::Resource)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'should return the expected Resource' do
|
|
43
|
+
@return.should equal(@expected)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe 'with a query' do
|
|
48
|
+
before :all do
|
|
49
|
+
@car.save # save @car and @expected to set @expected.id
|
|
50
|
+
|
|
51
|
+
@expected.id.should_not be_nil
|
|
52
|
+
|
|
53
|
+
@return = @car.send(@name, :id => @expected.id)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'should return a Resource' do
|
|
57
|
+
@return.should be_kind_of(DataMapper::Resource)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'should return the expected Resource' do
|
|
61
|
+
@return.should == @expected
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe 'when the target model is scoped' do
|
|
67
|
+
before :all do
|
|
68
|
+
@resource = @model.new
|
|
69
|
+
@car.send("#{@name}=", @resource)
|
|
70
|
+
@car.save
|
|
71
|
+
|
|
72
|
+
# set the model scope to not match the expected resource
|
|
73
|
+
@model.default_scope.update(:id.not => @resource.id)
|
|
74
|
+
|
|
75
|
+
@return = @car.model.get(*@car.key).send(@name)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'should return nil' do
|
|
79
|
+
@return.should be_nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
share_examples_for 'it creates a one mutator' do
|
|
86
|
+
describe 'mutator' do
|
|
87
|
+
describe 'when setting a Resource' do
|
|
88
|
+
before :all do
|
|
89
|
+
@expected = @model.new
|
|
90
|
+
|
|
91
|
+
@return = @car.send("#{@name}=", @expected)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'should return the expected Resource' do
|
|
95
|
+
@return.should equal(@expected)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'should set the Resource' do
|
|
99
|
+
@car.send(@name).should equal(@expected)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'should relate associated Resource' do
|
|
103
|
+
relationship = Car.relationships[@name]
|
|
104
|
+
many_to_one = relationship.kind_of?(DataMapper::Associations::ManyToOne::Relationship)
|
|
105
|
+
one_to_one_through = relationship.kind_of?(DataMapper::Associations::OneToOne::Relationship) && relationship.respond_to?(:through)
|
|
106
|
+
|
|
107
|
+
pending_if 'TODO', many_to_one || one_to_one_through do
|
|
108
|
+
@expected.car.should == @car
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'should persist the Resource' do
|
|
113
|
+
@car.save.should be_true
|
|
114
|
+
@car.model.get(*@car.key).send(@name).should == @expected
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should persist the associated Resource' do
|
|
118
|
+
@car.save.should be_true
|
|
119
|
+
@expected.should be_saved
|
|
120
|
+
@expected.model.get(*@expected.key).car.should == @car
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe 'when setting a Hash' do
|
|
125
|
+
before :all do
|
|
126
|
+
@car.send("#{@name}=", @model.new)
|
|
127
|
+
|
|
128
|
+
attributes = { :id => 10 }
|
|
129
|
+
@expected = @model.new(attributes)
|
|
130
|
+
|
|
131
|
+
@return = @car.send("#{@name}=", attributes)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'should return the expected Resource' do
|
|
135
|
+
@return.should == @expected
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'should set the Resource' do
|
|
139
|
+
@car.send(@name).should equal(@return)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'should relate associated Resource' do
|
|
143
|
+
relationship = Car.relationships[@name]
|
|
144
|
+
many_to_one = relationship.kind_of?(DataMapper::Associations::ManyToOne::Relationship)
|
|
145
|
+
one_to_one_through = relationship.kind_of?(DataMapper::Associations::OneToOne::Relationship) && relationship.respond_to?(:through)
|
|
146
|
+
|
|
147
|
+
pending_if 'TODO', many_to_one || one_to_one_through do
|
|
148
|
+
@return.car.should == @car
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'should persist the Resource' do
|
|
153
|
+
@car.save.should be_true
|
|
154
|
+
@car.model.get(*@car.key).send(@name).should == @return
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it 'should persist the associated Resource' do
|
|
158
|
+
@car.save.should be_true
|
|
159
|
+
@return.should be_saved
|
|
160
|
+
@return.model.get(*@return.key).car.should == @car
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe 'when setting nil' do
|
|
165
|
+
before :all do
|
|
166
|
+
@car.send("#{@name}=", @model.new)
|
|
167
|
+
|
|
168
|
+
@return = @car.send("#{@name}=", nil)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'should return nil' do
|
|
172
|
+
@return.should be_nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'should set nil' do
|
|
176
|
+
@car.send(@name).should be_nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'should persist as nil' do
|
|
180
|
+
@car.save.should be_true
|
|
181
|
+
@car.model.get(*@car.key).send(@name).should be_nil
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe 'when changing the Resource' do
|
|
186
|
+
before :all do
|
|
187
|
+
@car.send("#{@name}=", @model.new)
|
|
188
|
+
@expected = @model.new
|
|
189
|
+
|
|
190
|
+
@return = @car.send("#{@name}=", @expected)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'should return the expected Resource' do
|
|
194
|
+
@return.should equal(@expected)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'should set the Resource' do
|
|
198
|
+
@car.send(@name).should equal(@expected)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'should relate associated Resource' do
|
|
202
|
+
relationship = Car.relationships[@name]
|
|
203
|
+
many_to_one = relationship.kind_of?(DataMapper::Associations::ManyToOne::Relationship)
|
|
204
|
+
one_to_one_through = relationship.kind_of?(DataMapper::Associations::OneToOne::Relationship) && relationship.respond_to?(:through)
|
|
205
|
+
|
|
206
|
+
pending_if 'should create back-reference', many_to_one || one_to_one_through do
|
|
207
|
+
@expected.car.should == @car
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'should persist the Resource' do
|
|
212
|
+
@car.save.should be_true
|
|
213
|
+
@car.model.get(*@car.key).send(@name).should == @expected
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it 'should persist the associated Resource' do
|
|
217
|
+
@car.save.should be_true
|
|
218
|
+
@expected.should be_saved
|
|
219
|
+
@expected.model.get(*@expected.key).car.should == @car
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
share_examples_for 'it creates a many accessor' do
|
|
226
|
+
describe 'accessor' do
|
|
227
|
+
describe 'when there is no child resource and the source is saved' do
|
|
228
|
+
before :all do
|
|
229
|
+
@car.save.should be_true
|
|
230
|
+
@return = @car.send(@name)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it 'should return a Collection' do
|
|
234
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'should return an empty Collection' do
|
|
238
|
+
@return.should be_empty
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe 'when there is no child resource and the source is not saved' do
|
|
243
|
+
before :all do
|
|
244
|
+
@return = @car.send(@name)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it 'should return a Collection' do
|
|
248
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it 'should return an empty Collection' do
|
|
252
|
+
@return.should be_empty
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
describe 'when there is a child resource' do
|
|
257
|
+
before :all do
|
|
258
|
+
@return = nil
|
|
259
|
+
|
|
260
|
+
@expected = @model.new
|
|
261
|
+
@car.send("#{@name}=", [ @expected ])
|
|
262
|
+
|
|
263
|
+
@return = @car.send(@name)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'should return a Collection' do
|
|
267
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it 'should return expected Resources' do
|
|
271
|
+
@return.should == [ @expected ]
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe 'when the target model is scoped' do
|
|
276
|
+
before :all do
|
|
277
|
+
2.times { @car.send(@name).new }
|
|
278
|
+
@car.save
|
|
279
|
+
|
|
280
|
+
@expected = @car.send(@name).first
|
|
281
|
+
|
|
282
|
+
# set the model scope to only return the first record
|
|
283
|
+
@model.default_scope.update(@model.key(@repository.name).zip(@expected.key).to_hash)
|
|
284
|
+
|
|
285
|
+
@return = @car.model.get(*@car.key).send(@name)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it 'should return a Collection' do
|
|
289
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it 'should return expected Resources' do
|
|
293
|
+
@return.should == [ @expected ]
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
share_examples_for 'it creates a many mutator' do
|
|
300
|
+
describe 'mutator' do
|
|
301
|
+
describe 'when setting an Array of Resources' do
|
|
302
|
+
before :all do
|
|
303
|
+
@expected = [ @model.new ]
|
|
304
|
+
|
|
305
|
+
@return = @car.send("#{@name}=", @expected)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'should return the expected Collection' do
|
|
309
|
+
@return.should == @expected
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it 'should set the Collection' do
|
|
313
|
+
@car.send(@name).should == @expected
|
|
314
|
+
@car.send(@name).zip(@expected) { |value, expected| value.should equal(expected) }
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it 'should relate the associated Collection' do
|
|
318
|
+
pending_if 'TODO', Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
319
|
+
@expected.each { |resource| resource.car.should == @car }
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it 'should persist the Collection' do
|
|
324
|
+
@car.save.should be_true
|
|
325
|
+
@car.model.get(*@car.key).send(@name).should == @expected
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it 'should persist the associated Resource' do
|
|
329
|
+
@car.save.should be_true
|
|
330
|
+
@expected.each { |resource| resource.should be_saved }
|
|
331
|
+
@expected.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
describe 'when setting an Array of Hashes' do
|
|
336
|
+
before :all do
|
|
337
|
+
attributes = { :id => 11 }
|
|
338
|
+
@hashes = [ attributes ]
|
|
339
|
+
@expected = [ @model.new(attributes) ]
|
|
340
|
+
|
|
341
|
+
@return = @car.send("#{@name}=", @hashes)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it 'should return the expected Collection' do
|
|
345
|
+
@return.should == @expected
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
it 'should set the Collection' do
|
|
349
|
+
@car.send(@name).should == @return
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it 'should relate the associated Collection' do
|
|
353
|
+
pending_if 'TODO', Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
354
|
+
@return.each { |resource| resource.car.should == @car }
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it 'should persist the Collection' do
|
|
359
|
+
@car.save.should be_true
|
|
360
|
+
@car.model.get(*@car.key).send(@name).should == @return
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
it 'should persist the associated Resource' do
|
|
364
|
+
@car.save.should be_true
|
|
365
|
+
@return.each { |resource| resource.should be_saved }
|
|
366
|
+
@return.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
describe 'when setting an empty collection' do
|
|
371
|
+
before :all do
|
|
372
|
+
@car.send("#{@name}=", [ @model.new ])
|
|
373
|
+
|
|
374
|
+
@return = @car.send("#{@name}=", [])
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it 'should return a Collection' do
|
|
378
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it 'should set an empty Collection' do
|
|
382
|
+
@car.send(@name).should be_empty
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
it 'should persist as an empty Collection' do
|
|
386
|
+
@car.save.should be_true
|
|
387
|
+
@car.model.get(*@car.key).send(@name).should be_empty
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
describe 'when changing an associated collection' do
|
|
392
|
+
before :all do
|
|
393
|
+
@car.send("#{@name}=", [ @model.new ])
|
|
394
|
+
|
|
395
|
+
@expected = [ @model.new ]
|
|
396
|
+
|
|
397
|
+
@return = @car.send("#{@name}=", @expected)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
it 'should return the expected Resource' do
|
|
401
|
+
@return.should == @expected
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it 'should set the Resource' do
|
|
405
|
+
@car.send(@name).should == @expected
|
|
406
|
+
@car.send(@name).zip(@expected) { |value, expected| value.should equal(expected) }
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
it 'should relate associated Resource' do
|
|
410
|
+
pending_if 'TODO', Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
411
|
+
@expected.each { |resource| resource.car.should == @car }
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
it 'should persist the Resource' do
|
|
416
|
+
@car.save.should be_true
|
|
417
|
+
@car.model.get(*@car.key).send(@name).should == @expected
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it 'should persist the associated Resource' do
|
|
421
|
+
@car.save.should be_true
|
|
422
|
+
@expected.each { |resource| resource.should be_saved }
|
|
423
|
+
@expected.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
describe DataMapper::Associations do
|
|
430
|
+
before :all do
|
|
431
|
+
class ::Car
|
|
432
|
+
include DataMapper::Resource
|
|
433
|
+
|
|
434
|
+
property :id, Serial
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
class ::Engine
|
|
438
|
+
include DataMapper::Resource
|
|
439
|
+
|
|
440
|
+
property :id, Serial
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
class ::Door
|
|
444
|
+
include DataMapper::Resource
|
|
445
|
+
|
|
446
|
+
property :id, Serial
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
class ::Window
|
|
450
|
+
include DataMapper::Resource
|
|
451
|
+
|
|
452
|
+
property :id, Serial
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def n
|
|
457
|
+
1.0/0
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
it { Engine.should respond_to(:belongs_to) }
|
|
461
|
+
|
|
462
|
+
describe '#belongs_to' do
|
|
463
|
+
before :all do
|
|
464
|
+
@model = Engine
|
|
465
|
+
@name = :engine
|
|
466
|
+
|
|
467
|
+
Car.belongs_to(@name, :nullable => true)
|
|
468
|
+
Engine.has(1, :car)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
supported_by :all do
|
|
472
|
+
before :all do
|
|
473
|
+
@car = Car.new
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
it { @car.should respond_to(@name) }
|
|
477
|
+
|
|
478
|
+
it_should_behave_like 'it creates a one accessor'
|
|
479
|
+
|
|
480
|
+
it { @car.should respond_to("#{@name}=") }
|
|
481
|
+
|
|
482
|
+
it_should_behave_like 'it creates a one mutator'
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# TODO: refactor these specs into above structure once they pass
|
|
486
|
+
describe 'pending query specs' do
|
|
487
|
+
before :all do
|
|
488
|
+
Car.has(1, :engine)
|
|
489
|
+
Engine.belongs_to(:car)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
supported_by :all do
|
|
493
|
+
describe 'querying for a parent resource when only the foreign key is set' do
|
|
494
|
+
before :all do
|
|
495
|
+
# create a car that would be returned if the query is not
|
|
496
|
+
# scoped properly to retrieve @car
|
|
497
|
+
Car.create
|
|
498
|
+
|
|
499
|
+
@car = Car.create
|
|
500
|
+
engine = Engine.new(:car_id => @car.id)
|
|
501
|
+
|
|
502
|
+
@return = engine.car
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
it 'should return a Resource' do
|
|
506
|
+
@return.should be_kind_of(DataMapper::Resource)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it 'should return expected Resource' do
|
|
510
|
+
@return.should eql(@car)
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
describe 'querying for a parent resource' do
|
|
515
|
+
before :all do
|
|
516
|
+
@car = Car.create
|
|
517
|
+
@engine = Engine.create(:car => @car)
|
|
518
|
+
@resource = @engine.car(:id => @car.id)
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
it 'should return a Resource' do
|
|
522
|
+
@resource.should be_kind_of(DataMapper::Resource)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it 'should return expected Resource' do
|
|
526
|
+
@resource.should eql(@car)
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
describe 'querying for a parent resource that does not exist' do
|
|
531
|
+
before :all do
|
|
532
|
+
@car = Car.create
|
|
533
|
+
@engine = Engine.create(:car => @car)
|
|
534
|
+
@resource = @engine.car(:id.not => @car.id)
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
it 'should return nil' do
|
|
538
|
+
@resource.should be_nil
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
describe 'changing the parent resource' do
|
|
543
|
+
before :all do
|
|
544
|
+
@car = Car.create
|
|
545
|
+
@engine = Engine.new
|
|
546
|
+
@engine.car = @car
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it 'should set the associated foreign key' do
|
|
550
|
+
@engine.car_id.should == @car.id
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
it 'should add the engine object to the car' do
|
|
554
|
+
pending 'Changing a belongs_to parent should add the object to the correct association' do
|
|
555
|
+
@car.engines.should be_include(@engine)
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
describe 'changing the parent foreign key' do
|
|
561
|
+
before :all do
|
|
562
|
+
@car = Car.create
|
|
563
|
+
|
|
564
|
+
@engine = Engine.new
|
|
565
|
+
@engine.car_id = @car.id
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
it 'should set the associated resource' do
|
|
569
|
+
@engine.car.should eql(@car)
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
describe 'changing an existing resource through the relation' do
|
|
574
|
+
before :all do
|
|
575
|
+
@car1 = Car.create
|
|
576
|
+
@car2 = Car.create
|
|
577
|
+
@engine = Engine.create(:car => @car1)
|
|
578
|
+
@engine.car = @car2
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
it 'should also change the foreign key' do
|
|
582
|
+
@engine.car_id.should == @car2.id
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
it 'should add the engine to the car' do
|
|
586
|
+
pending 'Changing a belongs_to parent should add the object to the correct association' do
|
|
587
|
+
@car2.engines.should be_include(@engine)
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
describe 'changing an existing resource through the relation' do
|
|
593
|
+
before :all do
|
|
594
|
+
@car1 = Car.create
|
|
595
|
+
@car2 = Car.create
|
|
596
|
+
@engine = Engine.create(:car => @car1)
|
|
597
|
+
@engine.car_id = @car2.id
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
it 'should also change the foreign key' do
|
|
601
|
+
pending 'a change to the foreign key should also change the related object' do
|
|
602
|
+
@engine.car.should eql(@car2)
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
it 'should add the engine to the car' do
|
|
607
|
+
pending 'a change to the foreign key should also change the related object' do
|
|
608
|
+
@car2.engines.should be_include(@engine)
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
it { Car.should respond_to(:has) }
|
|
617
|
+
|
|
618
|
+
describe '#has' do
|
|
619
|
+
describe '1' do
|
|
620
|
+
before :all do
|
|
621
|
+
@model = Engine
|
|
622
|
+
@name = :engine
|
|
623
|
+
|
|
624
|
+
Car.has(1, @name)
|
|
625
|
+
Engine.belongs_to(:car)
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
supported_by :all do
|
|
629
|
+
before :all do
|
|
630
|
+
@car = Car.new
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
it { @car.should respond_to(@name) }
|
|
634
|
+
|
|
635
|
+
it_should_behave_like 'it creates a one accessor'
|
|
636
|
+
|
|
637
|
+
it { @car.should respond_to("#{@name}=") }
|
|
638
|
+
|
|
639
|
+
it_should_behave_like 'it creates a one mutator'
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
describe '1 through' do
|
|
644
|
+
before :all do
|
|
645
|
+
@model = Engine
|
|
646
|
+
@name = :engine
|
|
647
|
+
|
|
648
|
+
Car.has(1, @name, :through => DataMapper::Resource)
|
|
649
|
+
Engine.has(1, :car, :through => DataMapper::Resource)
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
supported_by :all do
|
|
653
|
+
before :all do
|
|
654
|
+
@no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
|
|
655
|
+
defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
before :all do
|
|
659
|
+
@car = Car.new
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
before do
|
|
663
|
+
pending if @no_join
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
it { @car.should respond_to(@name) }
|
|
667
|
+
|
|
668
|
+
it_should_behave_like 'it creates a one accessor'
|
|
669
|
+
|
|
670
|
+
it { @car.should respond_to("#{@name}=") }
|
|
671
|
+
|
|
672
|
+
it_should_behave_like 'it creates a one mutator'
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
describe 'n..n' do
|
|
677
|
+
before :all do
|
|
678
|
+
@model = Door
|
|
679
|
+
@name = :doors
|
|
680
|
+
|
|
681
|
+
Car.has(1..4, @name)
|
|
682
|
+
Door.belongs_to(:car, :nullable => true)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
supported_by :all do
|
|
686
|
+
before :all do
|
|
687
|
+
@car = Car.new
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
it { @car.should respond_to(@name) }
|
|
691
|
+
|
|
692
|
+
it_should_behave_like 'it creates a many accessor'
|
|
693
|
+
|
|
694
|
+
it { @car.should respond_to("#{@name}=") }
|
|
695
|
+
|
|
696
|
+
it_should_behave_like 'it creates a many mutator'
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
describe 'n..n through' do
|
|
701
|
+
before :all do
|
|
702
|
+
@model = Window
|
|
703
|
+
@name = :windows
|
|
704
|
+
|
|
705
|
+
Window.has(1, :car, :through => DataMapper::Resource)
|
|
706
|
+
Car.has(1..4, :windows, :through => DataMapper::Resource)
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
supported_by :all do
|
|
710
|
+
before :all do
|
|
711
|
+
@no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
|
|
712
|
+
defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
before :all do
|
|
716
|
+
@car = Car.new
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
before do
|
|
720
|
+
pending if @no_join
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
it { @car.should respond_to(@name) }
|
|
724
|
+
|
|
725
|
+
it_should_behave_like 'it creates a many accessor'
|
|
726
|
+
|
|
727
|
+
it { @car.should respond_to("#{@name}=") }
|
|
728
|
+
|
|
729
|
+
it_should_behave_like 'it creates a many mutator'
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
describe 'when the 3rd argument is a Model' do
|
|
734
|
+
before :all do
|
|
735
|
+
Car.has(1, :engine, Engine)
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
it 'should set the relationship target model' do
|
|
739
|
+
Car.relationships[:engine].target_model.should == Engine
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
describe 'when the 3rd argument is a String' do
|
|
744
|
+
before :all do
|
|
745
|
+
Car.has(1, :engine, 'Engine')
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
it 'should set the relationship target model' do
|
|
749
|
+
Car.relationships[:engine].target_model.should == Engine
|
|
750
|
+
end
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
it 'should raise an exception if the cardinality is not understood' do
|
|
754
|
+
lambda { Car.has(n..n, :doors) }.should raise_error(ArgumentError)
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
it 'should raise an exception if the minimum constraint is larger than the maximum' do
|
|
758
|
+
lambda { Car.has(2..1, :doors) }.should raise_error(ArgumentError)
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
describe 'property prefix inference' do
|
|
763
|
+
describe 'when a relationship has an inverse' do
|
|
764
|
+
before :all do
|
|
765
|
+
@engine_relationship = Car.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
supported_by :all do
|
|
769
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
770
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
describe 'when a relationship does not have an inverse' do
|
|
776
|
+
before :all do
|
|
777
|
+
@engine_relationship = Car.has(1, :engine)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
supported_by :all do
|
|
781
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
782
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :car_id ]
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
describe 'when a relationship is inherited' do
|
|
788
|
+
describe 'has an inverse' do
|
|
789
|
+
before :all do
|
|
790
|
+
Car.property(:type, DataMapper::Types::Discriminator)
|
|
791
|
+
|
|
792
|
+
class ::ElectricCar < Car; end
|
|
793
|
+
|
|
794
|
+
Car.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
supported_by :all do
|
|
798
|
+
before :all do
|
|
799
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
it 'should have a source model equal to the descendant' do
|
|
803
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
807
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
describe 'does not have an inverse' do
|
|
813
|
+
before :all do
|
|
814
|
+
Car.property(:type, DataMapper::Types::Discriminator)
|
|
815
|
+
|
|
816
|
+
class ::ElectricCar < Car; end
|
|
817
|
+
|
|
818
|
+
Car.has(1, :engine)
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
supported_by :all do
|
|
822
|
+
before :all do
|
|
823
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
it 'should have a source model equal to the descendant' do
|
|
827
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
831
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :car_id ]
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
end
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
describe "when a subclass defines it's own relationship" do
|
|
838
|
+
describe 'has an inverse' do
|
|
839
|
+
before :all do
|
|
840
|
+
Car.property(:type, DataMapper::Types::Discriminator)
|
|
841
|
+
|
|
842
|
+
class ::ElectricCar < Car; end
|
|
843
|
+
|
|
844
|
+
ElectricCar.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
supported_by :all do
|
|
848
|
+
before :all do
|
|
849
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
it 'should have a source model equal to the descendant' do
|
|
853
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
857
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
describe 'does not have an inverse' do
|
|
863
|
+
before :all do
|
|
864
|
+
Car.property(:type, DataMapper::Types::Discriminator)
|
|
865
|
+
|
|
866
|
+
class ::ElectricCar < Car; end
|
|
867
|
+
|
|
868
|
+
ElectricCar.has(1, :engine)
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
supported_by :all do
|
|
872
|
+
before :all do
|
|
873
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
it 'should have a source model equal to the descendant' do
|
|
877
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
881
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :electric_car_id ]
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
describe 'child is also a parent' do
|
|
889
|
+
before :all do
|
|
890
|
+
class ::Employee
|
|
891
|
+
include DataMapper::Resource
|
|
892
|
+
|
|
893
|
+
property :id, Serial
|
|
894
|
+
property :name, String
|
|
895
|
+
|
|
896
|
+
belongs_to :company
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
class ::Company
|
|
900
|
+
include DataMapper::Resource
|
|
901
|
+
|
|
902
|
+
property :id, Serial
|
|
903
|
+
property :name, String
|
|
904
|
+
|
|
905
|
+
belongs_to :owner, Employee, :nullable => true
|
|
906
|
+
has n, :employees
|
|
907
|
+
end
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
supported_by :all do
|
|
911
|
+
before :all do
|
|
912
|
+
@company = Company.create(:name => 'ACME Inc.')
|
|
913
|
+
@employee = @company.employees.create(:name => 'Wil E. Coyote')
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
it 'should save the child as a parent' do
|
|
917
|
+
lambda {
|
|
918
|
+
@company.owner = @employee
|
|
919
|
+
@company.save.should be_true
|
|
920
|
+
}.should_not raise_error
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
end
|
|
924
|
+
end
|