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.md ADDED
@@ -0,0 +1,48 @@
1
+ This history lists major release themes. See the GitHub Commits (https://github.com/caruby/core)
2
+ for change details.
3
+
4
+ 1.5.1 / 2011-06-28
5
+ ------------------
6
+ * Domain refactoring.
7
+
8
+ 1.4.9 / 2011-05-04
9
+ ------------------
10
+ * Support Oracle driver.
11
+
12
+ 1.4.8 / 2011-05-03
13
+ ------------------
14
+ * Fix annotation migration error.
15
+
16
+ * Refactor resource import.
17
+
18
+ * Add attribute filters.
19
+
20
+ 1.4.7 / 2011-03-04
21
+ ------------------
22
+ * Support annotation migration.
23
+
24
+ 1.4.6 / 2011-02-26
25
+ ------------------
26
+ * Upgrade to JRuby 1.5.
27
+
28
+ 1.4.5 / 2011-02-26
29
+ ------------------
30
+ * Fix default option.
31
+
32
+ 1.4.4 / 2011-02-25
33
+ ------------------
34
+ * Support default migration option.
35
+
36
+ * Merge nondomain collection value properly.
37
+
38
+ 1.4.3 / 2011-02-18
39
+ ------------------
40
+ * Refactor Persistifier
41
+
42
+ 1.4.2 / 2010-11-30
43
+ ------------------
44
+ * Minor Migrator fixes.
45
+
46
+ 1.4.1 / 2010-11-23
47
+ ------------------
48
+ * Initial public release.
@@ -79,7 +79,8 @@ module CaRuby
79
79
  [:file, "--file FILE", "Configuration file containing other options"],
80
80
  [:log, "--log FILE", "Log file"],
81
81
  [:debug, "--debug", "Display debug log messages"],
82
- [:quiet, "-q", "--quiet", "Suppress printing messages to stdout"]
82
+ [:quiet, "-q", "--quiet", "Suppress printing messages to stdout"],
83
+ [:verbose, "-v", "--verbose", "Print additional messages to stdout"]
83
84
  ]
84
85
 
85
86
  # @param [{Symbol => Object}] opts the option => value hash
@@ -55,18 +55,18 @@ module CaRuby
55
55
  @string_headers = Set.new
56
56
  @hdr_map.each do |path, cls_hdr_hash|
57
57
  last = path.last
58
- @string_headers.merge!(cls_hdr_hash.values) if AttributeMetadata === last and last.type == String
58
+ @string_headers.merge!(cls_hdr_hash.values) if Attribute === last and last.type == String
59
59
  end
60
60
  end
61
61
 
62
- # Returns the given klass's mapped AttributeMetadata paths.
62
+ # Returns the given klass's mapped Attribute paths.
63
63
  # The default klass is the target class.
64
64
  def paths(klass=nil)
65
65
  klass ||= @target
66
66
  @cls_paths_hash[klass]
67
67
  end
68
68
 
69
- # Returns the header mapped by the given AttributeMetadata path and starting klass.
69
+ # Returns the header mapped by the given Attribute path and starting klass.
70
70
  # The default klass is the target class.
71
71
  def header(path, klass=nil)
72
72
  klass ||= @target
@@ -90,8 +90,8 @@ module CaRuby
90
90
  end
91
91
  end
92
92
 
93
- # @param [{Symbol => <AttributeMetadata>}] config the field => path list configuration
94
- # @return [({Symbol => <AttributeMetadata>}, {Class => {<AttributeMetadata> => Symbol>}})]
93
+ # @param [{Symbol => <Attribute>}] config the field => path list configuration
94
+ # @return [({Symbol => <Attribute>}, {Class => {<Attribute> => Symbol>}})]
95
95
  # the class => paths hash and the path => class => header hash
96
96
  def map_headers(config)
97
97
  # the class => paths hash; populated in map_headers
@@ -112,7 +112,7 @@ module CaRuby
112
112
  [cls_paths_hash, hdr_map]
113
113
  end
114
114
 
115
- # Returns an array of AttributeMetadata or symbol objects for the period-delimited path string path_s in the
115
+ # Returns an array of Attribute or symbol objects for the period-delimited path string path_s in the
116
116
  # pattern (_class_|_attribute_)(+.+_attribute_)*, e.g.:
117
117
  # ClinicalStudy.status
118
118
  # study.status
@@ -127,7 +127,7 @@ module CaRuby
127
127
  if names.empty? then
128
128
  raise ConfigurationError.new("Attribute entry in CSV field mapping is not in <class>.<attribute> format: #{value}")
129
129
  end
130
- # build the AttributeMetadata path by traversing the names path
130
+ # build the Attribute path by traversing the names path
131
131
  # if the name corresponds to a parent attribute, then add the attribute metadata.
132
132
  # otherwise, if the name is a method, then add the method.
133
133
  path = []
@@ -150,7 +150,7 @@ module CaRuby
150
150
  tail = names[path.size..-1].map { |name| name.to_sym }
151
151
  path.concat(tail)
152
152
  # return the starting class and path
153
- # Note that the starting class is not necessarily the first path AttributeMetadata declarer, since the
153
+ # Note that the starting class is not necessarily the first path Attribute declarer, since the
154
154
  # starting class could be a concrete subclass of an abstract declarer. this is important, since the class
155
155
  # must be instantiated.
156
156
  [klass, path]
@@ -28,17 +28,18 @@ module CaRuby
28
28
  not saved?(obj)
29
29
  end
30
30
 
31
- # Returns the data access mediator for this domain object, if any. The default implementation
32
- # returns nil. Application #{Resource} modules can override this method.
31
+ # Returns the data access mediator for this domain object.
32
+ # Application #{Resource} modules are required to override this method.
33
33
  #
34
- # @return [Database, nil] the data access mediator for this Persistable, if any
34
+ # @return [Database] the data access mediator for this Persistable, if any
35
+ # @raise [DatabaseError] if the subclass does not override this method
35
36
  def database
36
- nil
37
+ raise ValidationError.new("#{self} database is missing")
37
38
  end
38
39
 
39
- # @return [PersistenceService, nil] the database application service for this Persistable, if any
40
+ # @return [PersistenceService] the database application service for this Persistable
40
41
  def persistence_service
41
- database.persistence_service(self.class) if database
42
+ database.persistence_service(self.class)
42
43
  end
43
44
 
44
45
  # Fetches the domain objects which match this template from the {#database}.
@@ -74,6 +75,13 @@ module CaRuby
74
75
  database.create(self)
75
76
  end
76
77
 
78
+ # Creates this domain object, if necessary.
79
+ #
80
+ # @raise (see Database#ensure_exists)
81
+ def ensure_exists
82
+ database.ensure_exists(self)
83
+ end
84
+
77
85
  # Saves this domain object in the {#database}.
78
86
  #
79
87
  # @return (see Writer#save)
@@ -109,7 +117,7 @@ module CaRuby
109
117
  alias :== :equal?
110
118
 
111
119
  alias :eql? :==
112
-
120
+
113
121
  # Captures the Persistable's updatable attribute base values.
114
122
  # The snapshot is subsequently accessible using the {#snapshot} method.
115
123
  #
@@ -156,8 +164,7 @@ module CaRuby
156
164
  def changed_attributes
157
165
  if @snapshot then
158
166
  ovh = value_hash(self.class.updatable_attributes)
159
- diff = @snapshot.diff(ovh) { |attr, v, ov|
160
- Resource.value_equal?(v, ov) }
167
+ diff = @snapshot.diff(ovh) { |attr, v, ov| Resource.value_equal?(v, ov) }
161
168
  diff.keys
162
169
  else
163
170
  self.class.updatable_attributes
@@ -191,8 +198,8 @@ module CaRuby
191
198
  end
192
199
 
193
200
  # Returns the attributes to load on demand. The base attribute list is given by the
194
- # {ResourceAttributes#loadable_attributes} whose value is nil or empty.
195
- # In addition, if this Persistable has more than one {ResourceDependency#owner_attributes}
201
+ # {Attributes#loadable_attributes} whose value is nil or empty.
202
+ # In addition, if this Persistable has more than one {Dependency#owner_attributes}
196
203
  # and one is non-nil, then none of the owner attributes are loaded on demand,
197
204
  # since there can be at most one owner and ownership cannot change.
198
205
  #
@@ -225,52 +232,23 @@ module CaRuby
225
232
  disable_singleton_method(writer)
226
233
  end
227
234
 
228
- # Returns whether this domain object must be fetched to reflect the database state.
229
- # This default implementation returns whether this domain object was created and
230
- # there are any autogenerated attributes. Subclasses can override to relax or restrict
231
- # the condition.
232
- #
233
- # caCORE alert - the auto-generated criterion is a necessary but not sufficient condition
234
- # to determine whether a save caCORE result reflects the database state. Example:
235
- # * caTissue SCG event parameters are not auto-generated on SCG create if the SCG collection
236
- # status is Pending, but are auto-generated on SCG update if the SCG status is changed
237
- # to Complete. By contrast, the SCG specimens are auto-generated on SCG create, even if
238
- # the status is +Pending+.
239
- # The caBIG application can override this method in a Database subclass to fine-tune the
240
- # fetch criteria. Adding a more restrictive {#fetch_saved?} condition will will improve
241
- # performance but not change functionality.
242
- #
243
- # caCORE alert - a saved attribute which is cascaded but not fetched must be fetched in
244
- # order to reflect the database identifier in the saved object.
245
- #
246
- # @return [Boolean] whether this domain object must be fetched to reflect the database state
247
- def fetch_saved?
248
- # only fetch a create, not an update (note that subclasses can override this condition)
249
- return false if identifier
250
- # Check for an attribute with a value that might need to be changed in order to
251
- # reflect the auto-generated database content.
252
- ag_attrs = self.class.autogenerated_attributes
253
- return false if ag_attrs.empty?
254
- ag_attrs.any? { |attr| not send(attr).nil_or_empty? }
255
- end
256
-
257
235
  # Returns this domain object's attributes which must be fetched to reflect the database state.
258
- # This default implementation returns the {ResourceAttributes#autogenerated_logical_dependent_attributes}
236
+ # This default implementation returns the {Attributes#autogenerated_logical_dependent_attributes}
259
237
  # if this domain object does not have an identifier, or an empty array otherwise.
260
238
  # Subclasses can override to relax or restrict the condition.
261
239
  #
262
- # caCORE alert - the auto-generated criterion is a necessary but not sufficient condition
263
- # to determine whether a save caCORE result reflects the database state. Example:
264
- # * caTissue SCG event parameters are not auto-generated on SCG create if the SCG collection
265
- # status is Pending, but are auto-generated on SCG update if the SCG status is changed
266
- # to Complete. By contrast, the SCG specimens are auto-generated on SCG create, even if
267
- # the status is +Pending+.
268
- # The caBIG application can override this method in a Database subclass to fine-tune the
269
- # fetch criteria. Adding a more restrictive {#fetch_saved?} condition will will improve
270
- # performance but not change functionality.
240
+ # @quirk caCORE the auto-generated criterion is a necessary but not sufficient condition
241
+ # to determine whether a save caCORE result reflects the database state. Example:
242
+ # * caTissue SCG event parameters are not auto-generated on SCG create if the SCG collection
243
+ # status is Pending, but are auto-generated on SCG update if the SCG status is changed
244
+ # to Complete. By contrast, the SCG specimens are auto-generated on SCG create, even if
245
+ # the status is +Pending+.
246
+ # The caBIG application can override this method in a Database subclass to fine-tune the
247
+ # fetch criteria. Adding a more restrictive {#fetch_saved?} condition will will improve
248
+ # performance but not change functionality.
271
249
  #
272
- # caCORE alert - a saved attribute which is cascaded but not fetched must be fetched in
273
- # order to reflect the database identifier in the saved object.
250
+ # @quirk caCORE a saved attribute which is cascaded but not fetched must be fetched in
251
+ # order to reflect the database identifier in the saved object.
274
252
  #
275
253
  # @param [Database::Operation] the save operation
276
254
  # @return [<Symbol>] whether this domain object must be fetched to reflect the database state
@@ -306,18 +284,19 @@ module CaRuby
306
284
  # there are any autogenerated attributes. Subclasses can override to relax or restrict
307
285
  # the condition.
308
286
  #
309
- # caCORE alert - the auto-generated criterion is a necessary but not sufficient condition
310
- # to determine whether a save caCORE result reflects the database state. Example:
311
- # * caTissue SCG event parameters are not auto-generated on SCG create if the SCG collection
312
- # status is Pending, but are auto-generated on SCG update if the SCG status is changed
313
- # to Complete. By contrast, the SCG specimens are auto-generated on SCG create, even if
314
- # the status is +Pending+.
315
- # The caBIG application can override this method in a Database subclass to fine-tune the
316
- # fetch criteria. Adding a more restrictive {#fetch_saved?} condition will will improve
317
- # performance but not change functionality.
287
+ # @quirk caCORE The auto-generated criterion is a necessary but not sufficient condition
288
+ # to determine whether a save caCORE result reflects the database state. Example:
289
+ # * caTissue SCG event parameters are not auto-generated on SCG create if the SCG collection
290
+ # status is Pending, but are auto-generated on SCG update if the SCG status is changed
291
+ # to Complete. By contrast, the SCG specimens are auto-generated on SCG create, even if
292
+ # the status is +Pending+.
293
+ #
294
+ # The caBIG application can override this method in a Database subclass to fine-tune the
295
+ # fetch criteria. Adding a more restrictive {#fetch_saved?} condition will will improve
296
+ # performance but not change functionality.
318
297
  #
319
- # caCORE alert - a saved attribute which is cascaded but not fetched must be fetched in
320
- # order to reflect the database identifier in the saved object.
298
+ # @quirk caCORE A saved attribute which is cascaded but not fetched must be fetched in
299
+ # order to reflect the database identifier in the saved object.
321
300
  #
322
301
  # @return [Boolean] whether this domain object must be fetched to reflect the database state
323
302
  def fetch_saved?
@@ -330,7 +309,7 @@ module CaRuby
330
309
  ag_attrs.any? { |attr| not send(attr).nil_or_empty? }
331
310
  end
332
311
 
333
- # Sets the {ResourceAttributes#volatile_nondomain_attributes} to the other fetched value,
312
+ # Sets the {Attributes#volatile_nondomain_attributes} to the other fetched value,
334
313
  # if different.
335
314
  #
336
315
  # @param [Resource] other the fetched domain object reflecting the database state
@@ -470,7 +449,7 @@ module CaRuby
470
449
  # dissociate the method from this instance
471
450
  method = self.method(name_or_sym.to_sym)
472
451
  method.unbind
473
- # JRuby alert - Unbind doesn't work in JRuby 1.1.6. In that case, redefine the singleton method to delegate
452
+ # JRuby unbind doesn't work in JRuby 1.1.6. In that case, redefine the singleton method to delegate
474
453
  # to the class instance method.
475
454
  if singleton_methods.include?(name_or_sym.to_s) then
476
455
  args = (1..method.arity).map { |argnum| "arg#{argnum}" }.join(', ')
@@ -47,16 +47,16 @@ module CaRuby
47
47
  # object following the given attribute path. The query condition is determined by the values set in the
48
48
  # template. Every non-nil attribute in the template is used as a select condition.
49
49
  #
50
- # caCORE alert - this method returns the direct result of calling the +caCORE+ application service
51
- # search method. Calling reference attributes of this result is broken by +caCORE+ design.
50
+ # @quirk caCORE this method returns the direct result of calling the +caCORE+ application service
51
+ # search method. Calling reference attributes of this result is broken by +caCORE+ design.
52
52
  def query(template_or_hql, *path)
53
53
  String === template_or_hql ? query_hql(template_or_hql) : query_template(template_or_hql, path)
54
54
  end
55
55
 
56
56
  # Submits the create to the application service and returns the created object.
57
57
  #
58
- # caCORE alert - this method returns the direct result of calling the +caCORE+ application service
59
- # create method. Calling reference attributes of this result is broken by +caCORE+ design.
58
+ # @quirk caCORE this method returns the direct result of calling the +caCORE+ application service
59
+ # create method. Calling reference attributes of this result is broken by +caCORE+ design.
60
60
  def create(obj)
61
61
  logger.debug { "Submitting create #{obj.pp_s(:single_line)} to application service #{name}..." }
62
62
  begin
@@ -91,9 +91,9 @@ module CaRuby
91
91
 
92
92
  # Returns a freshly initialized ApplicationServiceProvider remote instance.
93
93
  #
94
- # caCORE alert - When more than one application service is used, each call to the service
95
- # must reinitialize the remote instance. E.g. this is done in the caTissue DE examples,
96
- # and is a good general practice.
94
+ # @quirk caCORE When more than one application service is used, each call to the service
95
+ # must reinitialize the remote instance. E.g. this is done in the caTissue DE examples,
96
+ # and is a good general practice.
97
97
  #
98
98
  # @return [ApplicationServiceProvider] the CaCORE service provider wrapped by this PersistenceService
99
99
  def app_service
@@ -135,11 +135,14 @@ module CaRuby
135
135
  'localhost'
136
136
  end
137
137
 
138
+ # Dispatches the given HQL to the application service.
139
+ #
140
+ # @quirk caCORE query target parameter is necessary for caCORE 3.x but deprecated in caCORE 4+.
141
+ #
142
+ # @param [String] hql the HQL to submit
138
143
  def query_hql(hql)
139
144
  logger.debug { "Building HQLCriteria..." }
140
145
  criteria = HQLCriteria.new(hql)
141
- # caCORE alert - query target parameter is necessary for caCORE 3.x but deprecated in caCORE 4+
142
- # TODO caCORE 4 - remove target parameter
143
146
  target = hql[/from\s+(\S+)/i, 1]
144
147
  raise DatabaseError.new("HQL does not contain a FROM clause: #{hql}") unless target
145
148
  logger.debug { "Submitting search on target class #{target} with the following HQL:\n #{hql}" }
@@ -61,22 +61,22 @@ module CaRuby
61
61
  cached
62
62
  end
63
63
 
64
- # caCORE alert - Dereferencing a caCORE search result uncascaded collection attribute
65
- # raises a Hibernate missing session error.
66
- # This problem is addressed by post-processing the +caCORE+ search result to set the
67
- # toxic attributes to an empty value.
68
- #
69
- # caCORE alert - The caCORE search result does not set the obvious inverse attributes,
70
- # e.g. children fetched with a parent do not have the children inverse parent attribute
71
- # set to the parent. Rather, it is a toxic caCORE reference which must be purged. This
72
- # leaves an empty reference which must be lazy-loaded, which is inefficient and inconsistent.
73
- # This situation is rectified in this detoxify method by setting the dependent owner
74
- # attribute to the fetched owner in the detoxification {ReferenceVisitor} copy-match-merge.
75
- #
76
64
  # This method copies each result domain object into a new object of the same type.
77
65
  # The copy nondomain attribute values are set to the fetched object values.
78
66
  # The copy fetched reference attribute values are set to a copy of the result references.
79
67
  #
68
+ # @quirk caCORE Dereferencing a caCORE search result uncascaded collection attribute
69
+ # raises a Hibernate missing session error.
70
+ # This problem is addressed by post-processing the +caCORE+ search result to set the
71
+ # toxic attributes to an empty value.
72
+ #
73
+ # @quirk caCORE The caCORE search result does not set the obvious inverse attributes,
74
+ # e.g. children fetched with a parent do not have the children inverse parent attribute
75
+ # set to the parent. Rather, it is a toxic caCORE reference which must be purged. This
76
+ # leaves an empty reference which must be lazy-loaded, which is inefficient and inconsistent.
77
+ # This situation is rectified in this detoxify method by setting the dependent owner
78
+ # attribute to the fetched owner in the detoxification {ReferenceVisitor} copy-match-merge.
79
+ #
80
80
  # @return [Resource, <Resource>] the detoxified object(s)
81
81
  def detoxify(toxic)
82
82
  return if toxic.nil?
@@ -90,7 +90,7 @@ module CaRuby
90
90
  end
91
91
 
92
92
  # Sets each of the toxic attributes in the given domain object to the corresponding
93
- # {ResourceMetadata#empty_value}.
93
+ # {Metadata#empty_value}.
94
94
  #
95
95
  # @param [Resource] toxic the toxic domain object
96
96
  def clear_toxic_attributes(toxic)
@@ -156,7 +156,7 @@ module CaRuby
156
156
  # @param obj (see #persistify_object)
157
157
  def set_inverses(obj)
158
158
  obj.class.domain_attributes.each_pair do |attr, attr_md|
159
- inv_md = attr_md.inverse_attribute_metadata || next
159
+ inv_md = attr_md.inverse_metadata || next
160
160
  if inv_md.collection? then
161
161
  obj.send(attr).enumerate { |ref| ref.send(inv_md.to_sym) << obj }
162
162
  else
@@ -32,7 +32,7 @@ module CaRuby
32
32
  # is a String, then the HQL statement String is executed.
33
33
  #
34
34
  # Otherwise, the query condition is determined by the values set in the template.
35
- # The non-nil {ResourceAttributes#searchable_attributes} are used in the query.
35
+ # The non-nil {Attributes#searchable_attributes} are used in the query.
36
36
  #
37
37
  # The optional path arguments are attribute symbols from the template to the
38
38
  # destination class, e.g.:
@@ -107,11 +107,11 @@ module CaRuby
107
107
  # Queries the given obj_or_hql as described in {#query} and makes a detoxified copy of the
108
108
  # toxic caCORE search result.
109
109
  #
110
- # caCORE alert - The query result consists of new domain objects whose content is copied
111
- # from the caBIG application search result. The caBIG result is Hibernate-enhanced but
112
- # sessionless. This result contains toxic broken objects whose access methods fail.
113
- # Therefore, this method sanitizes the toxic caBIG result to reflect the persistent state
114
- # of the domain objects.
110
+ # @quirk caCORE The query result consists of new domain objects whose content is copied
111
+ # from the caBIG application search result. The caBIG result is Hibernate-enhanced but
112
+ # sessionless. This result contains toxic broken objects whose access methods fail.
113
+ # Therefore, this method sanitizes the toxic caBIG result to reflect the persistent state
114
+ # of the domain objects.
115
115
  #
116
116
  # @param (see #query)
117
117
  # @return (see #query)
@@ -209,8 +209,8 @@ module CaRuby
209
209
  # If a template could not be built and obj is dependent, then this method
210
210
  # queries the obj owner with a dependent filter.
211
211
  #
212
- # caCORE alert - Bug #79 - API search with only id returns entire table.
213
- # Work around this bug by issuing a HQL query instead.
212
+ # @quirk caCORE Bug #79 - API search with only id returns entire table.
213
+ # Work around this bug by issuing a HQL query instead.
214
214
  #
215
215
  # @param [Resource] obj the query template object
216
216
  # @param [Symbol, nil] attribute the optional attribute to fetch
@@ -267,15 +267,15 @@ module CaRuby
267
267
  return false if attribute.nil?
268
268
  attr_md = obj.class.attribute_metadata(attribute)
269
269
  return false if attr_md.type.abstract?
270
- inv_md = attr_md.inverse_attribute_metadata
270
+ inv_md = attr_md.inverse_metadata
271
271
  inv_md and inv_md.searchable? and finder_parameters(obj)
272
272
  end
273
273
 
274
274
  # Queries the given query object attribute by querying an attribute type template which references obj.
275
275
  #
276
- # caCORE alert - caCORE caCORE search enters an infinite loop when the search argument has an object
277
- # reference graph cycle. Work-around is to ensure that reference integrity is broken in the search
278
- # argument by not setting inverse attributes.
276
+ # @quirk caCORE caCORE caCORE search enters an infinite loop when the search argument has an object
277
+ # reference graph cycle. Work-around is to ensure that reference integrity is broken in the search
278
+ # argument by not setting inverse attributes.
279
279
  #
280
280
  # @param (see #query_object)
281
281
  def query_with_inverted_reference(obj, attribute=nil)
@@ -308,6 +308,9 @@ module CaRuby
308
308
  # If a match is found, then each missing search object non-domain-valued attribute is set to
309
309
  # the fetched attribute value and this method returns the search object.
310
310
  #
311
+ # @quirk caCORE there is no caCORE find utility method to update a search target with persistent content,
312
+ # so it is done manually here.
313
+ #
311
314
  # @param obj (see #find)
312
315
  # @return [Resource, nil] obj if there is a matching database record, nil otherwise
313
316
  # @raise [DatabaseError] if more than object matches the obj attribute values or if
@@ -323,14 +326,11 @@ module CaRuby
323
326
  fetched = fetch_object(obj) || return
324
327
  # fetch_object can return obj; if so, then done
325
328
  return obj if obj.equal?(fetched)
329
+
326
330
  logger.debug { "Fetch #{obj.qp} matched database object #{fetched}." }
327
331
  @transients.delete(obj)
328
-
329
- # caCORE alert - there is no caCORE find utility method to update a search target with persistent content,
330
- # so it is done manually here.
331
- # recursively copy the nondomain attributes, esp. the identifer, of the fetched domain object references
332
+ # recursively copy the nondomain attributes, esp. the identifer, of the fetched domain object references
332
333
  merge_fetched(fetched, obj)
333
- # caCORE alert - see query method alerts.
334
334
  # Inject the lazy loader for loadable domain reference attributes.
335
335
  persistify(obj, fetched)
336
336
  obj
@@ -407,38 +407,38 @@ module CaRuby
407
407
 
408
408
  # Returns a copy of obj containing only those key attributes used in a find operation.
409
409
  #
410
- # caCORE alert - Bug #79: caCORE search fetches on all non-nil attributes, except
411
- # occasionally the identifier. There is no indication of how to identify uniquely
412
- # searchable attributes, so the secondary and alternate key is added manually in the
413
- # application configuration.
410
+ # @quirk caCORE Bug #79: caCORE search fetches on all non-nil attributes, except
411
+ # occasionally the identifier. There is no indication of how to identify uniquely
412
+ # searchable attributes, so the secondary and alternate key is added manually in the
413
+ # application configuration.
414
414
  def finder_template(obj)
415
415
  hash = finder_parameters(obj) || return
416
416
  @srch_tmpl_bldr.build_template(obj, hash)
417
417
  end
418
418
 
419
419
  # Fetches the given obj attribute from the database.
420
- # caCORE alert - there is no association fetch for caCORE 3.1 and earlier;
421
- # caCORE 4 association search is not yet adequately proven in caRuby testing.
422
- # Fall back on a general query instead (the devil we know). See also the
423
- # following alert.
424
- #
425
- # caCORE alert - caCORE search on a non-collection attribute returns a collection result,
426
- # even with the caCORE 4 association search. caRuby rectifies this by returning
427
- # an association fetch result consistent with the association attribute return type.
428
- #
429
- # caCORE alert - Preliminary indication is that caCORE 4 does not validate that
430
- # a non-collection association search returns at most one item.
431
- #
432
- # caCORE alert - Since the caCORE search result has toxic references which must be purged,
433
- # the detoxified copy loses reference integrity. E.g. a query on the children attribute of
434
- # a parent object forces lazy load of each child => parent reference separately resolving
435
- # in separate parent copies. There is no recognition that the children reference the parent
436
- # which generated the query. This anomaly is partially rectified in this fetch_association
437
- # method by setting the fetched objects inverse to the given search target object. The
438
- # inconsistent and inefficient caCORE behavior is further corrected by setting inverse
439
- # owners when the fetch result is persistified, as described in {Persistifier#persistify}.
440
- # Callers who do not persistify the result should call {Persistifier#set_inverses} on the
441
- # result.
420
+ # @quirk caCORE there is no association fetch for caCORE 3.1 and earlier;
421
+ # caCORE 4 association search is not yet adequately proven in caRuby testing.
422
+ # Fall back on a general query instead (the devil we know). See also the
423
+ # following alert.
424
+ #
425
+ # @quirk caCORE caCORE search on a non-collection attribute returns a collection result,
426
+ # even with the caCORE 4 association search. caRuby rectifies this by returning
427
+ # an association fetch result consistent with the association attribute return type.
428
+ #
429
+ # @quirk caCORE Preliminary indication is that caCORE 4 does not validate that
430
+ # a non-collection association search returns at most one item.
431
+ #
432
+ # @quirk caCORE Since the caCORE search result has toxic references which must be purged,
433
+ # the detoxified copy loses reference integrity. E.g. a query on the children attribute of
434
+ # a parent object forces lazy load of each child => parent reference separately resolving
435
+ # in separate parent copies. There is no recognition that the children reference the parent
436
+ # which generated the query. This anomaly is partially rectified in this fetch_association
437
+ # method by setting the fetched objects inverse to the given search target object. The
438
+ # inconsistent and inefficient caCORE behavior is further corrected by setting inverse
439
+ # owners when the fetch result is persistified, as described in {Persistifier#persistify}.
440
+ # Callers who do not persistify the result should call {Persistifier#set_inverses} on the
441
+ # result.
442
442
  #
443
443
  # @param [Resource] obj the search target object
444
444
  # @param [Symbol] attribute the association to fetch
@@ -452,7 +452,7 @@ module CaRuby
452
452
  # fetch the reference
453
453
  result = query_safe(obj, attribute)
454
454
  # set the result inverse references
455
- inv_md = obj.class.attribute_metadata(attribute).inverse_attribute_metadata
455
+ inv_md = obj.class.attribute_metadata(attribute).inverse_metadata
456
456
  if inv_md and not inv_md.collection? then
457
457
  inv_obj = obj.copy(:identifier)
458
458
  result.each do |ref|
@@ -466,10 +466,10 @@ module CaRuby
466
466
 
467
467
  # Returns a copy of obj containing only those key attributes used in a find operation.
468
468
  #
469
- # caCORE alert - caCORE search fetches on all non-nil attributes, except occasionally the identifier
470
- # (cf. https://cabig-kc.nci.nih.gov/Bugzilla/show_bug.cgi?id=79).
471
- # there is no indication of how to identify uniquely searchable attributes, so the secondary key
472
- # is added manually in the application configuration.
469
+ # @quirk caCORE caCORE search fetches on all non-nil attributes, except occasionally the identifier
470
+ # (cf. https://cabig-kc.nci.nih.gov/Bugzilla/show_bug.cgi?id=79).
471
+ # there is no indication of how to identify uniquely searchable attributes, so the secondary key
472
+ # is added manually in the application configuration.
473
473
  def finder_parameters(obj)
474
474
  key_value_hash(obj, obj.class.primary_key_attributes) or
475
475
  key_value_hash(obj, obj.class.secondary_key_attributes) or
@@ -513,13 +513,15 @@ module CaRuby
513
513
 
514
514
  # Sets the template attribute to a new search reference object created from source.
515
515
  # The reference contains only the source identifier.
516
- # Returns the search reference, or nil if source does not exist in the database.
516
+ #
517
+ # @quirk caCORE The search template must break inverse integrity by clearing an owner inverse reference,
518
+ # since a dependent => onwer => dependent cycle causes a caCORE search infinite loop.
519
+ #
520
+ # @return [Resource, nil] the search reference, or nil if source does not exist in the database
517
521
  def add_search_template_reference(template, source, attribute)
518
522
  return if not exists?(source)
519
523
  ref = source.copy(:identifier)
520
524
  template.set_attribute(attribute, ref)
521
- # caCORE alert - clear an owner inverse reference, since the template attr assignment might have added a reference
522
- # from ref to template, which introduces a template => ref => template cycle that causes a caCORE search infinite loop.
523
525
  inverse = template.class.attribute_metadata(attribute).derived_inverse
524
526
  ref.clear_attribute(inverse) if inverse
525
527
  logger.debug { "Search reference parameter #{attribute} for #{template.qp} set to #{ref} copied from #{source.qp}" }
@@ -5,19 +5,18 @@ module CaRuby
5
5
  # SearchTemplateBuilder builds a template suitable for a caCORE saarch database operation.
6
6
  class SearchTemplateBuilder
7
7
  # Returns a template for matching the domain object obj and the optional hash values.
8
- # The default hash attributes are the {ResourceAttributes#searchable_attributes}.
8
+ # The default hash attributes are the {Attributes#searchable_attributes}.
9
9
  # The template includes only the non-domain attributes of the hash references.
10
10
  #
11
- # caCORE alert - Because of caCORE API limitations, the obj searchable attribute
12
- # values are limited to the following:
13
- # * non-domain attribute values
14
- # * non-collection domain attribute references which contain a key
11
+ # @quirk caCORE Because of caCORE API limitations, the obj searchable attribute
12
+ # values are limited to the following:
13
+ # * non-domain attribute values
14
+ # * non-collection domain attribute references which contain a key
15
15
  #
16
- # caCORE alert - the caCORE query builder breaks on reference cycles and
17
- # is easily confused by extraneous references, so it is necessary to search
18
- # with a template instead that contains only references essential to the
19
- # search. Each reference is confirmed to exist and the reference content in
20
- # the template consists entirely of the fetched identifier attribute.
16
+ # @quirk caCORE the caCORE query builder breaks on reference cycles and is easily confused
17
+ # by extraneous references, so it is necessary to search with a template instead that contains
18
+ # only references essential to the search. Each reference is confirmed to exist and the
19
+ # reference content in the template consists entirely of the fetched identifier attribute.
21
20
  def build_template(obj, hash=nil)
22
21
  # split the attributes into reference and non-reference attributes.
23
22
  # the new search template object is built from the non-reference attributes.