dm-core 0.10.2 → 1.0.0.rc1
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/.gitignore +10 -1
- data/Gemfile +143 -0
- data/Rakefile +9 -5
- data/VERSION +1 -1
- data/dm-core.gemspec +160 -57
- data/lib/dm-core.rb +131 -56
- data/lib/dm-core/adapters.rb +98 -14
- data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
- data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
- data/lib/dm-core/associations/many_to_many.rb +19 -30
- data/lib/dm-core/associations/many_to_one.rb +58 -42
- data/lib/dm-core/associations/one_to_many.rb +33 -23
- data/lib/dm-core/associations/one_to_one.rb +27 -11
- data/lib/dm-core/associations/relationship.rb +4 -4
- data/lib/dm-core/collection.rb +23 -16
- data/lib/dm-core/core_ext/array.rb +36 -0
- data/lib/dm-core/core_ext/hash.rb +30 -0
- data/lib/dm-core/core_ext/module.rb +46 -0
- data/lib/dm-core/core_ext/object.rb +31 -0
- data/lib/dm-core/core_ext/pathname.rb +20 -0
- data/lib/dm-core/core_ext/string.rb +22 -0
- data/lib/dm-core/core_ext/try_dup.rb +44 -0
- data/lib/dm-core/model.rb +88 -27
- data/lib/dm-core/model/hook.rb +75 -18
- data/lib/dm-core/model/property.rb +50 -9
- data/lib/dm-core/model/relationship.rb +31 -31
- data/lib/dm-core/model/scope.rb +3 -3
- data/lib/dm-core/property.rb +196 -516
- data/lib/dm-core/property/binary.rb +7 -0
- data/lib/dm-core/property/boolean.rb +35 -0
- data/lib/dm-core/property/class.rb +24 -0
- data/lib/dm-core/property/date.rb +47 -0
- data/lib/dm-core/property/date_time.rb +48 -0
- data/lib/dm-core/property/decimal.rb +43 -0
- data/lib/dm-core/property/discriminator.rb +48 -0
- data/lib/dm-core/property/float.rb +24 -0
- data/lib/dm-core/property/integer.rb +32 -0
- data/lib/dm-core/property/numeric.rb +43 -0
- data/lib/dm-core/property/object.rb +32 -0
- data/lib/dm-core/property/serial.rb +8 -0
- data/lib/dm-core/property/string.rb +49 -0
- data/lib/dm-core/property/text.rb +12 -0
- data/lib/dm-core/property/time.rb +48 -0
- data/lib/dm-core/property/typecast/numeric.rb +32 -0
- data/lib/dm-core/property/typecast/time.rb +28 -0
- data/lib/dm-core/property_set.rb +10 -4
- data/lib/dm-core/query.rb +14 -37
- data/lib/dm-core/query/conditions/comparison.rb +8 -6
- data/lib/dm-core/query/conditions/operation.rb +33 -2
- data/lib/dm-core/query/operator.rb +2 -5
- data/lib/dm-core/query/path.rb +4 -6
- data/lib/dm-core/repository.rb +21 -6
- data/lib/dm-core/resource.rb +316 -133
- data/lib/dm-core/resource/state.rb +79 -0
- data/lib/dm-core/resource/state/clean.rb +40 -0
- data/lib/dm-core/resource/state/deleted.rb +30 -0
- data/lib/dm-core/resource/state/dirty.rb +86 -0
- data/lib/dm-core/resource/state/immutable.rb +34 -0
- data/lib/dm-core/resource/state/persisted.rb +29 -0
- data/lib/dm-core/resource/state/transient.rb +70 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
- data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
- data/lib/dm-core/spec/setup.rb +165 -0
- data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
- data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
- data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/equalizer.rb +1 -0
- data/lib/dm-core/support/hook.rb +420 -0
- data/lib/dm-core/support/lazy_array.rb +453 -0
- data/lib/dm-core/support/local_object_space.rb +12 -0
- data/lib/dm-core/support/logger.rb +193 -6
- data/lib/dm-core/support/naming_conventions.rb +8 -8
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/type.rb +4 -0
- data/lib/dm-core/types/boolean.rb +2 -0
- data/lib/dm-core/types/decimal.rb +9 -0
- data/lib/dm-core/types/discriminator.rb +2 -0
- data/lib/dm-core/types/object.rb +3 -0
- data/lib/dm-core/types/serial.rb +2 -0
- data/lib/dm-core/types/text.rb +2 -0
- data/lib/dm-core/version.rb +1 -1
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
- data/spec/public/model/hook_spec.rb +209 -0
- data/spec/public/model/property_spec.rb +35 -0
- data/spec/public/model/relationship_spec.rb +33 -20
- data/spec/public/model_spec.rb +142 -10
- data/spec/public/property/binary_spec.rb +14 -0
- data/spec/public/property/boolean_spec.rb +14 -0
- data/spec/public/property/class_spec.rb +20 -0
- data/spec/public/property/date_spec.rb +14 -0
- data/spec/public/property/date_time_spec.rb +14 -0
- data/spec/public/property/decimal_spec.rb +14 -0
- data/spec/public/{types → property}/discriminator_spec.rb +2 -12
- data/spec/public/property/float_spec.rb +14 -0
- data/spec/public/property/integer_spec.rb +14 -0
- data/spec/public/property/object_spec.rb +9 -17
- data/spec/public/property/serial_spec.rb +14 -0
- data/spec/public/property/string_spec.rb +14 -0
- data/spec/public/property/text_spec.rb +52 -0
- data/spec/public/property/time_spec.rb +14 -0
- data/spec/public/property_spec.rb +28 -87
- data/spec/public/resource_spec.rb +101 -0
- data/spec/public/sel_spec.rb +5 -15
- data/spec/public/shared/collection_shared_spec.rb +16 -30
- data/spec/public/shared/finder_shared_spec.rb +2 -4
- data/spec/public/shared/property_shared_spec.rb +176 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
- data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
- data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
- data/spec/semipublic/associations/relationship_spec.rb +3 -3
- data/spec/semipublic/associations_spec.rb +1 -1
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +65 -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 +82 -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/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 +2 -532
- data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
- data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
- data/spec/semipublic/query/path_spec.rb +17 -17
- data/spec/semipublic/query_spec.rb +47 -78
- 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 +133 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
- data/spec/semipublic/resource/state/transient_spec.rb +128 -0
- data/spec/semipublic/resource/state_spec.rb +226 -0
- data/spec/semipublic/shared/property_shared_spec.rb +143 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
- data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec_helper.rb +21 -97
- data/spec/support/types/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +48 -0
- data/spec/unit/hash_spec.rb +35 -0
- data/spec/unit/hook_spec.rb +1234 -0
- data/spec/unit/lazy_array_spec.rb +1959 -0
- data/spec/unit/module_spec.rb +70 -0
- data/spec/unit/object_spec.rb +37 -0
- data/spec/unit/try_dup_spec.rb +45 -0
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- metadata +197 -71
- data/deps.rip +0 -2
- data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
- data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
- data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
- data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
- data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
- data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
- data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
- data/lib/dm-core/core_ext/enumerable.rb +0 -28
- data/lib/dm-core/migrations.rb +0 -1427
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
- data/lib/dm-core/transaction.rb +0 -508
- data/lib/dm-core/types/paranoid_boolean.rb +0 -42
- data/lib/dm-core/types/paranoid_datetime.rb +0 -41
- data/spec/lib/adapter_helpers.rb +0 -105
- data/spec/lib/collection_helpers.rb +0 -18
- data/spec/lib/pending_helpers.rb +0 -46
- data/spec/public/migrations_spec.rb +0 -503
- data/spec/public/transaction_spec.rb +0 -153
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -162,9 +162,9 @@ module DataMapper
|
|
162
162
|
namespace.const_get(name)
|
163
163
|
else
|
164
164
|
model = Model.new do
|
165
|
-
# all properties added to the anonymous through model are keys
|
165
|
+
# all properties added to the anonymous through model are keys
|
166
166
|
def property(name, type, options = {})
|
167
|
-
options[:key] = true
|
167
|
+
options[:key] = true
|
168
168
|
options.delete(:index)
|
169
169
|
super
|
170
170
|
end
|
@@ -196,7 +196,7 @@ module DataMapper
|
|
196
196
|
def through_relationship_name
|
197
197
|
if anonymous_through_model?
|
198
198
|
namespace = through_model_namespace_name.first
|
199
|
-
relationship_name =
|
199
|
+
relationship_name = ActiveSupport::Inflector.underscore(through_model.name.sub(/\A#{namespace.name}::/, '')).tr('/', '_')
|
200
200
|
relationship_name.pluralize.to_sym
|
201
201
|
else
|
202
202
|
options[:through]
|
@@ -302,20 +302,6 @@ module DataMapper
|
|
302
302
|
)
|
303
303
|
end
|
304
304
|
|
305
|
-
# Loads association targets and sets resulting value on
|
306
|
-
# given source resource
|
307
|
-
#
|
308
|
-
# @param [Resource] source
|
309
|
-
# the source resource for the association
|
310
|
-
#
|
311
|
-
# @return [undefined]
|
312
|
-
#
|
313
|
-
# @api private
|
314
|
-
def lazy_load(source)
|
315
|
-
# FIXME: delegate to super once SEL is enabled
|
316
|
-
set!(source, collection_for(source))
|
317
|
-
end
|
318
|
-
|
319
305
|
# Returns collection class used by this type of
|
320
306
|
# relationship
|
321
307
|
#
|
@@ -374,7 +360,10 @@ module DataMapper
|
|
374
360
|
return false
|
375
361
|
end
|
376
362
|
|
377
|
-
each
|
363
|
+
each do |resource|
|
364
|
+
resource.persisted_state = Resource::State::Immutable.new(resource)
|
365
|
+
end
|
366
|
+
|
378
367
|
clear
|
379
368
|
|
380
369
|
true
|
@@ -391,7 +380,7 @@ module DataMapper
|
|
391
380
|
source = self.source
|
392
381
|
|
393
382
|
@intermediaries ||= if through.loaded?(source)
|
394
|
-
through.
|
383
|
+
through.get_collection(source)
|
395
384
|
else
|
396
385
|
reset_intermediaries
|
397
386
|
end
|
@@ -422,27 +411,27 @@ module DataMapper
|
|
422
411
|
private
|
423
412
|
|
424
413
|
# @api private
|
425
|
-
def _create(
|
414
|
+
def _create(attributes, execute_hooks = true)
|
426
415
|
via = self.via
|
427
416
|
if via.respond_to?(:resource_for)
|
428
417
|
resource = super
|
429
|
-
if create_intermediary(
|
418
|
+
if create_intermediary(execute_hooks, resource)
|
430
419
|
resource
|
431
420
|
end
|
432
421
|
else
|
433
|
-
if intermediary = create_intermediary(
|
434
|
-
super(
|
422
|
+
if intermediary = create_intermediary(execute_hooks)
|
423
|
+
super(attributes.merge(via.inverse => intermediary), execute_hooks)
|
435
424
|
end
|
436
425
|
end
|
437
426
|
end
|
438
427
|
|
439
428
|
# @api private
|
440
|
-
def _save(
|
429
|
+
def _save(execute_hooks = true)
|
441
430
|
via = self.via
|
442
431
|
|
443
432
|
if @removed.any?
|
444
433
|
# delete only intermediaries linked to the removed targets
|
445
|
-
return false unless intermediaries.all(via => @removed).send(
|
434
|
+
return false unless intermediaries.all(via => @removed).send(execute_hooks ? :destroy : :destroy!)
|
446
435
|
|
447
436
|
# reset the intermediaries so that it reflects the current state of the datastore
|
448
437
|
reset_intermediaries
|
@@ -452,9 +441,9 @@ module DataMapper
|
|
452
441
|
|
453
442
|
if via.respond_to?(:resource_for)
|
454
443
|
super
|
455
|
-
loaded_entries.all? { |resource| create_intermediary(
|
444
|
+
loaded_entries.all? { |resource| create_intermediary(execute_hooks, resource) }
|
456
445
|
else
|
457
|
-
if intermediary = create_intermediary(
|
446
|
+
if loaded_entries.any? && (intermediary = create_intermediary(execute_hooks))
|
458
447
|
inverse = via.inverse
|
459
448
|
loaded_entries.each { |resource| inverse.set(resource, intermediary) }
|
460
449
|
end
|
@@ -464,14 +453,14 @@ module DataMapper
|
|
464
453
|
end
|
465
454
|
|
466
455
|
# @api private
|
467
|
-
def create_intermediary(
|
456
|
+
def create_intermediary(execute_hooks, resource = nil)
|
468
457
|
intermediary_for = self.intermediary_for
|
469
458
|
|
470
459
|
intermediary_resource = intermediary_for[resource]
|
471
460
|
return intermediary_resource if intermediary_resource
|
472
461
|
|
473
462
|
intermediaries = self.intermediaries
|
474
|
-
method =
|
463
|
+
method = execute_hooks ? :save : :save!
|
475
464
|
|
476
465
|
return unless intermediaries.send(method)
|
477
466
|
|
@@ -490,7 +479,7 @@ module DataMapper
|
|
490
479
|
through = self.through
|
491
480
|
source = self.source
|
492
481
|
|
493
|
-
through.
|
482
|
+
through.set_collection(source, through.collection_for(source))
|
494
483
|
end
|
495
484
|
|
496
485
|
# @api private
|
@@ -4,7 +4,7 @@ module DataMapper
|
|
4
4
|
# Relationship class with implementation specific
|
5
5
|
# to n side of 1 to n association
|
6
6
|
class Relationship < Associations::Relationship
|
7
|
-
OPTIONS = superclass::OPTIONS.dup << :required
|
7
|
+
OPTIONS = superclass::OPTIONS.dup << :required << :key
|
8
8
|
|
9
9
|
# @api semipublic
|
10
10
|
alias source_repository_name child_repository_name
|
@@ -26,6 +26,11 @@ module DataMapper
|
|
26
26
|
@required
|
27
27
|
end
|
28
28
|
|
29
|
+
# @api semipublic
|
30
|
+
def key?
|
31
|
+
@key
|
32
|
+
end
|
33
|
+
|
29
34
|
# @api private
|
30
35
|
def nullable?
|
31
36
|
klass = self.class
|
@@ -50,7 +55,7 @@ module DataMapper
|
|
50
55
|
properties[property_name] || begin
|
51
56
|
# create the property within the correct repository
|
52
57
|
DataMapper.repository(repository_name) do
|
53
|
-
type = parent_property.send(parent_property.type == DataMapper::
|
58
|
+
type = parent_property.send(parent_property.type == DataMapper::Property::Boolean ? :type : :primitive)
|
54
59
|
model.property(property_name, type, child_key_options(parent_property))
|
55
60
|
end
|
56
61
|
end
|
@@ -106,15 +111,15 @@ module DataMapper
|
|
106
111
|
# Query options
|
107
112
|
#
|
108
113
|
# @api semipublic
|
109
|
-
def get(source,
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
def get(source, query = nil)
|
115
|
+
lazy_load(source)
|
116
|
+
collection = get_collection(source)
|
117
|
+
collection.first(query) if collection
|
118
|
+
end
|
113
119
|
|
120
|
+
def get_collection(source)
|
114
121
|
resource = get!(source)
|
115
|
-
|
116
|
-
resource
|
117
|
-
end
|
122
|
+
resource.collection_for_self if resource
|
118
123
|
end
|
119
124
|
|
120
125
|
# Sets value of association target (ex.: author) for given source resource
|
@@ -128,36 +133,14 @@ module DataMapper
|
|
128
133
|
#
|
129
134
|
# @api semipublic
|
130
135
|
def set(source, target)
|
131
|
-
|
132
|
-
|
133
|
-
assert_kind_of 'source', source, source_model
|
134
|
-
assert_kind_of 'target', target, target_model, Hash, NilClass
|
135
|
-
|
136
|
-
if target.kind_of?(Hash)
|
137
|
-
target = target_model.new(target)
|
138
|
-
end
|
139
|
-
|
140
|
-
source_key.set(source, target.nil? ? [] : target_key.get(target))
|
136
|
+
target = typecast(target)
|
137
|
+
source_key.set(source, target_key.get(target))
|
141
138
|
set!(source, target)
|
142
139
|
end
|
143
140
|
|
144
|
-
private
|
145
|
-
|
146
|
-
# Initializes the relationship, always using max cardinality of 1.
|
147
|
-
#
|
148
141
|
# @api semipublic
|
149
|
-
def
|
150
|
-
|
151
|
-
nullable_options = options.only(:nullable)
|
152
|
-
required_options = { :required => !options.delete(:nullable) }
|
153
|
-
warn "#{nullable_options.inspect} is deprecated, use #{required_options.inspect} instead (#{caller[2]})"
|
154
|
-
options.update(required_options)
|
155
|
-
end
|
156
|
-
|
157
|
-
@required = options.fetch(:required, true)
|
158
|
-
target_model ||= Extlib::Inflection.camelize(name)
|
159
|
-
options = { :min => @required ? 1 : 0, :max => 1 }.update(options)
|
160
|
-
super
|
142
|
+
def default_for(source)
|
143
|
+
typecast(super)
|
161
144
|
end
|
162
145
|
|
163
146
|
# Loads association target and sets resulting value on
|
@@ -170,7 +153,7 @@ module DataMapper
|
|
170
153
|
#
|
171
154
|
# @api private
|
172
155
|
def lazy_load(source)
|
173
|
-
return
|
156
|
+
return if loaded?(source) || !valid_source?(source)
|
174
157
|
|
175
158
|
# SEL: load all related resources in the source collection
|
176
159
|
collection = source.collection
|
@@ -183,6 +166,26 @@ module DataMapper
|
|
183
166
|
end
|
184
167
|
end
|
185
168
|
|
169
|
+
private
|
170
|
+
|
171
|
+
# Initializes the relationship, always using max cardinality of 1.
|
172
|
+
#
|
173
|
+
# @api semipublic
|
174
|
+
def initialize(name, source_model, target_model, options = {})
|
175
|
+
if options.key?(:nullable)
|
176
|
+
nullable_options = options.only(:nullable)
|
177
|
+
required_options = { :required => !options.delete(:nullable) }
|
178
|
+
warn "#{nullable_options.inspect} is deprecated, use #{required_options.inspect} instead (#{caller[2]})"
|
179
|
+
options.update(required_options)
|
180
|
+
end
|
181
|
+
|
182
|
+
@required = options.fetch(:required, true)
|
183
|
+
@key = options.fetch(:key, false)
|
184
|
+
target_model ||= ActiveSupport::Inflector.camelize(name)
|
185
|
+
options = { :min => @required ? 1 : 0, :max => 1 }.update(options)
|
186
|
+
super
|
187
|
+
end
|
188
|
+
|
186
189
|
# Sets the association targets in the resource
|
187
190
|
#
|
188
191
|
# @param [Resource] source
|
@@ -199,6 +202,15 @@ module DataMapper
|
|
199
202
|
set(source, targets.first)
|
200
203
|
end
|
201
204
|
|
205
|
+
# @api private
|
206
|
+
def typecast(target)
|
207
|
+
if target.kind_of?(Hash)
|
208
|
+
target_model.new(target)
|
209
|
+
else
|
210
|
+
target
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
202
214
|
# Returns the inverse relationship class
|
203
215
|
#
|
204
216
|
# @api private
|
@@ -210,18 +222,22 @@ module DataMapper
|
|
210
222
|
#
|
211
223
|
# @api private
|
212
224
|
def inverse_name
|
213
|
-
super ||
|
225
|
+
super || ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(source_model.name)).pluralize.to_sym
|
214
226
|
end
|
215
227
|
|
216
228
|
# @api private
|
217
229
|
def child_key_options(parent_property)
|
218
|
-
options = parent_property.options.only(:length, :precision, :scale).update(
|
230
|
+
options = parent_property.options.only(:length, :precision, :scale).update(
|
231
|
+
:index => name,
|
232
|
+
:required => required?,
|
233
|
+
:key => key?
|
234
|
+
)
|
219
235
|
|
220
|
-
|
221
|
-
|
236
|
+
if parent_property.primitive == Integer
|
237
|
+
min = parent_property.min
|
238
|
+
max = parent_property.max
|
222
239
|
|
223
|
-
|
224
|
-
options.update(:min => min, :max => max)
|
240
|
+
options.update(:min => min, :max => max) if min && max
|
225
241
|
end
|
226
242
|
|
227
243
|
options
|
@@ -43,8 +43,8 @@ module DataMapper
|
|
43
43
|
collection.relationship = self
|
44
44
|
collection.source = source
|
45
45
|
|
46
|
-
# make the collection empty if the source is
|
47
|
-
collection.replace([])
|
46
|
+
# make the collection empty if the source is new
|
47
|
+
collection.replace([]) if source.new?
|
48
48
|
|
49
49
|
collection
|
50
50
|
end
|
@@ -53,13 +53,15 @@ module DataMapper
|
|
53
53
|
# (ex.: author)
|
54
54
|
#
|
55
55
|
# @api semipublic
|
56
|
-
def get(source,
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
def get(source, query = nil)
|
57
|
+
lazy_load(source)
|
58
|
+
collection = get_collection(source)
|
59
|
+
query ? collection.all(query) : collection
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
# @api private
|
63
|
+
def get_collection(source)
|
64
|
+
get!(source)
|
63
65
|
end
|
64
66
|
|
65
67
|
# Sets value of association targets (ex.: paragraphs) for given source resource
|
@@ -67,21 +69,13 @@ module DataMapper
|
|
67
69
|
#
|
68
70
|
# @api semipublic
|
69
71
|
def set(source, targets)
|
70
|
-
|
71
|
-
assert_kind_of 'targets', targets, Array
|
72
|
-
|
73
|
-
lazy_load(source) unless loaded?(source)
|
74
|
-
|
72
|
+
lazy_load(source)
|
75
73
|
get!(source).replace(targets)
|
76
74
|
end
|
77
75
|
|
78
|
-
private
|
79
|
-
|
80
|
-
|
81
|
-
def initialize(name, target_model, source_model, options = {})
|
82
|
-
target_model ||= Extlib::Inflection.camelize(name.to_s.singular)
|
83
|
-
options = { :min => 0, :max => source_model.n }.update(options)
|
84
|
-
super
|
76
|
+
# @api private
|
77
|
+
def set_collection(source, target)
|
78
|
+
set!(source, target)
|
85
79
|
end
|
86
80
|
|
87
81
|
# Loads association targets and sets resulting value on
|
@@ -94,6 +88,8 @@ module DataMapper
|
|
94
88
|
#
|
95
89
|
# @api private
|
96
90
|
def lazy_load(source)
|
91
|
+
return if loaded?(source)
|
92
|
+
|
97
93
|
# SEL: load all related resources in the source collection
|
98
94
|
collection = source.collection
|
99
95
|
if source.saved? && collection.size > 1
|
@@ -105,6 +101,20 @@ module DataMapper
|
|
105
101
|
end
|
106
102
|
end
|
107
103
|
|
104
|
+
# @api semipublic
|
105
|
+
def default_for(source)
|
106
|
+
collection_for(source).replace(Array(super))
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# @api semipublic
|
112
|
+
def initialize(name, target_model, source_model, options = {})
|
113
|
+
target_model ||= ActiveSupport::Inflector.camelize(name.to_s.singularize)
|
114
|
+
options = { :min => 0, :max => source_model.n }.update(options)
|
115
|
+
super
|
116
|
+
end
|
117
|
+
|
108
118
|
# Sets the association targets in the resource
|
109
119
|
#
|
110
120
|
# @param [Resource] source
|
@@ -140,7 +150,7 @@ module DataMapper
|
|
140
150
|
#
|
141
151
|
# @api private
|
142
152
|
def inverse_name
|
143
|
-
super ||
|
153
|
+
super || ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(source_model.name)).to_sym
|
144
154
|
end
|
145
155
|
|
146
156
|
# @api private
|
@@ -257,11 +267,11 @@ module DataMapper
|
|
257
267
|
end
|
258
268
|
|
259
269
|
# @api private
|
260
|
-
def _save(
|
270
|
+
def _save(execute_hooks = true)
|
261
271
|
assert_source_saved 'The source must be saved before saving the collection'
|
262
272
|
|
263
273
|
# update removed resources to not reference the source
|
264
|
-
@removed.all? { |resource| resource.destroyed? || resource.__send__(
|
274
|
+
@removed.all? { |resource| resource.destroyed? || resource.__send__(execute_hooks ? :save : :save!) } && super
|
265
275
|
end
|
266
276
|
|
267
277
|
# @api private
|
@@ -3,8 +3,11 @@ module DataMapper
|
|
3
3
|
module OneToOne #:nodoc:
|
4
4
|
class Relationship < Associations::Relationship
|
5
5
|
%w[ public protected private ].map do |visibility|
|
6
|
-
superclass.send("#{visibility}_instance_methods", false)
|
7
|
-
|
6
|
+
methods = superclass.send("#{visibility}_instance_methods", false) |
|
7
|
+
DataMapper::Subject.send("#{visibility}_instance_methods", false)
|
8
|
+
|
9
|
+
methods.each do |method|
|
10
|
+
undef_method method.to_sym unless method.to_s == 'initialize'
|
8
11
|
end
|
9
12
|
end
|
10
13
|
|
@@ -12,12 +15,16 @@ module DataMapper
|
|
12
15
|
# for given source
|
13
16
|
#
|
14
17
|
# @api semipublic
|
15
|
-
def get(source,
|
16
|
-
|
17
|
-
|
18
|
-
return unless loaded?(source) || valid_source?(source)
|
18
|
+
def get(source, query = nil)
|
19
|
+
relationship.get(source, query).first
|
20
|
+
end
|
19
21
|
|
20
|
-
|
22
|
+
# Get the resource directly
|
23
|
+
#
|
24
|
+
# @api semipublic
|
25
|
+
def get!(source)
|
26
|
+
collection = relationship.get!(source)
|
27
|
+
collection.first if collection
|
21
28
|
end
|
22
29
|
|
23
30
|
# Sets and returns association target
|
@@ -25,12 +32,21 @@ module DataMapper
|
|
25
32
|
#
|
26
33
|
# @api semipublic
|
27
34
|
def set(source, target)
|
28
|
-
assert_kind_of 'source', source, source_model
|
29
|
-
assert_kind_of 'target', target, target_model, Hash, NilClass
|
30
|
-
|
31
35
|
relationship.set(source, [ target ].compact).first
|
32
36
|
end
|
33
37
|
|
38
|
+
# Sets the resource directly
|
39
|
+
#
|
40
|
+
# @api semipublic
|
41
|
+
def set!(source, target)
|
42
|
+
set(source, target)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api semipublic
|
46
|
+
def default_for(source)
|
47
|
+
relationship.default_for(source).first
|
48
|
+
end
|
49
|
+
|
34
50
|
# @api public
|
35
51
|
def kind_of?(klass)
|
36
52
|
super || relationship.kind_of?(klass)
|
@@ -56,7 +72,7 @@ module DataMapper
|
|
56
72
|
# @api semipublic
|
57
73
|
def initialize(name, target_model, source_model, options = {})
|
58
74
|
klass = options.key?(:through) ? ManyToMany::Relationship : OneToMany::Relationship
|
59
|
-
target_model ||=
|
75
|
+
target_model ||= ActiveSupport::Inflector.camelize(name).freeze
|
60
76
|
@relationship = klass.new(name, target_model, source_model, options)
|
61
77
|
end
|
62
78
|
|