dm-core 1.0.0 → 1.0.1
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 +1 -0
- data/Gemfile +19 -20
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/dm-core.gemspec +15 -12
- data/lib/dm-core.rb +23 -14
- data/lib/dm-core/adapters.rb +7 -3
- data/lib/dm-core/adapters/abstract_adapter.rb +3 -9
- data/lib/dm-core/associations/many_to_many.rb +1 -1
- data/lib/dm-core/associations/many_to_one.rb +3 -4
- data/lib/dm-core/associations/one_to_many.rb +2 -2
- data/lib/dm-core/associations/one_to_one.rb +1 -1
- data/lib/dm-core/collection.rb +4 -6
- data/lib/dm-core/model.rb +22 -32
- data/lib/dm-core/model/property.rb +15 -39
- data/lib/dm-core/property.rb +75 -87
- data/lib/dm-core/property/discriminator.rb +3 -3
- data/lib/dm-core/property/lookup.rb +42 -0
- data/lib/dm-core/property/object.rb +5 -0
- data/lib/dm-core/property/serial.rb +6 -1
- data/lib/dm-core/query/conditions/comparison.rb +3 -3
- data/lib/dm-core/query/conditions/operation.rb +3 -3
- data/lib/dm-core/resource.rb +2 -2
- data/lib/dm-core/resource/state/dirty.rb +2 -2
- data/lib/dm-core/spec/lib/spec_helper.rb +11 -3
- data/lib/dm-core/spec/setup.rb +2 -2
- data/{spec/public/shared/property_shared_spec.rb → lib/dm-core/spec/shared/public/property_spec.rb} +51 -20
- data/{spec/semipublic/shared/property_shared_spec.rb → lib/dm-core/spec/shared/semipublic/property_spec.rb} +22 -26
- data/lib/dm-core/support/descendant_set.rb +84 -0
- data/lib/dm-core/support/naming_conventions.rb +8 -8
- data/lib/dm-core/types/discriminator.rb +2 -2
- data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
- data/spec/public/finalize_spec.rb +42 -11
- data/spec/public/property/discriminator_spec.rb +6 -6
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
- data/spec/semipublic/property/lookup_spec.rb +26 -0
- data/spec/semipublic/property_spec.rb +43 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +4 -2
- data/spec/support/{types → properties}/huge_integer.rb +5 -5
- data/tasks/local_gemfile.rake +5 -7
- metadata +15 -19
- data/lib/dm-core/model/descendant_set.rb +0 -81
data/lib/dm-core/collection.rb
CHANGED
@@ -65,9 +65,9 @@ module DataMapper
|
|
65
65
|
# @return [self]
|
66
66
|
#
|
67
67
|
# @api public
|
68
|
-
def reload(other_query =
|
68
|
+
def reload(other_query = Undefined)
|
69
69
|
query = self.query
|
70
|
-
query = other_query.
|
70
|
+
query = other_query.equal?(Undefined) ? query.dup : query.merge(other_query)
|
71
71
|
|
72
72
|
# make sure the Identity Map contains all the existing resources
|
73
73
|
identity_map = repository.identity_map(model)
|
@@ -214,10 +214,8 @@ module DataMapper
|
|
214
214
|
# Collection scoped by +query+
|
215
215
|
#
|
216
216
|
# @api public
|
217
|
-
def all(query =
|
218
|
-
|
219
|
-
# accept a Hash/Query and nothing else
|
220
|
-
if query.nil? || (query.kind_of?(Hash) && query.empty?)
|
217
|
+
def all(query = Undefined)
|
218
|
+
if query.equal?(Undefined) || (query.kind_of?(Hash) && query.empty?)
|
221
219
|
dup
|
222
220
|
else
|
223
221
|
# TODO: if there is no order parameter, and the Collection is not loaded
|
data/lib/dm-core/model.rb
CHANGED
@@ -35,7 +35,7 @@ module DataMapper
|
|
35
35
|
warn "Passing in +storage_name+ to #{name}.new is deprecated (#{caller[0]})"
|
36
36
|
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
37
37
|
def self.default_storage_name
|
38
|
-
#{
|
38
|
+
#{DataMapper::Inflector.classify(storage_name).inspect}.freeze
|
39
39
|
end
|
40
40
|
RUBY
|
41
41
|
end
|
@@ -75,7 +75,9 @@ module DataMapper
|
|
75
75
|
# Set containing the descendant classes
|
76
76
|
#
|
77
77
|
# @api semipublic
|
78
|
-
|
78
|
+
def descendants
|
79
|
+
@descendants ||= DescendantSet.new
|
80
|
+
end
|
79
81
|
|
80
82
|
# Return if Resource#save should raise an exception on save failures (globally)
|
81
83
|
#
|
@@ -203,35 +205,29 @@ module DataMapper
|
|
203
205
|
end
|
204
206
|
|
205
207
|
# @api private
|
206
|
-
def self.extended(
|
207
|
-
descendants
|
208
|
+
def self.extended(descendant)
|
209
|
+
descendants << descendant
|
208
210
|
|
209
|
-
|
211
|
+
descendant.instance_variable_set(:@valid, false)
|
212
|
+
descendant.instance_variable_set(:@base_model, descendant)
|
213
|
+
descendant.instance_variable_set(:@storage_names, {})
|
214
|
+
descendant.instance_variable_set(:@default_order, {})
|
210
215
|
|
211
|
-
|
212
|
-
model.instance_variable_set(:@base_model, model)
|
213
|
-
model.instance_variable_set(:@storage_names, {})
|
214
|
-
model.instance_variable_set(:@default_order, {})
|
215
|
-
model.instance_variable_set(:@descendants, descendants.class.new(model, descendants))
|
216
|
+
descendant.extend(Chainable)
|
216
217
|
|
217
|
-
|
218
|
-
|
219
|
-
extra_extensions.each { |mod| model.extend(mod) }
|
220
|
-
extra_inclusions.each { |mod| model.send(:include, mod) }
|
218
|
+
extra_extensions.each { |mod| descendant.extend(mod) }
|
219
|
+
extra_inclusions.each { |mod| descendant.send(:include, mod) }
|
221
220
|
end
|
222
221
|
|
223
222
|
# @api private
|
224
223
|
chainable do
|
225
|
-
def inherited(
|
226
|
-
descendants
|
227
|
-
|
228
|
-
descendants << model
|
224
|
+
def inherited(descendant)
|
225
|
+
descendants << descendant
|
229
226
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
model.instance_variable_set(:@descendants, descendants.class.new(model, descendants))
|
227
|
+
descendant.instance_variable_set(:@valid, false)
|
228
|
+
descendant.instance_variable_set(:@base_model, base_model)
|
229
|
+
descendant.instance_variable_set(:@storage_names, @storage_names.dup)
|
230
|
+
descendant.instance_variable_set(:@default_order, @default_order.dup)
|
235
231
|
end
|
236
232
|
end
|
237
233
|
|
@@ -250,7 +246,7 @@ module DataMapper
|
|
250
246
|
# the names of the storage receptacles for this resource across all repositories
|
251
247
|
#
|
252
248
|
# @return [Hash(Symbol => String)]
|
253
|
-
# All available names of storage
|
249
|
+
# All available names of storage receptacles
|
254
250
|
#
|
255
251
|
# @api public
|
256
252
|
def storage_names
|
@@ -339,10 +335,8 @@ module DataMapper
|
|
339
335
|
# @see Collection
|
340
336
|
#
|
341
337
|
# @api public
|
342
|
-
def all(query =
|
343
|
-
|
344
|
-
# accept a Hash/Query and nothing else
|
345
|
-
if query.nil? || (query.kind_of?(Hash) && query.empty?)
|
338
|
+
def all(query = Undefined)
|
339
|
+
if query.equal?(Undefined) || (query.kind_of?(Hash) && query.empty?)
|
346
340
|
# TODO: after adding Enumerable methods to Model, try to return self here
|
347
341
|
new_collection(self.query.dup)
|
348
342
|
else
|
@@ -726,10 +720,6 @@ module DataMapper
|
|
726
720
|
self
|
727
721
|
elsif name == :Resource
|
728
722
|
Resource
|
729
|
-
elsif DataMapper::Property.const_defined?(name)
|
730
|
-
DataMapper::Property.const_get(name)
|
731
|
-
elsif DataMapper::Types.const_defined?(name)
|
732
|
-
DataMapper::Types.const_get(name)
|
733
723
|
else
|
734
724
|
super
|
735
725
|
end
|
@@ -7,7 +7,7 @@
|
|
7
7
|
module DataMapper
|
8
8
|
module Model
|
9
9
|
module Property
|
10
|
-
Model.append_extensions self
|
10
|
+
Model.append_extensions self, DataMapper::Property::Lookup
|
11
11
|
|
12
12
|
extend Chainable
|
13
13
|
|
@@ -60,28 +60,13 @@ module DataMapper
|
|
60
60
|
|
61
61
|
# if the type can be found within Property then
|
62
62
|
# use that class rather than the primitive
|
63
|
-
|
64
|
-
unless type_name.blank?
|
65
|
-
type_name = ActiveSupport::Inflector.demodulize(type_name)
|
66
|
-
|
67
|
-
if DataMapper::Property.const_defined?(type_name)
|
68
|
-
type = DataMapper::Property.find_const(type_name)
|
69
|
-
elsif DataMapper::Types.const_defined?(type_name)
|
70
|
-
type = DataMapper::Types.find_const(type_name)
|
71
|
-
end
|
72
|
-
end
|
63
|
+
klass = DataMapper::Property.determine_class(type)
|
73
64
|
|
74
|
-
unless
|
65
|
+
unless klass
|
75
66
|
raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type"
|
76
67
|
end
|
77
68
|
|
78
|
-
|
79
|
-
type
|
80
|
-
else
|
81
|
-
DataMapper::Property.find_const(ActiveSupport::Inflector.demodulize(type.primitive.name))
|
82
|
-
end
|
83
|
-
|
84
|
-
property = klass.new(self, name, options, type)
|
69
|
+
property = klass.new(self, name, options, type < DataMapper::Type ? type : nil)
|
85
70
|
|
86
71
|
repository_name = self.repository_name
|
87
72
|
properties = properties(repository_name)
|
@@ -187,7 +172,7 @@ module DataMapper
|
|
187
172
|
|
188
173
|
# @api private
|
189
174
|
def properties_with_subclasses(repository_name = default_repository_name)
|
190
|
-
properties =
|
175
|
+
properties = properties(repository_name).dup
|
191
176
|
|
192
177
|
descendants.each do |model|
|
193
178
|
model.properties(repository_name).each do |property|
|
@@ -223,22 +208,20 @@ module DataMapper
|
|
223
208
|
reader_visibility = property.reader_visibility
|
224
209
|
instance_variable_name = property.instance_variable_name
|
225
210
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
#{instance_variable_name} = property ? persisted_state.get(property) : nil
|
234
|
-
end
|
211
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
212
|
+
chainable do
|
213
|
+
#{reader_visibility}
|
214
|
+
def #{name}
|
215
|
+
return #{instance_variable_name} if defined?(#{instance_variable_name})
|
216
|
+
property = properties[#{name.inspect}]
|
217
|
+
#{instance_variable_name} = property ? persisted_state.get(property) : nil
|
235
218
|
end
|
236
|
-
|
237
|
-
|
219
|
+
end
|
220
|
+
RUBY
|
238
221
|
|
239
222
|
boolean_reader_name = "#{name}?"
|
240
223
|
|
241
|
-
if property.kind_of?(DataMapper::Property::Boolean)
|
224
|
+
if property.kind_of?(DataMapper::Property::Boolean)
|
242
225
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
243
226
|
chainable do
|
244
227
|
#{reader_visibility}
|
@@ -259,8 +242,6 @@ module DataMapper
|
|
259
242
|
|
260
243
|
writer_name = "#{name}="
|
261
244
|
|
262
|
-
return if reserved_method?(writer_name)
|
263
|
-
|
264
245
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
265
246
|
chainable do
|
266
247
|
#{writer_visibility}
|
@@ -273,11 +254,6 @@ module DataMapper
|
|
273
254
|
RUBY
|
274
255
|
end
|
275
256
|
|
276
|
-
# @api private
|
277
|
-
def reserved_method?(name)
|
278
|
-
method_defined?(name) && !%w[ id type ].include?(name)
|
279
|
-
end
|
280
|
-
|
281
257
|
chainable do
|
282
258
|
# @api public
|
283
259
|
def method_missing(method, *args, &block)
|
data/lib/dm-core/property.rb
CHANGED
@@ -292,7 +292,7 @@ module DataMapper
|
|
292
292
|
# @api semipublic
|
293
293
|
def load(value)
|
294
294
|
unless value.nil?
|
295
|
-
value =
|
295
|
+
value = type.load(value, self) if type
|
296
296
|
typecast(value)
|
297
297
|
else
|
298
298
|
value
|
@@ -307,8 +307,8 @@ module DataMapper
|
|
307
307
|
#
|
308
308
|
# @api semipublic
|
309
309
|
def dump(value)
|
310
|
-
if
|
311
|
-
|
310
|
+
if type
|
311
|
+
type.dump(value, self)
|
312
312
|
else
|
313
313
|
value
|
314
314
|
end
|
@@ -354,9 +354,53 @@ module DataMapper
|
|
354
354
|
:default, :repository_name, :allow_nil, :allow_blank, :required
|
355
355
|
|
356
356
|
class << self
|
357
|
+
extend Deprecate
|
358
|
+
|
359
|
+
deprecate :all_descendants, :descendants
|
360
|
+
|
361
|
+
# @api semipublic
|
362
|
+
def determine_class(type)
|
363
|
+
if type < DataMapper::Property::Object
|
364
|
+
return type
|
365
|
+
end
|
366
|
+
|
367
|
+
name = DataMapper::Inflector.demodulize(type.name)
|
368
|
+
klass = find_class(name)
|
369
|
+
|
370
|
+
if !klass && type < DataMapper::Type
|
371
|
+
klass = find_class(type.primitive.name)
|
372
|
+
end
|
373
|
+
|
374
|
+
klass
|
375
|
+
end
|
376
|
+
|
377
|
+
# @api semipublic
|
378
|
+
def find_class(name)
|
379
|
+
klass = descendants.detect do |descendant|
|
380
|
+
DataMapper::Inflector.demodulize(descendant.name) == name
|
381
|
+
end
|
382
|
+
|
383
|
+
if !klass && const_defined?(name)
|
384
|
+
klass = const_get(name)
|
385
|
+
end
|
386
|
+
|
387
|
+
klass
|
388
|
+
end
|
389
|
+
|
357
390
|
# @api public
|
358
391
|
def descendants
|
359
|
-
@descendants ||=
|
392
|
+
@descendants ||= DescendantSet.new
|
393
|
+
end
|
394
|
+
|
395
|
+
# @api private
|
396
|
+
def inherited(descendant)
|
397
|
+
descendants << descendant
|
398
|
+
|
399
|
+
# inherit accepted options
|
400
|
+
descendant.accepted_options.concat(accepted_options)
|
401
|
+
|
402
|
+
# inherit the option values
|
403
|
+
options.each { |key, value| descendant.send(key, value) }
|
360
404
|
end
|
361
405
|
|
362
406
|
# @api public
|
@@ -368,20 +412,27 @@ module DataMapper
|
|
368
412
|
def accept_options(*args)
|
369
413
|
accepted_options.concat(args)
|
370
414
|
|
371
|
-
#
|
372
|
-
|
415
|
+
# create methods for each new option
|
416
|
+
args.each do |property_option|
|
373
417
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
374
|
-
def self.#{property_option}(
|
375
|
-
if
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
end
|
418
|
+
def self.#{property_option}(value = Undefined) # def self.unique(value = Undefined)
|
419
|
+
return @#{property_option} if value.equal?(Undefined) # return @unique if value.equal?(Undefined)
|
420
|
+
descendants.each do |descendant| # descendants.each do |descendant|
|
421
|
+
descendant.#{property_option}(value) # descendant.unique(value)
|
422
|
+
end # end
|
423
|
+
@#{property_option} = value # @unique = value
|
424
|
+
end # end
|
381
425
|
RUBY
|
382
426
|
end
|
383
427
|
|
384
|
-
descendants.each {|descendant| descendant.
|
428
|
+
descendants.each { |descendant| descendant.accepted_options.concat(args) }
|
429
|
+
end
|
430
|
+
|
431
|
+
# @api private
|
432
|
+
def nullable(*args)
|
433
|
+
# :required is preferable to :allow_nil, but :nullable maps precisely to :allow_nil
|
434
|
+
warn "#nullable is deprecated, use #required instead (#{caller[0]})"
|
435
|
+
allow_nil(*args)
|
385
436
|
end
|
386
437
|
|
387
438
|
# Gives all the options set on this type
|
@@ -392,49 +443,14 @@ module DataMapper
|
|
392
443
|
def options
|
393
444
|
options = {}
|
394
445
|
accepted_options.each do |method|
|
395
|
-
|
396
|
-
options[method] = value
|
446
|
+
value = send(method)
|
447
|
+
options[method] = send(method) unless value.nil?
|
397
448
|
end
|
398
449
|
options
|
399
450
|
end
|
400
|
-
|
401
|
-
# Ruby primitive type to use as basis for this type. See
|
402
|
-
# Property::PRIMITIVES for list of types.
|
403
|
-
#
|
404
|
-
# @param primitive [Class, nil]
|
405
|
-
# The class for the primitive. If nil is passed in, it returns the
|
406
|
-
# current primitive
|
407
|
-
#
|
408
|
-
# @return [Class] if the <primitive> param is nil, return the current primitive.
|
409
|
-
#
|
410
|
-
# @api public
|
411
|
-
def primitive(primitive = nil)
|
412
|
-
return @primitive if primitive.nil?
|
413
|
-
@primitive = primitive
|
414
|
-
end
|
415
|
-
|
416
|
-
def nullable(value)
|
417
|
-
# :required is preferable to :allow_nil, but :nullable maps precisely to :allow_nil
|
418
|
-
warn "#nullable is deprecated, use #required instead (#{caller[0]})"
|
419
|
-
allow_nil(value)
|
420
|
-
end
|
421
|
-
|
422
|
-
def inherited(base)
|
423
|
-
descendants << base
|
424
|
-
|
425
|
-
base.primitive primitive
|
426
|
-
base.accept_options(*accepted_options)
|
427
|
-
|
428
|
-
# inherit the options from the parent class
|
429
|
-
base_options = base.options
|
430
|
-
|
431
|
-
options.each do |key, value|
|
432
|
-
base.send(key, value) unless base_options.key?(key)
|
433
|
-
end
|
434
|
-
end
|
435
451
|
end
|
436
452
|
|
437
|
-
accept_options *Property::OPTIONS
|
453
|
+
accept_options :primitive, *Property::OPTIONS
|
438
454
|
|
439
455
|
# A hook to allow types to extend or modify property it's bound to.
|
440
456
|
# Implementations are not supposed to modify the state of the type class, and
|
@@ -448,11 +464,11 @@ module DataMapper
|
|
448
464
|
# @return [String] name of field in data-store
|
449
465
|
#
|
450
466
|
# @api semipublic
|
451
|
-
def field(repository_name =
|
467
|
+
def field(repository_name = Undefined)
|
452
468
|
self_repository_name = self.repository_name
|
453
469
|
klass = self.class
|
454
470
|
|
455
|
-
|
471
|
+
unless repository_name.equal?(Undefined)
|
456
472
|
warn "Passing in +repository_name+ to #{klass}#field is deprecated (#{caller[0]})"
|
457
473
|
|
458
474
|
if repository_name != self_repository_name
|
@@ -516,16 +532,6 @@ module DataMapper
|
|
516
532
|
@unique_index
|
517
533
|
end
|
518
534
|
|
519
|
-
# @api public
|
520
|
-
def kind_of?(klass)
|
521
|
-
super || klass == Property
|
522
|
-
end
|
523
|
-
|
524
|
-
# @api public
|
525
|
-
def instance_of?(klass)
|
526
|
-
super || klass == Property
|
527
|
-
end
|
528
|
-
|
529
535
|
# Returns whether or not the property is to be lazy-loaded
|
530
536
|
#
|
531
537
|
# @return [Boolean]
|
@@ -705,24 +711,6 @@ module DataMapper
|
|
705
711
|
end
|
706
712
|
end
|
707
713
|
|
708
|
-
# Returns given value unchanged for core types and
|
709
|
-
# uses +dump+ method of the property type for custom types.
|
710
|
-
#
|
711
|
-
# @param [Object] loaded_value
|
712
|
-
# the value to be converted into a storeable (ie., primitive) value
|
713
|
-
#
|
714
|
-
# @return [Object]
|
715
|
-
# the primitive value to be stored in the repository for +val+
|
716
|
-
#
|
717
|
-
# @api semipublic
|
718
|
-
def dump(value)
|
719
|
-
if custom?
|
720
|
-
type.dump(loaded_value, self)
|
721
|
-
else
|
722
|
-
loaded_value
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
714
|
# Test the value to see if it is a valid value for this Property
|
727
715
|
#
|
728
716
|
# @param [Object] loaded_value
|
@@ -775,9 +763,9 @@ module DataMapper
|
|
775
763
|
|
776
764
|
# @api semipublic
|
777
765
|
def initialize(model, name, options = {}, type = nil)
|
778
|
-
options
|
766
|
+
options = options.to_hash.dup
|
779
767
|
|
780
|
-
if type && !
|
768
|
+
if type && !kind_of?(type)
|
781
769
|
warn "#{type} < DataMapper::Type is deprecated, use the new DataMapper::Property API instead (#{caller[2]})"
|
782
770
|
@type = type
|
783
771
|
end
|
@@ -879,10 +867,10 @@ module DataMapper
|
|
879
867
|
#
|
880
868
|
# @api private
|
881
869
|
def determine_visibility
|
882
|
-
default_accessor = @options
|
870
|
+
default_accessor = @options.fetch(:accessor, :public)
|
883
871
|
|
884
|
-
@reader_visibility = @options
|
885
|
-
@writer_visibility = @options
|
872
|
+
@reader_visibility = @options.fetch(:reader, default_accessor)
|
873
|
+
@writer_visibility = @options.fetch(:writer, default_accessor)
|
886
874
|
end
|
887
875
|
end # class Property
|
888
876
|
end
|