ghost_dm-core 1.3.0.beta
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 +29 -0
- data/.document +5 -0
- data/.gitignore +35 -0
- data/.yardopts +1 -0
- data/Gemfile +65 -0
- data/LICENSE +20 -0
- data/README.md +269 -0
- data/Rakefile +4 -0
- data/dm-core.gemspec +24 -0
- data/lib/dm-core.rb +292 -0
- data/lib/dm-core/adapters.rb +222 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +237 -0
- data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
- data/lib/dm-core/associations/many_to_many.rb +499 -0
- data/lib/dm-core/associations/many_to_one.rb +290 -0
- data/lib/dm-core/associations/one_to_many.rb +348 -0
- data/lib/dm-core/associations/one_to_one.rb +86 -0
- data/lib/dm-core/associations/relationship.rb +663 -0
- data/lib/dm-core/backwards.rb +13 -0
- data/lib/dm-core/collection.rb +1515 -0
- data/lib/dm-core/core_ext/kernel.rb +23 -0
- data/lib/dm-core/core_ext/pathname.rb +6 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +7 -0
- data/lib/dm-core/model.rb +874 -0
- data/lib/dm-core/model/hook.rb +103 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +249 -0
- data/lib/dm-core/model/relationship.rb +378 -0
- data/lib/dm-core/model/scope.rb +89 -0
- data/lib/dm-core/property.rb +866 -0
- data/lib/dm-core/property/binary.rb +21 -0
- data/lib/dm-core/property/boolean.rb +20 -0
- data/lib/dm-core/property/class.rb +17 -0
- data/lib/dm-core/property/date.rb +10 -0
- data/lib/dm-core/property/date_time.rb +10 -0
- data/lib/dm-core/property/decimal.rb +36 -0
- data/lib/dm-core/property/discriminator.rb +44 -0
- data/lib/dm-core/property/float.rb +16 -0
- data/lib/dm-core/property/integer.rb +22 -0
- data/lib/dm-core/property/invalid_value_error.rb +22 -0
- data/lib/dm-core/property/lookup.rb +27 -0
- data/lib/dm-core/property/numeric.rb +38 -0
- data/lib/dm-core/property/object.rb +34 -0
- data/lib/dm-core/property/serial.rb +14 -0
- data/lib/dm-core/property/string.rb +38 -0
- data/lib/dm-core/property/text.rb +9 -0
- data/lib/dm-core/property/time.rb +10 -0
- data/lib/dm-core/property_set.rb +177 -0
- data/lib/dm-core/query.rb +1366 -0
- data/lib/dm-core/query/conditions/comparison.rb +911 -0
- data/lib/dm-core/query/conditions/operation.rb +721 -0
- data/lib/dm-core/query/direction.rb +36 -0
- data/lib/dm-core/query/operator.rb +35 -0
- data/lib/dm-core/query/path.rb +114 -0
- data/lib/dm-core/query/sort.rb +39 -0
- data/lib/dm-core/relationship_set.rb +72 -0
- data/lib/dm-core/repository.rb +226 -0
- data/lib/dm-core/resource.rb +1214 -0
- data/lib/dm-core/resource/persistence_state.rb +75 -0
- data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
- data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
- data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
- data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
- data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
- data/lib/dm-core/resource/persistence_state/transient.rb +80 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +64 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
- data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
- data/lib/dm-core/spec/setup.rb +174 -0
- data/lib/dm-core/spec/shared/adapter_spec.rb +341 -0
- data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
- data/lib/dm-core/spec/shared/resource_spec.rb +1232 -0
- data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
- data/lib/dm-core/spec/shared/semipublic/property_spec.rb +176 -0
- data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/chainable.rb +18 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/descendant_set.rb +89 -0
- data/lib/dm-core/support/equalizer.rb +48 -0
- data/lib/dm-core/support/ext/array.rb +22 -0
- data/lib/dm-core/support/ext/blank.rb +25 -0
- data/lib/dm-core/support/ext/hash.rb +67 -0
- data/lib/dm-core/support/ext/module.rb +47 -0
- data/lib/dm-core/support/ext/object.rb +57 -0
- data/lib/dm-core/support/ext/string.rb +24 -0
- data/lib/dm-core/support/ext/try_dup.rb +12 -0
- data/lib/dm-core/support/hook.rb +405 -0
- data/lib/dm-core/support/inflections.rb +60 -0
- data/lib/dm-core/support/inflector/inflections.rb +211 -0
- data/lib/dm-core/support/inflector/methods.rb +151 -0
- data/lib/dm-core/support/lazy_array.rb +451 -0
- data/lib/dm-core/support/local_object_space.rb +13 -0
- data/lib/dm-core/support/logger.rb +201 -0
- data/lib/dm-core/support/mash.rb +176 -0
- data/lib/dm-core/support/naming_conventions.rb +90 -0
- data/lib/dm-core/support/ordered_set.rb +380 -0
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/support/subject_set.rb +250 -0
- data/lib/dm-core/version.rb +3 -0
- data/script/performance.rb +275 -0
- data/script/profile.rb +218 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
- data/spec/public/associations/many_to_many_spec.rb +197 -0
- data/spec/public/associations/many_to_one_spec.rb +83 -0
- data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
- data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
- data/spec/public/associations/one_to_many_spec.rb +81 -0
- data/spec/public/associations/one_to_one_spec.rb +176 -0
- data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
- data/spec/public/collection_spec.rb +69 -0
- data/spec/public/finalize_spec.rb +76 -0
- data/spec/public/model/hook_spec.rb +246 -0
- data/spec/public/model/property_spec.rb +88 -0
- data/spec/public/model/relationship_spec.rb +1040 -0
- data/spec/public/model_spec.rb +462 -0
- data/spec/public/property/binary_spec.rb +41 -0
- data/spec/public/property/boolean_spec.rb +22 -0
- data/spec/public/property/class_spec.rb +28 -0
- data/spec/public/property/date_spec.rb +22 -0
- data/spec/public/property/date_time_spec.rb +22 -0
- data/spec/public/property/decimal_spec.rb +23 -0
- data/spec/public/property/discriminator_spec.rb +135 -0
- data/spec/public/property/float_spec.rb +22 -0
- data/spec/public/property/integer_spec.rb +22 -0
- data/spec/public/property/object_spec.rb +107 -0
- data/spec/public/property/serial_spec.rb +22 -0
- data/spec/public/property/string_spec.rb +22 -0
- data/spec/public/property/text_spec.rb +63 -0
- data/spec/public/property/time_spec.rb +22 -0
- data/spec/public/property_spec.rb +341 -0
- data/spec/public/resource_spec.rb +288 -0
- data/spec/public/sel_spec.rb +53 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +309 -0
- data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
- data/spec/public/shared/collection_shared_spec.rb +1667 -0
- data/spec/public/shared/finder_shared_spec.rb +1629 -0
- data/spec/rcov.opts +6 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
- data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
- data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +200 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +110 -0
- data/spec/semipublic/model_spec.rb +96 -0
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +47 -0
- data/spec/semipublic/property/class_spec.rb +33 -0
- data/spec/semipublic/property/date_spec.rb +43 -0
- data/spec/semipublic/property/date_time_spec.rb +46 -0
- data/spec/semipublic/property/decimal_spec.rb +83 -0
- data/spec/semipublic/property/discriminator_spec.rb +19 -0
- data/spec/semipublic/property/float_spec.rb +82 -0
- data/spec/semipublic/property/integer_spec.rb +82 -0
- data/spec/semipublic/property/lookup_spec.rb +29 -0
- data/spec/semipublic/property/serial_spec.rb +13 -0
- data/spec/semipublic/property/string_spec.rb +13 -0
- data/spec/semipublic/property/text_spec.rb +31 -0
- data/spec/semipublic/property/time_spec.rb +50 -0
- data/spec/semipublic/property_spec.rb +114 -0
- data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
- data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
- data/spec/semipublic/query/path_spec.rb +471 -0
- data/spec/semipublic/query_spec.rb +3682 -0
- data/spec/semipublic/resource/state/clean_spec.rb +88 -0
- data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +162 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
- data/spec/semipublic/resource/state/transient_spec.rb +162 -0
- data/spec/semipublic/resource/state_spec.rb +230 -0
- data/spec/semipublic/resource_spec.rb +23 -0
- data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
- data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/core_ext/hash.rb +10 -0
- data/spec/support/core_ext/inheritable_attributes.rb +46 -0
- data/spec/support/properties/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +23 -0
- data/spec/unit/blank_spec.rb +73 -0
- data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
- data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
- data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
- data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
- data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
- data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
- data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
- data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
- data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
- data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
- data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
- data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
- data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
- data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
- data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
- data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
- data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
- data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
- data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
- data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
- data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
- data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
- data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
- data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
- data/spec/unit/hash_spec.rb +28 -0
- data/spec/unit/hook_spec.rb +1235 -0
- data/spec/unit/inflections_spec.rb +16 -0
- data/spec/unit/lazy_array_spec.rb +1949 -0
- data/spec/unit/mash_spec.rb +312 -0
- data/spec/unit/module_spec.rb +71 -0
- data/spec/unit/object_spec.rb +38 -0
- data/spec/unit/try_dup_spec.rb +46 -0
- data/tasks/ci.rake +1 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +365 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe DataMapper::Model::Hook do
|
|
4
|
+
before :all do
|
|
5
|
+
class ::ModelHookSpecs
|
|
6
|
+
include DataMapper::Resource
|
|
7
|
+
|
|
8
|
+
property :id, Serial
|
|
9
|
+
property :value, Integer, :required => true, :default => 1
|
|
10
|
+
|
|
11
|
+
def an_instance_method
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class ::ModelHookSpecsSubclass < ModelHookSpecs; end
|
|
16
|
+
|
|
17
|
+
DataMapper.finalize
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
before :all do
|
|
21
|
+
@resource = ModelHookSpecs.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '#before' do
|
|
25
|
+
describe 'an instance method' do
|
|
26
|
+
before do
|
|
27
|
+
@hooks = hooks = []
|
|
28
|
+
ModelHookSpecs.before(:an_instance_method) { hooks << :before_instance_method }
|
|
29
|
+
|
|
30
|
+
@resource.an_instance_method
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should execute before instance method hook' do
|
|
34
|
+
@hooks.should == [ :before_instance_method ]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe 'save' do
|
|
39
|
+
supported_by :all do
|
|
40
|
+
before do
|
|
41
|
+
@hooks = hooks = []
|
|
42
|
+
ModelHookSpecs.before(:save) { hooks << :before_save }
|
|
43
|
+
|
|
44
|
+
@resource.save
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'should execute before save hook' do
|
|
48
|
+
@hooks.should == [ :before_save ]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe 'create' do
|
|
54
|
+
supported_by :all do
|
|
55
|
+
before do
|
|
56
|
+
@hooks = hooks = []
|
|
57
|
+
ModelHookSpecs.before(:create) { hooks << :before_create }
|
|
58
|
+
|
|
59
|
+
@resource.save
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should execute before create hook' do
|
|
63
|
+
@hooks.should == [ :before_create ]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe 'update' do
|
|
69
|
+
supported_by :all do
|
|
70
|
+
before do
|
|
71
|
+
@hooks = hooks = []
|
|
72
|
+
ModelHookSpecs.before(:update) { hooks << :before_update }
|
|
73
|
+
|
|
74
|
+
@resource.save
|
|
75
|
+
@resource.update(:value => 2)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'should execute before update hook' do
|
|
79
|
+
@hooks.should == [ :before_update ]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe 'destroy' do
|
|
85
|
+
supported_by :all do
|
|
86
|
+
before do
|
|
87
|
+
@hooks = hooks = []
|
|
88
|
+
ModelHookSpecs.before(:destroy) { hooks << :before_destroy }
|
|
89
|
+
|
|
90
|
+
@resource.save
|
|
91
|
+
@resource.destroy
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'should execute before destroy hook' do
|
|
95
|
+
@hooks.should == [ :before_destroy ]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe 'with an inherited hook' do
|
|
101
|
+
supported_by :all do
|
|
102
|
+
before do
|
|
103
|
+
@hooks = hooks = []
|
|
104
|
+
ModelHookSpecs.before(:an_instance_method) { hooks << :inherited_hook }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'should execute inherited hook' do
|
|
108
|
+
ModelHookSpecsSubclass.new.an_instance_method
|
|
109
|
+
@hooks.should == [ :inherited_hook ]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe 'with a hook declared in the subclasss' do
|
|
115
|
+
supported_by :all do
|
|
116
|
+
before do
|
|
117
|
+
@hooks = hooks = []
|
|
118
|
+
ModelHookSpecsSubclass.before(:an_instance_method) { hooks << :hook }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'should execute hook' do
|
|
122
|
+
ModelHookSpecsSubclass.new.an_instance_method
|
|
123
|
+
@hooks.should == [ :hook ]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'should not alter hooks in the parent class' do
|
|
127
|
+
@hooks.should be_empty
|
|
128
|
+
ModelHookSpecs.new.an_instance_method
|
|
129
|
+
@hooks.should == []
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe '#after' do
|
|
136
|
+
describe 'an instance method' do
|
|
137
|
+
before do
|
|
138
|
+
@hooks = hooks = []
|
|
139
|
+
ModelHookSpecs.after(:an_instance_method) { hooks << :after_instance_method }
|
|
140
|
+
|
|
141
|
+
@resource.an_instance_method
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'should execute after instance method hook' do
|
|
145
|
+
@hooks.should == [ :after_instance_method ]
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
describe 'save' do
|
|
150
|
+
supported_by :all do
|
|
151
|
+
before do
|
|
152
|
+
@hooks = hooks = []
|
|
153
|
+
ModelHookSpecs.after(:save) { hooks << :after_save }
|
|
154
|
+
|
|
155
|
+
@resource.save
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it 'should execute after save hook' do
|
|
159
|
+
@hooks.should == [ :after_save ]
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe 'create' do
|
|
165
|
+
supported_by :all do
|
|
166
|
+
before do
|
|
167
|
+
@hooks = hooks = []
|
|
168
|
+
ModelHookSpecs.after(:create) { hooks << :after_create }
|
|
169
|
+
|
|
170
|
+
@resource.save
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it 'should execute after create hook' do
|
|
174
|
+
@hooks.should == [ :after_create ]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
describe 'update' do
|
|
180
|
+
supported_by :all do
|
|
181
|
+
before do
|
|
182
|
+
@hooks = hooks = []
|
|
183
|
+
ModelHookSpecs.after(:update) { hooks << :after_update }
|
|
184
|
+
|
|
185
|
+
@resource.save
|
|
186
|
+
@resource.update(:value => 2)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'should execute after update hook' do
|
|
190
|
+
@hooks.should == [ :after_update ]
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe 'destroy' do
|
|
196
|
+
supported_by :all do
|
|
197
|
+
before do
|
|
198
|
+
@hooks = hooks = []
|
|
199
|
+
ModelHookSpecs.after(:destroy) { hooks << :after_destroy }
|
|
200
|
+
|
|
201
|
+
@resource.save
|
|
202
|
+
@resource.destroy
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'should execute after destroy hook' do
|
|
206
|
+
@hooks.should == [ :after_destroy ]
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
describe 'with an inherited hook' do
|
|
212
|
+
supported_by :all do
|
|
213
|
+
before do
|
|
214
|
+
@hooks = hooks = []
|
|
215
|
+
ModelHookSpecs.after(:an_instance_method) { hooks << :inherited_hook }
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it 'should execute inherited hook' do
|
|
219
|
+
ModelHookSpecsSubclass.new.an_instance_method
|
|
220
|
+
@hooks.should == [ :inherited_hook ]
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe 'with a hook declared in the subclasss' do
|
|
226
|
+
supported_by :all do
|
|
227
|
+
before do
|
|
228
|
+
@hooks = hooks = []
|
|
229
|
+
ModelHookSpecsSubclass.after(:an_instance_method) { hooks << :hook }
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it 'should execute hook' do
|
|
233
|
+
ModelHookSpecsSubclass.new.an_instance_method
|
|
234
|
+
@hooks.should == [ :hook ]
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'should not alter hooks in the parent class' do
|
|
238
|
+
@hooks.should be_empty
|
|
239
|
+
ModelHookSpecs.new.an_instance_method
|
|
240
|
+
@hooks.should == []
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples_for "a correct property declaration" do
|
|
4
|
+
it 'should define a name accessor' do
|
|
5
|
+
@model.should_not be_method_defined(@property_name)
|
|
6
|
+
subject
|
|
7
|
+
@model.should be_method_defined(@property_name)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'should define a name= mutator' do
|
|
11
|
+
@model.should_not be_method_defined(:"#{@property_name}=")
|
|
12
|
+
subject
|
|
13
|
+
@model.should be_method_defined(:"#{@property_name}=")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe DataMapper::Model::Property do
|
|
18
|
+
before do
|
|
19
|
+
Object.send(:remove_const, :ModelPropertySpecs) if defined?(ModelPropertySpecs)
|
|
20
|
+
class ::ModelPropertySpecs
|
|
21
|
+
include DataMapper::Resource
|
|
22
|
+
|
|
23
|
+
property :id, Serial
|
|
24
|
+
end
|
|
25
|
+
DataMapper.finalize
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#property' do
|
|
29
|
+
context "using default repository" do
|
|
30
|
+
before do
|
|
31
|
+
Object.send(:remove_const, :UserDefault) if defined?(::UserDefault)
|
|
32
|
+
|
|
33
|
+
class ::UserDefault
|
|
34
|
+
include DataMapper::Resource
|
|
35
|
+
property :id, Serial
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@model = ::UserDefault
|
|
39
|
+
@property_name = :name
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
subject do
|
|
43
|
+
::UserDefault.property(:name, String)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it_should_behave_like "a correct property declaration"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "using alternate repository" do
|
|
50
|
+
before do
|
|
51
|
+
Object.send(:remove_const, :UserAlternate) if defined?(::UserAlternate)
|
|
52
|
+
|
|
53
|
+
class ::UserAlternate
|
|
54
|
+
include DataMapper::Resource
|
|
55
|
+
property :id, Serial
|
|
56
|
+
repository(:alternate) { property :age, Integer }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@model = UserAlternate
|
|
60
|
+
@property_name = :alt_name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
subject do
|
|
64
|
+
::UserAlternate.property(:alt_name, String)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it_should_behave_like "a correct property declaration"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'should raise an exception if the method exists' do
|
|
71
|
+
lambda {
|
|
72
|
+
ModelPropertySpecs.property(:key, String)
|
|
73
|
+
}.should raise_error(ArgumentError, '+name+ was :key, which cannot be used as a property name since it collides with an existing method or a query option')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should raise an exception if the property is boolean and method with question mark already exists' do
|
|
77
|
+
lambda {
|
|
78
|
+
ModelPropertySpecs.property(:destroyed, DataMapper::Property::Boolean)
|
|
79
|
+
}.should raise_error(ArgumentError, '+name+ was :destroyed, which cannot be used as a property name since it collides with an existing method or a query option')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'should raise an exception if the name is the same as one of the query options' do
|
|
83
|
+
lambda {
|
|
84
|
+
ModelPropertySpecs.property(:order, String)
|
|
85
|
+
}.should raise_error(ArgumentError, '+name+ was :order, which cannot be used as a property name since it collides with an existing method or a query option')
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
require '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 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 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
|
+
@expected.should_not be_nil
|
|
282
|
+
|
|
283
|
+
# set the model scope to only return the first record
|
|
284
|
+
@model.default_scope.update(
|
|
285
|
+
Hash[ @model.key(@repository.name).zip(@expected.key) ]
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
@return = @car.model.get(*@car.key).__send__(@name)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it 'should return a Collection' do
|
|
292
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it 'should return expected Resources' do
|
|
296
|
+
@return.should == [ @expected ]
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
share_examples_for 'it creates a many mutator' do
|
|
303
|
+
describe 'mutator' do
|
|
304
|
+
describe 'when setting an Array of Resources' do
|
|
305
|
+
before :all do
|
|
306
|
+
@expected = [ @model.new ]
|
|
307
|
+
|
|
308
|
+
@return = @car.__send__("#{@name}=", @expected)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'should return the expected Collection' do
|
|
312
|
+
@return.should == @expected
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it 'should set the Collection' do
|
|
316
|
+
@car.__send__(@name).should == @expected
|
|
317
|
+
@car.__send__(@name).zip(@expected) { |value, expected| value.should equal(expected) }
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it 'should relate the associated Collection' do
|
|
321
|
+
pending_if Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
322
|
+
@expected.each { |resource| resource.car.should == @car }
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it 'should persist the Collection' do
|
|
327
|
+
@car.save.should be(true)
|
|
328
|
+
@car.model.get(*@car.key).__send__(@name).should == @expected
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it 'should persist the associated Resource' do
|
|
332
|
+
@car.save.should be(true)
|
|
333
|
+
@expected.each { |resource| resource.should be_saved }
|
|
334
|
+
@expected.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
describe 'when setting an Array of Hashes' do
|
|
339
|
+
before :all do
|
|
340
|
+
attributes = { :id => 11 }
|
|
341
|
+
@hashes = [ attributes ]
|
|
342
|
+
@expected = [ @model.new(attributes) ]
|
|
343
|
+
|
|
344
|
+
@return = @car.__send__("#{@name}=", @hashes)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it 'should return the expected Collection' do
|
|
348
|
+
@return.should == @expected
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
it 'should set the Collection' do
|
|
352
|
+
@car.__send__(@name).should == @return
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it 'should relate the associated Collection' do
|
|
356
|
+
pending_if Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
357
|
+
@return.each { |resource| resource.car.should == @car }
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
it 'should persist the Collection' do
|
|
362
|
+
@car.save.should be(true)
|
|
363
|
+
@car.model.get(*@car.key).__send__(@name).should == @return
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it 'should persist the associated Resource' do
|
|
367
|
+
@car.save.should be(true)
|
|
368
|
+
@return.each { |resource| resource.should be_saved }
|
|
369
|
+
@return.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
describe 'when setting an empty collection' do
|
|
374
|
+
before :all do
|
|
375
|
+
@car.__send__("#{@name}=", [ @model.new ])
|
|
376
|
+
|
|
377
|
+
@return = @car.__send__("#{@name}=", [])
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it 'should return a Collection' do
|
|
381
|
+
@return.should be_kind_of(DataMapper::Collection)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
it 'should set an empty Collection' do
|
|
385
|
+
@car.__send__(@name).should be_empty
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it 'should persist as an empty Collection' do
|
|
389
|
+
@car.save.should be(true)
|
|
390
|
+
@car.model.get(*@car.key).__send__(@name).should be_empty
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
describe 'when changing an associated collection' do
|
|
395
|
+
before :all do
|
|
396
|
+
@car.__send__("#{@name}=", [ @model.new ])
|
|
397
|
+
|
|
398
|
+
@expected = [ @model.new ]
|
|
399
|
+
|
|
400
|
+
@return = @car.__send__("#{@name}=", @expected)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
it 'should return the expected Resource' do
|
|
404
|
+
@return.should == @expected
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it 'should set the Resource' do
|
|
408
|
+
@car.__send__(@name).should == @expected
|
|
409
|
+
@car.__send__(@name).zip(@expected) { |value, expected| value.should equal(expected) }
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it 'should relate associated Resource' do
|
|
413
|
+
pending_if Car.relationships[@name].kind_of?(DataMapper::Associations::ManyToMany::Relationship) do
|
|
414
|
+
@expected.each { |resource| resource.car.should == @car }
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
it 'should persist the Resource' do
|
|
419
|
+
@car.save.should be(true)
|
|
420
|
+
@car.model.get(*@car.key).__send__(@name).should == @expected
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
it 'should persist the associated Resource' do
|
|
424
|
+
@car.save.should be(true)
|
|
425
|
+
@expected.each { |resource| resource.should be_saved }
|
|
426
|
+
@expected.each { |resource| resource.model.get(*resource.key).car.should == @car }
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
describe DataMapper::Associations do
|
|
433
|
+
before :all do
|
|
434
|
+
class ::Car
|
|
435
|
+
include DataMapper::Resource
|
|
436
|
+
|
|
437
|
+
property :id, Serial
|
|
438
|
+
property :name, String
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
class ::Engine
|
|
442
|
+
include DataMapper::Resource
|
|
443
|
+
|
|
444
|
+
property :id, Serial
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
class ::Door
|
|
448
|
+
include DataMapper::Resource
|
|
449
|
+
|
|
450
|
+
property :id, Serial
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
class ::Window
|
|
454
|
+
include DataMapper::Resource
|
|
455
|
+
|
|
456
|
+
property :id, Serial
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def n
|
|
461
|
+
1.0/0
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
it { Engine.should respond_to(:belongs_to) }
|
|
465
|
+
|
|
466
|
+
describe '#belongs_to' do
|
|
467
|
+
before :all do
|
|
468
|
+
@model = Engine
|
|
469
|
+
@name = :engine
|
|
470
|
+
|
|
471
|
+
Car.belongs_to(@name, :required => false)
|
|
472
|
+
Engine.has(1, :car)
|
|
473
|
+
DataMapper.finalize
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
supported_by :all do
|
|
477
|
+
before :all do
|
|
478
|
+
@car = Car.new
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
it { @car.should respond_to(@name) }
|
|
482
|
+
|
|
483
|
+
it_should_behave_like 'it creates a one accessor'
|
|
484
|
+
|
|
485
|
+
it { @car.should respond_to("#{@name}=") }
|
|
486
|
+
|
|
487
|
+
it_should_behave_like 'it creates a one mutator'
|
|
488
|
+
|
|
489
|
+
describe 'with a :key option' do
|
|
490
|
+
before :all do
|
|
491
|
+
@relationship = Car.belongs_to("#{@name}_with_key".to_sym, @model, :required => false, :key => true)
|
|
492
|
+
DataMapper.finalize
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
it 'should create a foreign key that is part of the key' do
|
|
496
|
+
@relationship.child_key.each do |property|
|
|
497
|
+
property.should be_key
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
describe 'with a :unique option' do
|
|
503
|
+
let(:unique) { [ :one, :two, :three ] }
|
|
504
|
+
|
|
505
|
+
before :all do
|
|
506
|
+
@relationship = Car.belongs_to("#{@name}_with_unique".to_sym, @model, :unique => unique)
|
|
507
|
+
DataMapper.finalize
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
it 'should create a foreign key that is unique' do
|
|
511
|
+
@relationship.child_key.each do |property|
|
|
512
|
+
property.should be_unique
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
it 'should create a foreign key that has a unique index' do
|
|
517
|
+
@relationship.child_key.each do |property|
|
|
518
|
+
property.unique_index.should equal(unique)
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# TODO: refactor these specs into above structure once they pass
|
|
525
|
+
describe 'pending query specs' do
|
|
526
|
+
before :all do
|
|
527
|
+
Car.has(1, :engine)
|
|
528
|
+
Engine.belongs_to(:car)
|
|
529
|
+
DataMapper.finalize
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
supported_by :all do
|
|
533
|
+
describe 'querying for a parent resource when only the foreign key is set' do
|
|
534
|
+
before :all do
|
|
535
|
+
# create a car that would be returned if the query is not
|
|
536
|
+
# scoped properly to retrieve @car
|
|
537
|
+
Car.create
|
|
538
|
+
|
|
539
|
+
@car = Car.create
|
|
540
|
+
engine = Engine.new(:car_id => @car.id)
|
|
541
|
+
|
|
542
|
+
@return = engine.car
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
it 'should return a Resource' do
|
|
546
|
+
@return.should be_kind_of(DataMapper::Resource)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it 'should return expected Resource' do
|
|
550
|
+
@return.should eql(@car)
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
describe 'querying for a parent resource' do
|
|
555
|
+
before :all do
|
|
556
|
+
@car = Car.create
|
|
557
|
+
@engine = Engine.create(:car => @car)
|
|
558
|
+
@resource = @engine.car(:id => @car.id)
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
it 'should return a Resource' do
|
|
562
|
+
@resource.should be_kind_of(DataMapper::Resource)
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
it 'should return expected Resource' do
|
|
566
|
+
@resource.should eql(@car)
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
describe 'querying for a parent resource that does not exist' do
|
|
571
|
+
before :all do
|
|
572
|
+
@car = Car.create
|
|
573
|
+
@engine = Engine.create(:car => @car)
|
|
574
|
+
@resource = @engine.car(:id.not => @car.id)
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it 'should return nil' do
|
|
578
|
+
@resource.should be_nil
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
describe 'changing the parent resource' do
|
|
583
|
+
before :all do
|
|
584
|
+
@car = Car.create
|
|
585
|
+
@engine = Engine.new
|
|
586
|
+
@engine.car = @car
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
it 'should set the associated foreign key' do
|
|
590
|
+
@engine.car_id.should == @car.id
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
it 'should add the engine object to the car' do
|
|
594
|
+
pending 'Changing a belongs_to parent should add the object to the correct association' do
|
|
595
|
+
@car.engines.should be_include(@engine)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
describe 'changing the parent foreign key' do
|
|
601
|
+
before :all do
|
|
602
|
+
@car = Car.create
|
|
603
|
+
|
|
604
|
+
@engine = Engine.new(:car_id => @car.id)
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
it 'should set the associated resource' do
|
|
608
|
+
@engine.car.should eql(@car)
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
describe 'changing an existing resource through the relation' do
|
|
613
|
+
before :all do
|
|
614
|
+
@car1 = Car.create
|
|
615
|
+
@car2 = Car.create
|
|
616
|
+
@engine = Engine.create(:car => @car1)
|
|
617
|
+
@engine.car = @car2
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
it 'should also change the foreign key' do
|
|
621
|
+
@engine.car_id.should == @car2.id
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
it 'should add the engine to the car' do
|
|
625
|
+
pending 'Changing a belongs_to parent should add the object to the correct association' do
|
|
626
|
+
@car2.engines.should be_include(@engine)
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
describe 'changing an existing resource through the relation' do
|
|
632
|
+
before :all do
|
|
633
|
+
@car1 = Car.create
|
|
634
|
+
@car2 = Car.create
|
|
635
|
+
@engine = Engine.create(:car => @car1)
|
|
636
|
+
@engine.car_id = @car2.id
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
it 'should also change the foreign key' do
|
|
640
|
+
@engine.car.should eql(@car2)
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
it 'should add the engine to the car' do
|
|
644
|
+
pending 'a change to the foreign key should also change the related object' do
|
|
645
|
+
@car2.engines.should be_include(@engine)
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
describe 'with a model' do
|
|
653
|
+
before :all do
|
|
654
|
+
Engine.belongs_to(:vehicle, Car)
|
|
655
|
+
DataMapper.finalize
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
it 'should set the relationship target model' do
|
|
659
|
+
Engine.relationships[:vehicle].target_model.should == Car
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
describe 'with a :model option' do
|
|
664
|
+
before :all do
|
|
665
|
+
Engine.belongs_to(:vehicle, :model => Car)
|
|
666
|
+
DataMapper.finalize
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
it 'should set the relationship target model' do
|
|
670
|
+
Engine.relationships[:vehicle].target_model.should == Car
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
describe 'with a single element as :child_key option' do
|
|
675
|
+
before :all do
|
|
676
|
+
Engine.belongs_to(:vehicle, :model => Car, :child_key => :bike_id)
|
|
677
|
+
DataMapper.finalize
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
it 'should set the relationship child key' do
|
|
681
|
+
Engine.relationships[:vehicle].child_key.map { |property| property.name }.should == [:bike_id]
|
|
682
|
+
end
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
describe 'with an array as :child_key option' do
|
|
686
|
+
before :all do
|
|
687
|
+
Engine.belongs_to(:vehicle, :model => Car, :child_key => [:bike_id])
|
|
688
|
+
DataMapper.finalize
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
it 'should set the relationship child key' do
|
|
692
|
+
Engine.relationships[:vehicle].child_key.map { |property| property.name }.should == [:bike_id]
|
|
693
|
+
end
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
describe 'with a single element as :parent_key option' do
|
|
697
|
+
before :all do
|
|
698
|
+
Engine.belongs_to(:vehicle, :model => Car, :parent_key => :name)
|
|
699
|
+
DataMapper.finalize
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
it 'should set the relationship parent key' do
|
|
703
|
+
Engine.relationships[:vehicle].parent_key.map { |property| property.name }.should == [:name]
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
describe 'with an array as :parent_key option' do
|
|
708
|
+
before :all do
|
|
709
|
+
Engine.belongs_to(:vehicle, :model => Car, :parent_key => [:name])
|
|
710
|
+
DataMapper.finalize
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
it 'should set the relationship parent key' do
|
|
714
|
+
Engine.relationships[:vehicle].parent_key.map { |property| property.name }.should == [:name]
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
it { Car.should respond_to(:has) }
|
|
720
|
+
|
|
721
|
+
describe '#has' do
|
|
722
|
+
describe '1' do
|
|
723
|
+
before :all do
|
|
724
|
+
@model = Engine
|
|
725
|
+
@name = :engine
|
|
726
|
+
|
|
727
|
+
Car.has(1, @name)
|
|
728
|
+
Engine.belongs_to(:car)
|
|
729
|
+
DataMapper.finalize
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
supported_by :all do
|
|
733
|
+
before :all do
|
|
734
|
+
@car = Car.new
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
it { @car.should respond_to(@name) }
|
|
738
|
+
|
|
739
|
+
it_should_behave_like 'it creates a one accessor'
|
|
740
|
+
|
|
741
|
+
it { @car.should respond_to("#{@name}=") }
|
|
742
|
+
|
|
743
|
+
it_should_behave_like 'it creates a one mutator'
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
describe '1 through' do
|
|
748
|
+
before :all do
|
|
749
|
+
@model = Engine
|
|
750
|
+
@name = :engine
|
|
751
|
+
|
|
752
|
+
Car.has(1, @name, :through => DataMapper::Resource)
|
|
753
|
+
Engine.has(1, :car, :through => DataMapper::Resource)
|
|
754
|
+
DataMapper.finalize
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
supported_by :all do
|
|
758
|
+
before :all do
|
|
759
|
+
@no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
|
|
760
|
+
defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
before :all do
|
|
764
|
+
@car = Car.new
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
before do
|
|
768
|
+
pending if @no_join
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
it { @car.should respond_to(@name) }
|
|
772
|
+
|
|
773
|
+
it_should_behave_like 'it creates a one accessor'
|
|
774
|
+
|
|
775
|
+
it { @car.should respond_to("#{@name}=") }
|
|
776
|
+
|
|
777
|
+
it_should_behave_like 'it creates a one mutator'
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
describe 'n..n' do
|
|
782
|
+
before :all do
|
|
783
|
+
@model = Door
|
|
784
|
+
@name = :doors
|
|
785
|
+
|
|
786
|
+
Car.has(1..4, @name)
|
|
787
|
+
Door.belongs_to(:car, :required => false)
|
|
788
|
+
DataMapper.finalize
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
supported_by :all do
|
|
792
|
+
before :all do
|
|
793
|
+
@car = Car.new
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
it { @car.should respond_to(@name) }
|
|
797
|
+
|
|
798
|
+
it_should_behave_like 'it creates a many accessor'
|
|
799
|
+
|
|
800
|
+
it { @car.should respond_to("#{@name}=") }
|
|
801
|
+
|
|
802
|
+
it_should_behave_like 'it creates a many mutator'
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
describe 'n..n through' do
|
|
807
|
+
before :all do
|
|
808
|
+
@model = Window
|
|
809
|
+
@name = :windows
|
|
810
|
+
|
|
811
|
+
Window.has(1, :car, :through => DataMapper::Resource)
|
|
812
|
+
Car.has(1..4, :windows, :through => DataMapper::Resource)
|
|
813
|
+
DataMapper.finalize
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
supported_by :all do
|
|
817
|
+
before :all do
|
|
818
|
+
@no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
|
|
819
|
+
defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
before :all do
|
|
823
|
+
@car = Car.new
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
before do
|
|
827
|
+
pending if @no_join
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
it { @car.should respond_to(@name) }
|
|
831
|
+
|
|
832
|
+
it_should_behave_like 'it creates a many accessor'
|
|
833
|
+
|
|
834
|
+
it { @car.should respond_to("#{@name}=") }
|
|
835
|
+
|
|
836
|
+
it_should_behave_like 'it creates a many mutator'
|
|
837
|
+
end
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
describe 'when the 3rd argument is a Model' do
|
|
841
|
+
before :all do
|
|
842
|
+
Car.has(1, :engine, Engine)
|
|
843
|
+
DataMapper.finalize
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
it 'should set the relationship target model' do
|
|
847
|
+
Car.relationships[:engine].target_model.should == Engine
|
|
848
|
+
end
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
describe 'when the 3rd argument is a String' do
|
|
852
|
+
before :all do
|
|
853
|
+
Car.has(1, :engine, 'Engine')
|
|
854
|
+
DataMapper.finalize
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
it 'should set the relationship target model' do
|
|
858
|
+
Car.relationships[:engine].target_model.should == Engine
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
it 'should raise an exception if the cardinality is not understood' do
|
|
863
|
+
lambda { Car.has(n..n, :doors) }.should raise_error(ArgumentError)
|
|
864
|
+
end
|
|
865
|
+
|
|
866
|
+
it 'should raise an exception if the minimum constraint is larger than the maximum' do
|
|
867
|
+
lambda { Car.has(2..1, :doors) }.should raise_error(ArgumentError)
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
describe 'property prefix inference' do
|
|
872
|
+
describe 'when a relationship has an inverse' do
|
|
873
|
+
before :all do
|
|
874
|
+
@engine_relationship = Car.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
875
|
+
DataMapper.finalize
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
supported_by :all do
|
|
879
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
880
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
881
|
+
end
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
describe 'when a relationship does not have an inverse' do
|
|
886
|
+
before :all do
|
|
887
|
+
@engine_relationship = Car.has(1, :engine)
|
|
888
|
+
DataMapper.finalize
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
supported_by :all do
|
|
892
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
893
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :car_id ]
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
describe 'when a relationship is inherited' do
|
|
899
|
+
describe 'has an inverse' do
|
|
900
|
+
before :all do
|
|
901
|
+
Car.property(:type, DataMapper::Property::Discriminator)
|
|
902
|
+
|
|
903
|
+
class ::ElectricCar < Car; end
|
|
904
|
+
|
|
905
|
+
Car.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
906
|
+
DataMapper.finalize
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
supported_by :all do
|
|
910
|
+
before :all do
|
|
911
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
it 'should have a source model equal to the ancestor' do
|
|
915
|
+
@engine_relationship.source_model.should equal(Car)
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
919
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
920
|
+
end
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
describe 'does not have an inverse' do
|
|
925
|
+
before :all do
|
|
926
|
+
Car.property(:type, DataMapper::Property::Discriminator)
|
|
927
|
+
|
|
928
|
+
class ::ElectricCar < Car; end
|
|
929
|
+
|
|
930
|
+
Car.has(1, :engine)
|
|
931
|
+
DataMapper.finalize
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
supported_by :all do
|
|
935
|
+
before :all do
|
|
936
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
it 'should have a source model equal to the ancestor' do
|
|
940
|
+
@engine_relationship.source_model.should equal(Car)
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
944
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :car_id ]
|
|
945
|
+
end
|
|
946
|
+
end
|
|
947
|
+
end
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
describe "when a subclass defines it's own relationship" do
|
|
951
|
+
describe 'has an inverse' do
|
|
952
|
+
before :all do
|
|
953
|
+
Car.property(:type, DataMapper::Property::Discriminator)
|
|
954
|
+
|
|
955
|
+
class ::ElectricCar < Car; end
|
|
956
|
+
|
|
957
|
+
ElectricCar.has(1, :engine, :inverse => Engine.belongs_to(:sports_car, Car))
|
|
958
|
+
DataMapper.finalize
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
supported_by :all do
|
|
962
|
+
before :all do
|
|
963
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
it 'should have a source model equal to the descendant' do
|
|
967
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
it 'should have a child key prefix the same as the inverse relationship' do
|
|
971
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :sports_car_id ]
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
describe 'does not have an inverse' do
|
|
977
|
+
before :all do
|
|
978
|
+
Car.property(:type, DataMapper::Property::Discriminator)
|
|
979
|
+
|
|
980
|
+
class ::ElectricCar < Car; end
|
|
981
|
+
|
|
982
|
+
ElectricCar.has(1, :engine)
|
|
983
|
+
DataMapper.finalize
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
supported_by :all do
|
|
987
|
+
before :all do
|
|
988
|
+
@engine_relationship = ElectricCar.relationships(@repository.name)[:engine]
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
it 'should have a source model equal to the descendant' do
|
|
992
|
+
@engine_relationship.source_model.should equal(ElectricCar)
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
it 'should have a child key prefix inferred from the source model name' do
|
|
996
|
+
@engine_relationship.child_key.map { |property| property.name }.should == [ :electric_car_id ]
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
end
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
describe 'child is also a parent' do
|
|
1004
|
+
before :all do
|
|
1005
|
+
class ::Employee
|
|
1006
|
+
include DataMapper::Resource
|
|
1007
|
+
|
|
1008
|
+
property :id, Serial
|
|
1009
|
+
property :name, String
|
|
1010
|
+
|
|
1011
|
+
belongs_to :company
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
class ::Company
|
|
1015
|
+
include DataMapper::Resource
|
|
1016
|
+
|
|
1017
|
+
property :id, Serial
|
|
1018
|
+
property :name, String
|
|
1019
|
+
|
|
1020
|
+
belongs_to :owner, Employee, :required => false
|
|
1021
|
+
has n, :employees
|
|
1022
|
+
end
|
|
1023
|
+
DataMapper.finalize
|
|
1024
|
+
end
|
|
1025
|
+
|
|
1026
|
+
supported_by :all do
|
|
1027
|
+
before :all do
|
|
1028
|
+
@company = Company.create(:name => 'ACME Inc.')
|
|
1029
|
+
@employee = @company.employees.create(:name => 'Wil E. Coyote')
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
it 'should save the child as a parent' do
|
|
1033
|
+
lambda {
|
|
1034
|
+
@company.owner = @employee
|
|
1035
|
+
@company.save.should be(true)
|
|
1036
|
+
}.should_not raise_error
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
end
|
|
1040
|
+
end
|