caruby-core 1.4.9 → 1.5.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.
Files changed (61) hide show
  1. data/History.md +48 -0
  2. data/lib/caruby/cli/command.rb +2 -1
  3. data/lib/caruby/csv/csv_mapper.rb +8 -8
  4. data/lib/caruby/database/persistable.rb +44 -65
  5. data/lib/caruby/database/persistence_service.rb +12 -9
  6. data/lib/caruby/database/persistifier.rb +14 -14
  7. data/lib/caruby/database/reader.rb +53 -51
  8. data/lib/caruby/database/search_template_builder.rb +9 -10
  9. data/lib/caruby/database/store_template_builder.rb +58 -58
  10. data/lib/caruby/database/writer.rb +96 -96
  11. data/lib/caruby/database.rb +19 -19
  12. data/lib/caruby/domain/attribute.rb +581 -0
  13. data/lib/caruby/domain/attributes.rb +615 -0
  14. data/lib/caruby/domain/dependency.rb +240 -0
  15. data/lib/caruby/domain/importer.rb +183 -0
  16. data/lib/caruby/domain/introspection.rb +176 -0
  17. data/lib/caruby/domain/inverse.rb +173 -0
  18. data/lib/caruby/domain/inversible.rb +1 -2
  19. data/lib/caruby/domain/java_attribute.rb +173 -0
  20. data/lib/caruby/domain/merge.rb +13 -10
  21. data/lib/caruby/domain/metadata.rb +141 -0
  22. data/lib/caruby/domain/mixin.rb +35 -0
  23. data/lib/caruby/domain/reference_visitor.rb +5 -3
  24. data/lib/caruby/domain.rb +340 -0
  25. data/lib/caruby/import/java.rb +29 -25
  26. data/lib/caruby/migration/migratable.rb +5 -5
  27. data/lib/caruby/migration/migrator.rb +19 -15
  28. data/lib/caruby/migration/resource_module.rb +1 -1
  29. data/lib/caruby/resource.rb +39 -30
  30. data/lib/caruby/util/collection.rb +94 -33
  31. data/lib/caruby/util/coordinate.rb +28 -2
  32. data/lib/caruby/util/log.rb +4 -4
  33. data/lib/caruby/util/module.rb +12 -28
  34. data/lib/caruby/util/partial_order.rb +9 -10
  35. data/lib/caruby/util/pretty_print.rb +46 -26
  36. data/lib/caruby/util/topological_sync_enumerator.rb +10 -4
  37. data/lib/caruby/util/transitive_closure.rb +2 -2
  38. data/lib/caruby/util/visitor.rb +1 -1
  39. data/lib/caruby/version.rb +1 -1
  40. data/test/lib/caruby/database/persistable_test.rb +1 -1
  41. data/test/lib/caruby/domain/domain_test.rb +14 -28
  42. data/test/lib/caruby/domain/inversible_test.rb +1 -1
  43. data/test/lib/caruby/import/java_test.rb +5 -0
  44. data/test/lib/caruby/migration/test_case.rb +0 -1
  45. data/test/lib/caruby/test_case.rb +9 -10
  46. data/test/lib/caruby/util/collection_test.rb +23 -5
  47. data/test/lib/caruby/util/module_test.rb +10 -14
  48. data/test/lib/caruby/util/partial_order_test.rb +16 -15
  49. data/test/lib/caruby/util/visitor_test.rb +1 -1
  50. data/test/lib/examples/galena/clinical_trials/migration/test_case.rb +1 -1
  51. metadata +16 -15
  52. data/History.txt +0 -44
  53. data/lib/caruby/domain/attribute_metadata.rb +0 -551
  54. data/lib/caruby/domain/java_attribute_metadata.rb +0 -183
  55. data/lib/caruby/domain/resource_attributes.rb +0 -565
  56. data/lib/caruby/domain/resource_dependency.rb +0 -217
  57. data/lib/caruby/domain/resource_introspection.rb +0 -160
  58. data/lib/caruby/domain/resource_inverse.rb +0 -151
  59. data/lib/caruby/domain/resource_metadata.rb +0 -155
  60. data/lib/caruby/domain/resource_module.rb +0 -370
  61. data/lib/caruby/yard/resource_metadata_handler.rb +0 -8
data/History.txt DELETED
@@ -1,44 +0,0 @@
1
- This history lists major release themes. See the GitHub source (https://github.com/caruby/core)
2
- for change details.
3
-
4
- === 1.4.1 / 2010-11-23
5
-
6
- * Initial public release.
7
-
8
- === 1.4.2 / 2010-11-30
9
-
10
- * Minor Migrator fixes.
11
-
12
- === 1.4.3 / 2011-02-18
13
-
14
- * Refactor Persistifier
15
-
16
- * Add attribute filters.
17
-
18
- === 1.4.4 / 2011-02-25
19
-
20
- * Support default migration option.
21
-
22
- * Merge nondomain collection value properly.
23
-
24
- === 1.4.5 / 2011-02-26
25
-
26
- * Fix default option.
27
-
28
- === 1.4.6 / 2011-02-26
29
-
30
- * Upgrade to JRuby 1.5.
31
-
32
- === 1.4.7 / 2011-03-04
33
-
34
- * Support annotation migration.
35
-
36
- === 1.4.8 / 2011-05-03
37
-
38
- * Fix annotation migration error.
39
-
40
- * Refactor resource import.
41
-
42
- === 1.4.9 / 2011-05-04
43
-
44
- * Support Oracle driver.
@@ -1,551 +0,0 @@
1
- require 'set'
2
- require 'caruby/util/inflector'
3
- require 'caruby/util/collection'
4
- require 'caruby/util/validation'
5
-
6
- module CaRuby
7
- # An Attribute captures the following metadata about a domain class attribute:
8
- # * attribute symbol
9
- # * declarer type
10
- # * return type
11
- # * reader method symbol
12
- # * writer method symbol
13
- class AttributeMetadata
14
- # The supported attribute qualifier flags. See the complementary methods for an explanation of
15
- # the flag option, e.g. {#autogenerated?} for the +:autogenerated+ flag.
16
- SUPPORTED_FLAGS = [
17
- :autogenerated, :autogenerated_on_update, :collection, :dependent, :derived, :logical, :disjoint,
18
- :owner, :cascaded, :no_cascade_update_to_create, :saved, :unsaved, :optional, :fetched, :unfetched,
19
- :include_in_save_template, :saved_fetch, :create_only, :update_only, :unidirectional, :volatile].to_set
20
-
21
- # @return [(Symbol, Symbol)] the standard attribute reader and writer methods
22
- attr_reader :accessors
23
-
24
- # @return [Class] the declaring class
25
- attr_accessor :declarer
26
-
27
- # @return [Class] the return type
28
- attr_reader :type
29
-
30
- # @return [<Symbol>] the qualifier flags
31
- # @see SUPPORTED_FLAGS
32
- attr_accessor :flags
33
-
34
- # Creates a new AttributeMetadata from the given attribute.
35
- #
36
- # The type is the referenced entity type; an attribute whose return type is a collection
37
- # of domain objects is thus the domain object class rather than a collection class.
38
- #
39
- # If the type is given, then the following flags are recognized:
40
- # * +:dependent+ - the attribute references a dependent
41
- # * +:collection+ - the attribute return type is a collection
42
- # * +:owner+ - the attribute references the owner of a dependent
43
- # * +:cascaded+ - a database create/update/delete operation propagates to the attribute reference
44
- #
45
- # @param [String,Symbol] attr the subject attribute
46
- # @param [Class] declarer the declaring class
47
- # @param [Class] declarer the return type
48
- # @param [<Symbol>] flags the qualifying flags
49
- def initialize(attribute, declarer, type=nil, *flags)
50
- # the attribute symbol
51
- @symbol = attribute.to_sym
52
- # the declaring class
53
- @declarer = declarer
54
- # the Ruby class
55
- @type = Class.to_ruby(type) if type
56
- # the read and write methods
57
- @accessors = [@symbol, "#{attribute}=".to_sym]
58
- # the qualifier flags
59
- @flags = Set.new
60
- # identifier is always volatile
61
- if @symbol == :identifier then flags << :volatile end
62
- qualify(*flags)
63
- end
64
-
65
- # @return [Symbol] the reader method
66
- def reader
67
- accessors.first
68
- end
69
-
70
- # @return [Symbol] the writer method
71
- def writer
72
- accessors.last
73
- end
74
-
75
- # @return [Symbol, nil] the inverse of this attribute, if any
76
- def inverse
77
- @inv_md.to_sym if @inv_md
78
- end
79
-
80
- # @return [Boolean] whether this attribute does not have an inverse
81
- def unidirectional?
82
- inverse.nil?
83
- end
84
-
85
- # @param [Class] the attribute return type
86
- def type=(klass)
87
- return if klass == @type
88
- @type = klass
89
- if @inv_md then
90
- self.inverse = @inv_md.to_sym
91
- logger.debug { "Reset #{@declarer.qp}.#{self} inverse from #{@inv_md.type}.#{@inv_md} to #{klass}#{@inv_md}." }
92
- end
93
- end
94
-
95
- # Creates a new declarer attribute which restricts this attribute {#type} to the given type.
96
- #
97
- # @param declarer (see #restrict)
98
- # @param [Class] type the restricted subclass of this attribute's return type
99
- # @return (see #restrict)
100
- def restrict_type(declarer, type)
101
- if self.type and not type < self.type then
102
- raise ArgumentError.new("Cannot restrict #{self.declarer.qp}.#{self} to incompatible attribute type #{type.qp}")
103
- end
104
- copy = restrict(declarer)
105
- copy.type = type
106
- # specialize the inverse to the restricted type attribute, if necessary
107
- copy.restrict_inverse_type
108
- copy
109
- end
110
-
111
- # Creates a new declarer attribute which qualifies this attribute for the given declarer.
112
- #
113
- # @param declarer (see #restrict)
114
- # @param [<Symbol>] flags the additional flags for the restricted attribute
115
- # @return (see #restrict)
116
- def restrict_flags(declarer, *flags)
117
- copy = restrict(declarer)
118
- copy.qualify(*flags)
119
- copy
120
- end
121
-
122
- # Sets the inverse of the subject attribute to the given attribute.
123
- # The inverse relation is symmetric, i.e. the inverse of the referenced AttributeMetadata
124
- # is set to this AttributeMetadata's subject attribute.
125
- #
126
- # @param attribute the inverse attribute
127
- def inverse=(attribute)
128
- return if inverse == attribute
129
- # if no attribute, then the clear the existing inverse, if any
130
- return clear_inverse if attribute.nil?
131
-
132
- logger.debug { "Set #{@declarer.qp}.#{self} inverse to #{type.qp}.#{attribute}." }
133
- begin
134
- @inv_md = type.attribute_metadata(attribute)
135
- rescue NameError
136
- raise MetadataError.new("#{@declarer.qp}.#{self} inverse attribute #{type.qp}.#{attribute} not found - #{$!}")
137
- end
138
-
139
- # the inverse of the inverse
140
- inv_inv_md = @inv_md.inverse_attribute_metadata
141
- # If the inverse of the inverse is already set to a different attribute, then raise an exception.
142
- # Otherwise, it there is an inverse, then set the inverse of the inverse to this attribute.
143
- if inv_inv_md then
144
- unless inv_inv_md == self then
145
- raise MetadataError.new("Cannot set #{type.qp}.#{@inv_md} inverse attribute to #{@declarer.qp}.#{self} since it conflicts with existing inverse #{@inv_md.inverse}")
146
- end
147
- else
148
- # set the inverse of the inverse
149
- @inv_md.inverse = @symbol
150
- # if this attribute is disjoint, then so is the inverse.
151
- @inv_md.qualify(:disjoint) if disjoint?
152
- end
153
- # propagate to restrictions
154
- if @restrictions then @restrictions.each { |attr_md| attr_md.restrict_inverse_type(@inv_md) } end
155
- end
156
-
157
- # @return [AttributeMetadata, nil] the metadata for the {#inverse} attribute, if any
158
- def inverse_attribute_metadata
159
- @inv_md
160
- end
161
-
162
- # Qualifies this attribute with the given flags. Supported flags are listed in {SUPPORTED_FLAGS}.
163
- #
164
- # @param [<Symbol>] the flags to add
165
- # @raise [ArgumentError] if the flag is not supported
166
- def qualify(*flags)
167
- flags.each { |flag| set_flag(flag) }
168
- # propagate to restrictions
169
- if @restrictions then @restrictions.each { |attr_md| attr_md.qualify(*flags) } end
170
- end
171
-
172
- # @return whether the subject attribute encapsulates a Java property
173
- def java_property?
174
- CaRuby::JavaAttributeMetadata === self
175
- end
176
-
177
- # @return whether the subject attribute returns a domain object or collection of domain objects
178
- def domain?
179
- # the type must be a Ruby class rather than a Java Class, and include the Domain mix-in
180
- Class === type and type < Resource
181
- end
182
-
183
- # @return whether the subject attribute is not a domain object attribute
184
- def nondomain?
185
- not domain?
186
- end
187
-
188
- # Returns whether the subject attribute is fetched, determined as follows:
189
- # * An attribute marked with the :fetched flag is fetched.
190
- # * An attribute marked with the :unfetched flag is not fetched.
191
- # Otherwise, a non-domain attribute is fetched, and a domain attribute is
192
- # fetched if one of the following conditions hold:
193
- # * A dependent domain attribute is fetched if it is not logical.
194
- # * An owner domain attribute is fetched by default.
195
- # * An independent domain attribute is fetched if it is abstract and not derived.
196
- #
197
- # @return [Boolean] whether the attribute is fetched
198
- def fetched?
199
- return true if @flags.include?(:fetched)
200
- return false if @flags.include?(:unfetched)
201
- nondomain? or dependent? ? fetched_dependent? : fetched_independent?
202
- end
203
-
204
- # @return whether the subject attribute return type is a collection
205
- def collection?
206
- @flags.include?(:collection)
207
- end
208
-
209
- # Returns whether the subject attribute is a dependent on a parent. See the caRuby configuration
210
- # documentation for a dependency description.
211
- #
212
- # @return [Boolean] whether the attribute references a dependent
213
- def dependent?
214
- @flags.include?(:dependent)
215
- end
216
-
217
- # Returns whether the subject attribute is marked as optional in a create.
218
- # This method returns true only if the :optional flag is explicitly set.
219
- # Other attributes are optional by default.
220
- #
221
- # @return [Boolean] whether the attribute is optional
222
- # @see ResourceAttributes#mandatory_attributes.
223
- def optional?
224
- @flags.include?(:optional)
225
- end
226
-
227
- # Returns whether the subject attribute is not saved.
228
- #
229
- # @return [Boolean] whether the attribute is unsaved
230
- def unsaved?
231
- @flags.include?(:unsaved)
232
- end
233
-
234
- # Returns whether the subject attribute is a dependent whose value is automatically generated
235
- # with place-holder domain objects when the parent is created. An attribute is auto-generated
236
- # if the +:autogenerate+ or the +:autogenerated_on_update+ flag is set.
237
- #
238
- # @return [Boolean] whether the attribute is auto-generated
239
- def autogenerated?
240
- @flags.include?(:autogenerated) or @flags.include?(:autogenerated_on_update)
241
- end
242
-
243
- # Returns whether the the subject attribute is #{autogenerated?} for create. An attribute is
244
- # auto-generated for create if the +:autogenerate+ flag is set and the
245
- # +:autogenerated_on_update+ flag is not set.
246
- #
247
- # @return [Boolean] whether the attribute is auto-generated on create
248
- def autogenerated_on_create?
249
- @flags.include?(:autogenerated) and not @flags.include?(:autogenerated_on_update)
250
- end
251
-
252
- # Returns whether this attribute must be fetched when a declarer instance is saved.
253
- # An attribute is a saved fetch attribute if either of the following conditions hold:
254
- # * it is {#autogenerated?}
255
- # * it is {#cascaded?} and marked with the +:unfetched+ flag.
256
- #
257
- # @return [Boolean] whether the subject attribute must be refetched in order to reflect
258
- # the database content
259
- def saved_fetch?
260
- @flags.include?(:saved_fetch) or autogenerated? or (cascaded? and @flags.include?(:unfetched))
261
- end
262
-
263
- # Returns whether the subject attribute is a dependent whose owner does not automatically
264
- # cascade application service creation or update to the dependent. It is incumbent upon
265
- # CaRuby::Database to cascade the changes.
266
- #
267
- # @return [Boolean] whether the attribute is an uncascaded dependent
268
- def logical?
269
- @flags.include?(:logical)
270
- end
271
-
272
- # An attribute is derived if the attribute value is set by setting another attribute, e.g. if this
273
- # attribute is the inverse of a dependent owner attribute.
274
- #
275
- # @return [Boolean] whether this attribute is derived from another attribute
276
- def derived?
277
- @flags.include?(:derived) or (dependent? and not inverse.nil?)
278
- end
279
-
280
- # @return [Boolean] this attribute's inverse attribute if the inverse is a derived attribute, or nil otherwise
281
- def derived_inverse
282
- @inv_md.to_sym if @inv_md and @inv_md.derived?
283
- end
284
-
285
- # An independent attribute is a reference to one or more non-dependent Resource objects.
286
- # An {#owner?} attribute is independent.
287
- #
288
- # @return [Boolean] whether the subject attribute is a non-dependent domain attribute
289
- def independent?
290
- domain? and not dependent?
291
- end
292
-
293
- # A Java attribute is creatable if all of the following conditions hold:
294
- # * the attribute is {#saved?}
295
- # * the attribute is not a {#proxied_save?}
296
- # * the attribute :update_only flag is not set
297
- #
298
- # @return [Boolean] whether this attribute is saved in a create operation
299
- def creatable?
300
- saved? and not @flags.include?(:update_only)
301
- end
302
-
303
- # A Java attribute is an uncreated dependent if any of the following conditions hold:
304
- # * the attribute is a {#logical?} dependent
305
- # * the attribute is a #dependent? which is not {#creatable?}
306
- #
307
- # @return [Boolean] whether this attribute is saved in a create operation
308
- def uncreated_dependent?
309
- logical? or (dependent? and not creatable?)
310
- end
311
-
312
- # A Java attribute is updatable if all of the following conditions hold:
313
- # * the attribute is {#saved?}
314
- # * the attribute :create_only flag is not set
315
- #
316
- # @return [Boolean] whether this attribute is saved in a update operation
317
- def updatable?
318
- saved? and not @flags.include?(:create_only)
319
- end
320
-
321
- # @return [Boolean] whether the attribute is a physical dependent or the +:cascaded+ flag is set
322
- def cascaded?
323
- (dependent? and not logical?) or @flags.include?(:cascaded)
324
- end
325
-
326
- # @return whether this attribute is {#cascaded?} or marked with the +:include_in_save_template+ flag
327
- def include_in_save_template?
328
- cascaded? or @flags.include?(:include_in_save_template)
329
- end
330
-
331
- # Returns whether this attribute is #{#cascaded} and cascades a parent update to a child
332
- # create. This corresponds to the Hibernate +save-update+ cascade style but not the Hibernate
333
- # +all+ cascade style.
334
- #
335
- # This method returns true if this attribute is cascaded and the +:no_cascade_update_to_create+
336
- # flag is not set. Set this flag if the Hibernate mapping specifies the +all+ cascade style.
337
- # Failure to set this flag will result in the caTissue Hibernate error:
338
- # Exception: gov.nih.nci.system.applicationservice.ApplicationException:
339
- # The given object has a null identifier:
340
- # followed by the attribute type name.
341
- #
342
- # @return [Boolean] whether the attribute cascades to crate when the owner is updated
343
- def cascade_update_to_create?
344
- cascaded? and not @flags.include?(:no_cascade_update_to_create)
345
- end
346
-
347
- # A Java property attribute is saved if none of the following conditions hold:
348
- # * the attribute :unsaved flag is set
349
- # * the attribute is {#proxied_save?}
350
- # and any of the following conditions hold:
351
- # * the attibute is {#nondomain?}
352
- # * the attribute is cascaded
353
- # * the attribute value is not a collection
354
- # * the attribute does not have an inverse
355
- # * the attribute :saved flag is set
356
- #
357
- # @return [Boolean] whether this attribute is saved in a create or update operation
358
- def saved?
359
- @flags.include?(:saved) or
360
- (java_property? and not @flags.include?(:unsaved) and not proxied_save? and
361
- (nondomain? or cascaded? or not collection? or inverse.nil? or unidirectional_java_dependent?))
362
- end
363
-
364
- # @return [Boolean] whether this attribute is not {#saved?}
365
- def unsaved?
366
- not saved?
367
- end
368
-
369
- # @return [Boolean] whether the attribute return {#type} is a Resource class which
370
- # implements the saver_proxy method
371
- def proxied_save?
372
- domain? and type.method_defined?(:saver_proxy)
373
- end
374
-
375
- # Returns whether this attribute's referents must exist before an instance of the
376
- # declarer class can be created. An attribute is a storable prerequisite if it is
377
- # either:
378
- # * a {#cascaded?} dependent which does not #{#cascade_update_to_create?}, or
379
- # * a {#saved?} {#independent?} 1:M or M:N association.
380
- #
381
- # @return [Boolean] whether this attribute is a create prerequisite
382
- def storable_prerequisite?
383
- return true if cascaded? and @flags.include?(:no_cascade_update_to_create)
384
- return false unless independent? and saved?
385
- return true unless collection?
386
- inv_md = inverse_attribute_metadata
387
- inv_md.nil? or inv_md.collection?
388
- end
389
-
390
- # @return [Boolean] whether this attribute is a collection with a collection inverse
391
- def many_to_many?
392
- return false unless collection?
393
- inv_md = inverse_attribute_metadata
394
- inv_md and inv_md.collection?
395
- end
396
-
397
- # @return [Boolean] whether the subject attribute is not saved
398
- def transient?
399
- not saved?
400
- end
401
-
402
- # Returns whether this attribute is set on the server as a side-effect
403
- # of a change to the declarer object. The volatile attributes include
404
- # those which are {#unsaved?} and those which are saved but marked
405
- # with the +:volatile+ flag.
406
- #
407
- # @return [Boolean] whether this attribute's value is determined by the server
408
- def volatile?
409
- unsaved? or @flags.include?(:volatile)
410
- end
411
-
412
- # @return [Boolean] whether this is a non-collection Java attribute
413
- def searchable?
414
- java_property? and not collection?
415
- end
416
-
417
- # @return [Boolean] whether the subject attribute is a dependency owner
418
- def owner?
419
- @flags.include?(:owner)
420
- end
421
-
422
- # @return [Boolean] whether this is a dependent attribute which has exactly one owner value chosen from
423
- # several owner attributes.
424
- def disjoint?
425
- @flags.include?(:disjoint)
426
- end
427
-
428
- # @return [Boolean] whether this attribute is a dependent which does not have a Java inverse owner attribute
429
- def unidirectional_java_dependent?
430
- # TODO - can this be relaxed to java_unidirectional? i.e. eliminate dependent filter
431
- dependent? and not bidirectional_java_association?
432
- end
433
-
434
- # @return [Boolean] whether this is a Java attribute which has a Java inverse
435
- def bidirectional_java_association?
436
- inverse and java_property? and inverse_attribute_metadata.java_property?
437
- end
438
-
439
- def to_sym
440
- @symbol
441
- end
442
-
443
- def to_s
444
- @symbol.to_s
445
- end
446
-
447
- alias :inspect :to_s
448
-
449
- alias :qp :to_s
450
-
451
- protected
452
-
453
- # Duplicates the mutable content as part of a {#deep_copy}.
454
- def dup_content
455
- # keep the copied flags but don't share them
456
- @flags = @flags.dup
457
- # restrictions are neither shared nor copied
458
- @restrictions = nil
459
- end
460
-
461
- # If there is a current inverse which can be restricted to an attribute in the scope of
462
- # this metadata's restricted type, then reset the inverse to that attribute.
463
- #
464
- # @param [AttributeMetadata, nil] inv_md the inverse attribute to restrict
465
- def restrict_inverse_type(inv_md=nil)
466
- # set the inverse, if necessary
467
- @inv_md ||= inv_md || return
468
- # the current inverse
469
- attr = inverse
470
- # the restricted type's metadata for the current inverse
471
- rstr_inv_md = @type.attribute_metadata(attr)
472
- # bail if the restricted type delegates to the current inverse metadata
473
- return if rstr_inv_md == @inv_md
474
- # clear the inverse
475
- @inv_md = nil
476
- # reset the inverse to the restricted attribute
477
- self.inverse = attr
478
- end
479
-
480
- private
481
-
482
- # Creates a copy of this metadata which does not share mutable content.
483
- def deep_copy
484
- copy = dup
485
- copy.dup_content
486
- copy
487
- end
488
-
489
- # Creates a new declarer attribute which restricts this attribute type or flags.
490
- #
491
- # @param [Class] declarer the class for which the restriction holds
492
- # @return [AttributeMetadata] the metadata for the new declarer attribute
493
- def restrict(declarer)
494
- unless declarer < self.declarer then
495
- raise ArgumentError.new("Cannot restrict #{self.declarer.qp}.#{self} to incompatible declarer type #{declarer.qp}")
496
- end
497
- copy = deep_copy
498
- # specialize the copy declarer and type
499
- copy.declarer = declarer
500
- # Capture the restriction to propagate modifications to this metadata, esp.
501
- # adding an inverse.
502
- @restrictions ||= []
503
- @restrictions << copy
504
- copy
505
- end
506
-
507
- def clear_inverse
508
- return unless @inv_md
509
- logger.debug { "Clearing #{@declarer.qp}.#{self} inverse #{type.qp}.#{inverse}..." }
510
- inv_inv_md = @inv_md.inverse_attribute_metadata
511
- @inv_md = nil
512
- if inv_inv_md then inv_inv_md.inverse = nil end
513
- logger.debug { "Cleared #{@declarer.qp}.#{self} inverse." }
514
- end
515
-
516
- # @param [Symbol] the flag to set
517
- # @raise [ArgumentError] if flag is not supported
518
- def set_flag(flag)
519
- return if @flags.include?(flag)
520
- raise ArgumentError.new("Attribute flag not supported: #{flag}") unless SUPPORTED_FLAGS.include?(flag)
521
- @flags << flag
522
- case flag
523
- when :owner then
524
- if dependent? then
525
- raise MetadataError.new("#{declarer.qp}.#{self} cannot be set as a #{type.qp} owner since it is already defined as a #{type.qp} dependent")
526
- end
527
- inv_attr = type.dependent_attribute(@declarer)
528
- if inv_attr.nil? then
529
- raise MetadataError.new("#{@declarer.qp} owner attribute #{self} does not have a #{type.qp} dependent inverse")
530
- end
531
- self.inverse = type.dependent_attribute(@declarer)
532
- if inverse_attribute_metadata.logical? then @flags << :logical end
533
- when :dependent then
534
- if owner? then
535
- raise MetadataError.new("#{declarer.qp}.#{self} cannot be set as a #{type.qp} dependent since it is already defined as a #{type.qp} owner")
536
- end
537
- end
538
- end
539
-
540
- # @return [Boolean] whether this dependent attribute is fetched. Only physical dependents are fetched by default.
541
- def fetched_dependent?
542
- not (logical? or @flags.include?(:unfetched))
543
- end
544
-
545
- # @return [Boolean] whether this independent attribute is fetched. Only abstract, non-derived independent
546
- # references are fetched by default.
547
- def fetched_independent?
548
- type.abstract? and not (derived? or @flags.include?(:unfetched))
549
- end
550
- end
551
- end