dm-core 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|