caruby-core 1.4.7 → 1.4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/History.txt +11 -0
  2. data/README.md +1 -1
  3. data/lib/caruby/cli/command.rb +27 -3
  4. data/lib/caruby/csv/csv_mapper.rb +2 -0
  5. data/lib/caruby/csv/csvio.rb +187 -169
  6. data/lib/caruby/database.rb +33 -16
  7. data/lib/caruby/database/lazy_loader.rb +23 -23
  8. data/lib/caruby/database/persistable.rb +32 -18
  9. data/lib/caruby/database/persistence_service.rb +20 -7
  10. data/lib/caruby/database/reader.rb +22 -21
  11. data/lib/caruby/database/search_template_builder.rb +7 -9
  12. data/lib/caruby/database/sql_executor.rb +52 -27
  13. data/lib/caruby/database/store_template_builder.rb +18 -13
  14. data/lib/caruby/database/writer.rb +107 -44
  15. data/lib/caruby/domain/attribute_metadata.rb +35 -25
  16. data/lib/caruby/domain/java_attribute_metadata.rb +43 -20
  17. data/lib/caruby/domain/merge.rb +9 -5
  18. data/lib/caruby/domain/reference_visitor.rb +4 -3
  19. data/lib/caruby/domain/resource_attributes.rb +52 -12
  20. data/lib/caruby/domain/resource_dependency.rb +129 -42
  21. data/lib/caruby/domain/resource_introspection.rb +1 -1
  22. data/lib/caruby/domain/resource_inverse.rb +20 -3
  23. data/lib/caruby/domain/resource_metadata.rb +20 -4
  24. data/lib/caruby/domain/resource_module.rb +190 -124
  25. data/lib/caruby/import/java.rb +39 -19
  26. data/lib/caruby/migration/migratable.rb +31 -6
  27. data/lib/caruby/migration/migrator.rb +126 -40
  28. data/lib/caruby/migration/uniquify.rb +0 -1
  29. data/lib/caruby/resource.rb +28 -5
  30. data/lib/caruby/util/attribute_path.rb +0 -2
  31. data/lib/caruby/util/class.rb +8 -5
  32. data/lib/caruby/util/collection.rb +5 -3
  33. data/lib/caruby/util/domain_extent.rb +0 -3
  34. data/lib/caruby/util/options.rb +10 -9
  35. data/lib/caruby/util/person.rb +41 -12
  36. data/lib/caruby/util/pretty_print.rb +1 -1
  37. data/lib/caruby/util/validation.rb +0 -28
  38. data/lib/caruby/version.rb +1 -1
  39. data/test/lib/caruby/import/java_test.rb +26 -9
  40. data/test/lib/caruby/migration/test_case.rb +103 -0
  41. data/test/lib/caruby/test_case.rb +231 -0
  42. data/test/lib/caruby/util/class_test.rb +2 -2
  43. data/test/lib/caruby/util/visitor_test.rb +3 -2
  44. data/test/lib/examples/galena/clinical_trials/migration/participant_test.rb +28 -0
  45. data/test/lib/examples/galena/clinical_trials/migration/test_case.rb +40 -0
  46. metadata +195 -170
  47. data/lib/caruby/domain/attribute_initializer.rb +0 -16
  48. data/test/lib/caruby/util/validation_test.rb +0 -14
@@ -6,16 +6,15 @@ require 'caruby/util/options'
6
6
  require 'caruby/util/visitor'
7
7
  require 'caruby/util/inflector'
8
8
  require 'caruby/database/persistable'
9
- require 'caruby/database/persistifier'
9
+ require 'caruby/database/persistence_service'
10
10
  require 'caruby/database/reader'
11
11
  require 'caruby/database/writer'
12
- require 'caruby/database/persistence_service'
13
-
14
- # the caBIG client classes
15
- import 'gov.nih.nci.system.applicationservice.ApplicationServiceProvider'
16
- import 'gov.nih.nci.system.comm.client.ClientSession'
12
+ require 'caruby/database/persistifier'
17
13
 
18
14
  module CaRuby
15
+ # The caBIG client session class.
16
+ java_import Java::gov.nih.nci.system.comm.client.ClientSession
17
+
19
18
  # Database operation error.
20
19
  class DatabaseError < RuntimeError; end
21
20
 
@@ -43,7 +42,7 @@ module CaRuby
43
42
  # store method. CaRuby::Resource sets reasonable default values, recognizes application dependencies and steers
44
43
  # around caBIG idiosyncracies to the extent possible.
45
44
  class Database
46
- include Reader, Writer, Persistifier, Validation
45
+ include Reader, Writer, Persistifier
47
46
 
48
47
  # Database CRUD operation.
49
48
  class Operation
@@ -78,6 +77,24 @@ module CaRuby
78
77
 
79
78
  # Creates a new Database with the specified service name and options.
80
79
  #
80
+ # caCORE alert - obtaining a caCORE session instance mysteriously depends on referencing the
81
+ # application service first. Therefore, the default persistence service appService method must
82
+ # be called after it is instantiated and before the session is instantiated. However, when
83
+ # the appService method is called just before a session is acquired, then this call corrupts
84
+ # the object state of existing objects.
85
+ #
86
+ # Specifically, when a CaTissue::CollectionProtocol is created which references a
87
+ # CaTissue::CollectionProtocolRegistration which in turn references a CaTissue::Participant,
88
+ # then the call to PersistenceService.appService replaces the CaTissue::Participant
89
+ # reference with a difference CaTissue::Participant instance. The work-around for
90
+ # this extremely bizarre bug is to call appService immediately after instantiating
91
+ # the default persistence service.
92
+ #
93
+ # This bug might be a low-level JRuby-Java-caCORE-Hibernate confusion where something in
94
+ # caCORE stomps on an existing JRuby object graph. To reproduce, move the appService call
95
+ # to the start_session method and run PCBIN::MigrationTest#test_save with all but the
96
+ # verify_save(:biopsy, BIOPSY_OPTS) line commented out.
97
+ #
81
98
  # @param [String] service_name the name of the default {PersistenceService}
82
99
  # @param [{Symbol => String}] opts access options
83
100
  # @option opts [String] :host application service host name
@@ -96,6 +113,7 @@ module CaRuby
96
113
  port = Options.get(:port, opts)
97
114
  # class => service hash; default is the catissuecore app service
98
115
  @def_persist_svc = PersistenceService.new(service_name, :host => host, :port => port)
116
+ @def_persist_svc.app_service
99
117
  @persistence_services = [@def_persist_svc].to_set
100
118
  @cls_svc_hash = Hash.new(@def_persist_svc)
101
119
  # the create/update nested operations
@@ -149,11 +167,12 @@ module CaRuby
149
167
  # Subclasses can override for specialized services. A session is
150
168
  # started on demand if necessary.
151
169
  #
152
- # @param [Persistable] obj the domain object
170
+ # @param [Persistable, Class] obj the domain object or {Resource} class
153
171
  # @return [PersistanceService] the service for the domain object
154
- def persistence_service(obj)
155
- start_session if @session.nil?
156
- @def_persist_svc
172
+ def persistence_service(klass)
173
+ unless Class === klass then raise ArgumentError.new("#{self} persistence_service argument is not a Class: {#klass.qp}") end
174
+ start_session if @session.nil?
175
+ @def_persist_svc
157
176
  end
158
177
 
159
178
  # Adds the given service to this database.
@@ -244,11 +263,9 @@ module CaRuby
244
263
 
245
264
  # Initializes the default application service.
246
265
  def start_session
247
- raise DatabaseError.new('Application user option missing') if @user.nil?
248
- raise DatabaseError.new('Application password option missing') if @password.nil?
249
- # caCORE alert - obtaining a caCORE session instance mysteriously depends on referencing the application service first
250
- @def_persist_svc.app_service
251
- @session = ClientSession.instance()
266
+ if @user.nil? then raise DatabaseError.new('Application user option missing') end
267
+ if @password.nil? then raise DatabaseError.new('Application password option missing') end
268
+ @session = ClientSession.instance
252
269
  connect(@user, @password)
253
270
  end
254
271
 
@@ -3,19 +3,40 @@ require 'caruby/database/fetched_matcher'
3
3
  module CaRuby
4
4
  class Database
5
5
  # A LazyLoader fetches an association from the database on demand.
6
- class LazyLoader < Proc
6
+ class LazyLoader
7
7
  # Creates a new LazyLoader which calls the loader block on the subject.
8
8
  #
9
9
  # @yield [subject, attribute] fetches the given subject attribute value from the database
10
10
  # @yieldparam [Resource] subject the domain object whose attribute is to be loaded
11
11
  # @yieldparam [Symbol] attribute the domain attribute to load
12
12
  def initialize(&loader)
13
- super { |sbj, attr| load(sbj, attr, &loader) }
13
+ @loader = loader
14
14
  # the fetch result matcher
15
15
  @matcher = FetchedMatcher.new
16
16
  @enabled = true
17
17
  end
18
18
 
19
+ # @param [Resource] subject the domain object whose attribute is to be loaded
20
+ # @param [Symbol] the domain attribute to load
21
+ # @yield (see #initialize)
22
+ # @yieldparam (see #initialize)
23
+ # @return the attribute value loaded from the database
24
+ # @raise [RuntimeError] if this loader is disabled
25
+ def load(subject, attribute)
26
+ if disabled? then raise RuntimeError.new("#{subject.qp} lazy load called on disabled loader") end
27
+ logger.debug { "Lazy-loading #{subject.qp} #{attribute}..." }
28
+ # the current value
29
+ oldval = subject.send(attribute)
30
+ # load the fetched value
31
+ fetched = @loader.call(subject, attribute)
32
+ # nothing to merge if nothing fetched
33
+ return oldval if fetched.nil_or_empty?
34
+ # merge the fetched into the attribute
35
+ logger.debug { "Merging #{subject.qp} fetched #{attribute} value #{fetched.qp}#{' into ' + oldval.qp if oldval}..." }
36
+ matches = @matcher.match(fetched.to_enum, oldval.to_enum)
37
+ subject.merge_attribute(attribute, fetched, matches)
38
+ end
39
+
19
40
  # Disables this lazy loader. If the loader is already disabled, then this method is a no-op.
20
41
  # Otherwise, if a block is given, then the lazy loader is reenabled after the block is executed.
21
42
  #
@@ -74,27 +95,6 @@ module CaRuby
74
95
  # @return [Boolean] true if this loader was previously disabled, false otherwise
75
96
  def set_enabled
76
97
  disabled? and (@enabled = true)
77
- end
78
-
79
- # @param [Resource] subject the domain object whose attribute is to be loaded
80
- # @param [Symbol] the domain attribute to load
81
- # @yield (see #initialize)
82
- # @yieldparam (see #initialize)
83
- # @return the attribute value loaded from the database
84
- # @raise [RuntimeError] if this loader is disabled
85
- def load(subject, attribute)
86
- if disabled? then raise RuntimeError.new("#{subject.qp} lazy load called on disabled loader") end
87
- logger.debug { "Lazy-loading #{subject.qp} #{attribute}..." }
88
- # the current value
89
- oldval = subject.send(attribute)
90
- # load the fetched value
91
- fetched = yield(subject, attribute)
92
- # nothing to merge if nothing fetched
93
- return oldval if fetched.nil_or_empty?
94
- # merge the fetched into the attribute
95
- logger.debug { "Merging #{subject.qp} fetched #{attribute} value #{fetched.qp}#{' into ' + oldval.qp if oldval}..." }
96
- matches = @matcher.match(fetched.to_enum, oldval.to_enum)
97
- subject.merge_attribute(attribute, fetched, matches)
98
98
  end
99
99
  end
100
100
  end
@@ -8,10 +8,8 @@ module CaRuby
8
8
  # The Persistable mixin adds persistance capability. Every instance which includes Persistable
9
9
  # must respond to an overrided {#database} method.
10
10
  module Persistable
11
- include Validation
12
-
13
- # @return [{Symbol => Object}] the content value hash at the point of the last
14
- # take_snapshot call
11
+ # @return [{Symbol => Object}] the content value hash at the point of the last {#take_snapshot}
12
+ # call
15
13
  attr_reader :snapshot
16
14
 
17
15
  # @param [Resource, <Resource>, nil] obj the object(s) to check
@@ -30,10 +28,17 @@ module CaRuby
30
28
  not saved?(obj)
31
29
  end
32
30
 
33
- # @return [Database] the data access mediator for this Persistable
34
- # @raise [NotImplementedError] if the Persistable subclass does not define this method
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.
33
+ #
34
+ # @return [Database, nil] the data access mediator for this Persistable, if any
35
35
  def database
36
- raise NotImplementedError.new("Database operations are not available for #{self}")
36
+ nil
37
+ end
38
+
39
+ # @return [PersistenceService, nil] the database application service for this Persistable, if any
40
+ def persistence_service
41
+ database.persistence_service(self.class) if database
37
42
  end
38
43
 
39
44
  # Fetches the domain objects which match this template from the {#database}.
@@ -177,13 +182,12 @@ module CaRuby
177
182
  def add_lazy_loader(loader, attributes=nil)
178
183
  # guard against invalid call
179
184
  if identifier.nil? then raise ValidationError.new("Cannot add lazy loader to an unfetched domain object: #{self}") end
180
-
181
185
  # the attributes to lazy-load
182
186
  attributes ||= loadable_attributes
183
187
  return if attributes.empty?
184
188
  # define the reader and writer method overrides for the missing attributes
185
- loaded = attributes.select { |attr| inject_lazy_loader(attr) }
186
- logger.debug { "Lazy loader added to #{qp} attributes #{loaded.to_series}." } unless loaded.empty?
189
+ attrs = attributes.select { |attr| inject_lazy_loader(attr) }
190
+ logger.debug { "Lazy loader added to #{qp} attributes #{attrs.to_series}." } unless attrs.empty?
187
191
  end
188
192
 
189
193
  # Returns the attributes to load on demand. The base attribute list is given by the
@@ -361,7 +365,6 @@ module CaRuby
361
365
  vh = @snapshot
362
366
  ovh = value_hash(self.class.updatable_attributes)
363
367
 
364
-
365
368
  # KLUDGE TODO - confirm this is still a problem and fix
366
369
  # In Galena frozen migration example, SpecimenPosition snapshot doesn't include identifier; work around this here
367
370
  # This could be related to the problem of an abstract DomainObject not being added as a domain module class. See the
@@ -371,8 +374,6 @@ module CaRuby
371
374
  end
372
375
  # END OF KLUDGE
373
376
 
374
-
375
-
376
377
  if vh.size < ovh.size then
377
378
  attr, oval = ovh.detect { |a, v| not vh.has_key?(a) }
378
379
  logger.debug { "#{qp} is missing snapshot #{attr} compared to the current value #{oval.qp}." }
@@ -400,7 +401,7 @@ module CaRuby
400
401
  # @return [Boolean] whether a loader was added to the attribute
401
402
  def inject_lazy_loader(attribute)
402
403
  # bail if there is already a value
403
- send(attribute).enumerate { |ref| return false unless ref.identifier }
404
+ return false if attribute_loaded?(attribute)
404
405
  # the accessor methods to modify
405
406
  reader, writer = self.class.attribute_metadata(attribute).accessors
406
407
  # The singleton attribute reader method loads the reference once and thenceforth calls the
@@ -411,6 +412,15 @@ module CaRuby
411
412
  instance_eval "def #{writer}(value); remove_lazy_loader(:#{attribute}); super; end"
412
413
  true
413
414
  end
415
+
416
+ # @param (see #inject_lazy_loader)
417
+ # @return [Boolean] whether the attribute references one or more domain objects, and each
418
+ # referenced object has an identifier
419
+ def attribute_loaded?(attribute)
420
+ value = transient_value(attribute)
421
+ return false if value.nil_or_empty?
422
+ Enumerable === value ? value.all? { |ref| ref.identifier } : value.identifier
423
+ end
414
424
 
415
425
  # Loads the reference attribute database value into this Persistable.
416
426
  #
@@ -419,14 +429,12 @@ module CaRuby
419
429
  def load_reference(attribute)
420
430
  ldr = database.lazy_loader
421
431
  # bypass the singleton method and call the class instance method if the lazy loader is disabled
422
- unless ldr.enabled? then
423
- return self.class.instance_method(attribute).bind(self).call
424
- end
432
+ return transient_value(attribute) unless ldr.enabled?
425
433
 
426
434
  # Disable lazy loading first for the attribute, since the reader method is called by the loader.
427
435
  remove_lazy_loader(attribute)
428
436
  # load the fetched value
429
- merged = ldr.call(self, attribute)
437
+ merged = ldr.load(self, attribute)
430
438
 
431
439
  # update dependent snapshots if necessary
432
440
  attr_md = self.class.attribute_metadata(attribute)
@@ -447,6 +455,12 @@ module CaRuby
447
455
 
448
456
  merged
449
457
  end
458
+
459
+ # @param (see #load_reference)
460
+ # @return the in-memory attribute value, without invoking the lazy loader
461
+ def transient_value(attribute)
462
+ self.class.instance_method(attribute).bind(self).call
463
+ end
450
464
 
451
465
  # Disables the given singleton attribute accessor method.
452
466
  #
@@ -2,9 +2,16 @@ require 'caruby/util/version'
2
2
  require 'caruby/database'
3
3
  require 'caruby/util/stopwatch'
4
4
 
5
- import 'gov.nih.nci.common.util.HQLCriteria'
6
-
7
5
  module CaRuby
6
+ # HQLCriteria is required for the query_hql method.
7
+ java_import Java::gov.nih.nci.common.util.HQLCriteria
8
+
9
+ # The encapsulated caBIG service class.
10
+ java_import Java::gov.nih.nci.system.applicationservice.ApplicationServiceProvider
11
+
12
+ # This import is not strictly necessary, but works around Ticket #5.
13
+ java_import Java::gov.nih.nci.system.comm.client.ApplicationServiceClientImpl
14
+
8
15
  # A PersistenceService wraps a caCORE application service.
9
16
  class PersistenceService
10
17
  # The service name.
@@ -17,14 +24,15 @@ module CaRuby
17
24
  #
18
25
  # @param [String] the caBIG application service name
19
26
  # @param [{Symbol => Object}] opts the options
20
- # @option opts :host the service host (default +localhost+)
21
- # @option opts :version the caTissue version identifier
27
+ # @option opts [String] :host the service host (default +localhost+)
28
+ # @option opts [String] :version the caTissue version identifier
22
29
  def initialize(name, opts={})
23
30
  @name = name
24
31
  ver_opt = opts[:version]
25
32
  @version = ver_opt.to_s.to_version if ver_opt
26
33
  @host = opts[:host] || default_host
27
34
  @port = opts[:port] || 8080
35
+ @url = "http://#{@host}:#{@port}/#{@name}/http/remoteService"
28
36
  @timer = Stopwatch.new
29
37
  logger.debug { "Created persistence service #{name} at #{@host}:#{@port}." }
30
38
  end
@@ -81,11 +89,16 @@ module CaRuby
81
89
  end
82
90
  end
83
91
 
92
+ # Returns a freshly initialized ApplicationServiceProvider remote instance.
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.
97
+ #
84
98
  # @return [ApplicationServiceProvider] the CaCORE service provider wrapped by this PersistenceService
85
99
  def app_service
86
- url = "http://#{@host}:#{@port}/#{@name}/http/remoteService"
87
- logger.debug { "Connecting to service provider at #{url}..." }
88
- ApplicationServiceProvider.remote_instance(url)
100
+ logger.debug { "Connecting to service provider at #{@url}..." }
101
+ ApplicationServiceProvider.remote_instance(@url)
89
102
  end
90
103
 
91
104
  private
@@ -13,7 +13,7 @@ module CaRuby
13
13
  def initialize
14
14
  super
15
15
  # the query template builder
16
- @srch_tmpl_bldr = SearchTemplateBuilder.new(self)
16
+ @srch_tmpl_bldr = SearchTemplateBuilder.new
17
17
  # the fetch result matcher
18
18
  @matcher = FetchedMatcher.new
19
19
  # the fetched copier
@@ -85,16 +85,18 @@ module CaRuby
85
85
  end
86
86
  end
87
87
 
88
- # Returns whether domain object obj has a database identifier or exists in the database.
89
- # This method fetches obj from the database if necessary.
90
- # If obj is a domain object collection, then returns whether each item in the collection exists.
88
+ # Returns whether the given domain object has a database identifier or exists in the database.
89
+ # This method fetches the object from the database if necessary.
90
+ #
91
+ # @param [Resource, <Resource>] obj the domain object(s) to find
92
+ # @return [Boolean] whether the domain object(s) exist in the database
91
93
  def exists?(obj)
92
94
  if obj.nil? then
93
95
  false
94
96
  elsif obj.collection? then
95
97
  obj.all? { |item| exists?(item) }
96
98
  else
97
- obj.identifier or (obj.searchable? and find(obj))
99
+ obj.identifier or find(obj)
98
100
  end
99
101
  end
100
102
 
@@ -196,9 +198,8 @@ module CaRuby
196
198
  def query_hql(hql)
197
199
  java_name = hql[/from\s+(\S+)/i, 1]
198
200
  raise DatabaseError.new("Could not determine target type from HQL: #{hql}") if java_name.nil?
199
- target = Class.to_ruby(java_name)
200
- service = persistence_service(target)
201
- service.query(hql)
201
+ tgt = Class.to_ruby(java_name)
202
+ persistence_service(tgt).query(hql)
202
203
  end
203
204
 
204
205
  # Returns an array of objects fetched from the database which matches
@@ -229,9 +230,9 @@ module CaRuby
229
230
  # Returns an array of objects fetched from the database which matches
230
231
  # the given template and follows the given optional domain attribute.
231
232
  def query_on_template(template, attribute=nil)
232
- target = attribute ? template.class.domain_type(attribute) : template.class
233
- service = persistence_service(target)
234
- attribute ? service.query(template, attribute) : service.query(template)
233
+ tgt = attribute ? template.class.domain_type(attribute) : template.class
234
+ svc = persistence_service(tgt)
235
+ attribute ? svc.query(template, attribute) : svc.query(template)
235
236
  end
236
237
 
237
238
  # Queries on the given template and attribute by issuing a HQL query with an identifier condition.
@@ -272,6 +273,10 @@ module CaRuby
272
273
 
273
274
  # Queries the given query object attribute by querying an attribute type template which references obj.
274
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.
279
+ #
275
280
  # @param (see #query_object)
276
281
  def query_with_inverted_reference(obj, attribute=nil)
277
282
  attr_md = obj.class.attribute_metadata(attribute)
@@ -282,17 +287,15 @@ module CaRuby
282
287
  tmpl = attr_md.type.new
283
288
  # the inverse attribute
284
289
  inv_md = tmpl.class.attribute_metadata(attr_md.inverse)
285
- # the Java property writer to set the tmpl inverse to ref.
286
- # use the property writer rather than the attribute writer in order to curtail automatically
290
+ # The Java property writer to set the tmpl inverse to ref.
291
+ # Use the property writer rather than the attribute writer in order to curtail automatically
287
292
  # adding tmpl to the ref attribute value when the inv_md attribute is set to ref.
288
- # caCORE alert - caCORE query relies on a lack of inverse integrity, since caCORE search
289
- # enters an infinite loop upon encountering an object graph cycle.
290
- writer = inv_md.property_accessors.last
293
+ wtr = inv_md.property_writer
291
294
  # parameterize tmpl with inverse ref
292
- tmpl.send(writer, ref)
295
+ tmpl.send(wtr, ref)
293
296
  # submit the query
294
297
  logger.debug { "Submitting #{obj.qp} #{attribute} inverted query template #{tmpl.qp} ..." }
295
- persistence_service(tmpl).query(tmpl)
298
+ persistence_service(tmpl.class).query(tmpl)
296
299
  end
297
300
 
298
301
  # Finds the database content matching the given search object and merges the matching
@@ -310,7 +313,7 @@ module CaRuby
310
313
  # @raise [DatabaseError] if more than object matches the obj attribute values or if
311
314
  # the search object is a dependent entity that does not reference an owner
312
315
  def find_object(obj)
313
- if @transients.include?(obj) then
316
+ if @transients.include?(obj) then
314
317
  logger.debug { "Find #{obj.qp} obviated since the search was previously unsuccessful in the current database operation context." }
315
318
  return
316
319
  end
@@ -327,7 +330,6 @@ module CaRuby
327
330
  # so it is done manually here.
328
331
  # recursively copy the nondomain attributes, esp. the identifer, of the fetched domain object references
329
332
  merge_fetched(fetched, obj)
330
-
331
333
  # caCORE alert - see query method alerts.
332
334
  # Inject the lazy loader for loadable domain reference attributes.
333
335
  persistify(obj, fetched)
@@ -354,7 +356,6 @@ module CaRuby
354
356
  # submit the query on the template
355
357
  logger.debug { "Query template for finding #{obj.qp}: #{template}." }
356
358
  result = query_on_template(template)
357
-
358
359
  # a fetch query which returns more than one result is an error.
359
360
  # possible cause is an incorrect secondary key.
360
361
  if result.size > 1 then