caruby-core 1.4.9 → 1.5.1

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