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.
- data/History.md +48 -0
- data/lib/caruby/cli/command.rb +2 -1
- data/lib/caruby/csv/csv_mapper.rb +8 -8
- data/lib/caruby/database/persistable.rb +44 -65
- data/lib/caruby/database/persistence_service.rb +12 -9
- data/lib/caruby/database/persistifier.rb +14 -14
- data/lib/caruby/database/reader.rb +53 -51
- data/lib/caruby/database/search_template_builder.rb +9 -10
- data/lib/caruby/database/store_template_builder.rb +58 -58
- data/lib/caruby/database/writer.rb +96 -96
- data/lib/caruby/database.rb +19 -19
- data/lib/caruby/domain/attribute.rb +581 -0
- data/lib/caruby/domain/attributes.rb +615 -0
- data/lib/caruby/domain/dependency.rb +240 -0
- data/lib/caruby/domain/importer.rb +183 -0
- data/lib/caruby/domain/introspection.rb +176 -0
- data/lib/caruby/domain/inverse.rb +173 -0
- data/lib/caruby/domain/inversible.rb +1 -2
- data/lib/caruby/domain/java_attribute.rb +173 -0
- data/lib/caruby/domain/merge.rb +13 -10
- data/lib/caruby/domain/metadata.rb +141 -0
- data/lib/caruby/domain/mixin.rb +35 -0
- data/lib/caruby/domain/reference_visitor.rb +5 -3
- data/lib/caruby/domain.rb +340 -0
- data/lib/caruby/import/java.rb +29 -25
- data/lib/caruby/migration/migratable.rb +5 -5
- data/lib/caruby/migration/migrator.rb +19 -15
- data/lib/caruby/migration/resource_module.rb +1 -1
- data/lib/caruby/resource.rb +39 -30
- data/lib/caruby/util/collection.rb +94 -33
- data/lib/caruby/util/coordinate.rb +28 -2
- data/lib/caruby/util/log.rb +4 -4
- data/lib/caruby/util/module.rb +12 -28
- data/lib/caruby/util/partial_order.rb +9 -10
- data/lib/caruby/util/pretty_print.rb +46 -26
- data/lib/caruby/util/topological_sync_enumerator.rb +10 -4
- data/lib/caruby/util/transitive_closure.rb +2 -2
- data/lib/caruby/util/visitor.rb +1 -1
- data/lib/caruby/version.rb +1 -1
- data/test/lib/caruby/database/persistable_test.rb +1 -1
- data/test/lib/caruby/domain/domain_test.rb +14 -28
- data/test/lib/caruby/domain/inversible_test.rb +1 -1
- data/test/lib/caruby/import/java_test.rb +5 -0
- data/test/lib/caruby/migration/test_case.rb +0 -1
- data/test/lib/caruby/test_case.rb +9 -10
- data/test/lib/caruby/util/collection_test.rb +23 -5
- data/test/lib/caruby/util/module_test.rb +10 -14
- data/test/lib/caruby/util/partial_order_test.rb +16 -15
- data/test/lib/caruby/util/visitor_test.rb +1 -1
- data/test/lib/examples/galena/clinical_trials/migration/test_case.rb +1 -1
- metadata +16 -15
- data/History.txt +0 -44
- data/lib/caruby/domain/attribute_metadata.rb +0 -551
- data/lib/caruby/domain/java_attribute_metadata.rb +0 -183
- data/lib/caruby/domain/resource_attributes.rb +0 -565
- data/lib/caruby/domain/resource_dependency.rb +0 -217
- data/lib/caruby/domain/resource_introspection.rb +0 -160
- data/lib/caruby/domain/resource_inverse.rb +0 -151
- data/lib/caruby/domain/resource_metadata.rb +0 -155
- data/lib/caruby/domain/resource_module.rb +0 -370
- 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
|