caruby-tissue 1.4.2 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/History.md +53 -0
  2. data/bin/crtdump +1 -6
  3. data/bin/crtexample +1 -6
  4. data/bin/crtmigrate +1 -6
  5. data/bin/crtsmoke +1 -6
  6. data/conf/migration/filter_fields.yaml +1 -1
  7. data/conf/migration/general_fields.yaml +1 -1
  8. data/conf/migration/simple_fields.yaml +1 -1
  9. data/conf/migration/small_fields.yaml +1 -1
  10. data/examples/galena/README.md +34 -25
  11. data/examples/galena/bin/seed +2 -7
  12. data/examples/galena/conf/migration/annotation_fields.yaml +1 -1
  13. data/examples/galena/conf/migration/filter_fields.yaml +1 -1
  14. data/examples/galena/conf/migration/frozen_fields.yaml +2 -2
  15. data/examples/galena/conf/migration/general_fields.yaml +1 -1
  16. data/examples/galena/conf/migration/registration_fields.yaml +1 -0
  17. data/examples/galena/conf/migration/simple_fields.yaml +1 -1
  18. data/examples/galena/data/frozen.csv +1 -1
  19. data/examples/galena/data/general.csv +1 -1
  20. data/examples/galena/data/registration.csv +1 -1
  21. data/examples/galena/lib/galena/tissue/migration/frozen_shims.rb +8 -4
  22. data/examples/galena/lib/galena/tissue/seed/defaults.rb +16 -9
  23. data/examples/pcbin/README.md +8 -8
  24. data/examples/pcbin/conf/biopsy_fields.yaml +1 -1
  25. data/examples/pcbin/conf/patient_fields.yaml +1 -1
  26. data/examples/pcbin/conf/surgery_fields.yaml +1 -1
  27. data/examples/pcbin/conf/t_stage_fields.yaml +1 -1
  28. data/examples/pcbin/conf/therapy_fields.yaml +1 -1
  29. data/lib/catissue.rb +1 -1
  30. data/lib/catissue/annotation/annotatable.rb +12 -22
  31. data/lib/catissue/annotation/annotatable_class.rb +87 -114
  32. data/lib/catissue/annotation/annotation.rb +9 -44
  33. data/lib/catissue/annotation/annotation_class.rb +238 -145
  34. data/lib/catissue/annotation/annotation_module.rb +47 -59
  35. data/lib/catissue/annotation/de_integration.rb +12 -2
  36. data/lib/catissue/annotation/proxy.rb +11 -17
  37. data/lib/catissue/annotation/proxy_1_1.rb +47 -0
  38. data/lib/catissue/annotation/proxy_class.rb +55 -37
  39. data/lib/catissue/annotation/record_entry_proxy.rb +20 -0
  40. data/lib/catissue/database.rb +164 -112
  41. data/lib/catissue/database/annotation/annotation_service.rb +5 -5
  42. data/lib/catissue/database/annotation/annotator.rb +2 -2
  43. data/lib/catissue/database/annotation/entity_facade.rb +24 -21
  44. data/lib/catissue/database/annotation/id_generator.rb +26 -26
  45. data/lib/catissue/database/annotation/integration_service.rb +8 -8
  46. data/lib/catissue/database/annotation/record_entry_integrator.rb +24 -6
  47. data/lib/catissue/database/annotation/reference_writer.rb +33 -6
  48. data/lib/catissue/domain.rb +26 -0
  49. data/lib/catissue/domain/abstract_position.rb +1 -1
  50. data/lib/catissue/domain/abstract_specimen.rb +16 -16
  51. data/lib/catissue/domain/check_in_check_out_event_parameter.rb +1 -1
  52. data/lib/catissue/domain/collection_event_parameters.rb +1 -1
  53. data/lib/catissue/domain/collection_protocol.rb +9 -13
  54. data/lib/catissue/domain/collection_protocol_event.rb +4 -4
  55. data/lib/catissue/domain/collection_protocol_registration.rb +4 -4
  56. data/lib/catissue/domain/container.rb +12 -21
  57. data/lib/catissue/domain/container_type.rb +65 -64
  58. data/lib/catissue/domain/disposal_event_parameters.rb +1 -1
  59. data/lib/catissue/domain/hash_code.rb +3 -6
  60. data/lib/catissue/domain/new_specimen_array_order_item.rb +4 -4
  61. data/lib/catissue/domain/order_details.rb +3 -3
  62. data/lib/catissue/domain/participant.rb +28 -20
  63. data/lib/catissue/domain/participant/clinical/chemotherapy.rb +21 -0
  64. data/lib/catissue/domain/participant/clinical/duration.rb +11 -0
  65. data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +21 -0
  66. data/lib/catissue/domain/participant_medical_identifier.rb +2 -2
  67. data/lib/catissue/domain/site.rb +6 -6
  68. data/lib/catissue/domain/specimen.rb +41 -34
  69. data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +18 -0
  70. data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +13 -8
  71. data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +21 -0
  72. data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +30 -7
  73. data/lib/catissue/domain/specimen/pathology/specimen_details.rb +18 -0
  74. data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +18 -0
  75. data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +22 -6
  76. data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +18 -0
  77. data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +18 -0
  78. data/lib/catissue/domain/specimen_array.rb +8 -8
  79. data/lib/catissue/domain/specimen_array_content.rb +4 -4
  80. data/lib/catissue/domain/specimen_collection_group.rb +43 -41
  81. data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +16 -0
  82. data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +16 -0
  83. data/lib/catissue/domain/specimen_position.rb +3 -3
  84. data/lib/catissue/domain/specimen_protocol.rb +7 -7
  85. data/lib/catissue/domain/specimen_requirement.rb +9 -9
  86. data/lib/catissue/domain/storage_container.rb +13 -13
  87. data/lib/catissue/domain/storage_type.rb +12 -7
  88. data/lib/catissue/domain/transfer_event_parameters.rb +2 -2
  89. data/lib/catissue/domain/user.rb +15 -15
  90. data/lib/catissue/extract/extractor.rb +1 -1
  91. data/lib/catissue/resource.rb +8 -36
  92. data/lib/catissue/util/location.rb +0 -13
  93. data/lib/catissue/util/person.rb +2 -1
  94. data/lib/catissue/util/position.rb +1 -11
  95. data/lib/catissue/util/uniquify.rb +1 -1
  96. data/lib/catissue/version.rb +1 -1
  97. data/lib/catissue/wustl/logger.rb +17 -16
  98. data/test/fixtures/lib/catissue/defaults_test_fixture.rb +6 -4
  99. data/test/lib/catissue/domain/collection_protocol_test.rb +0 -1
  100. data/test/lib/catissue/domain/participant_test.rb +74 -19
  101. data/test/lib/catissue/domain/specimen_collection_group_test.rb +14 -10
  102. data/test/lib/catissue/domain/specimen_test.rb +36 -60
  103. data/test/lib/catissue/domain/storage_type_test.rb +5 -5
  104. data/test/lib/catissue/domain/transfer_event_parameters_test.rb +14 -12
  105. data/test/lib/catissue/migration/test_case.rb +0 -1
  106. data/test/lib/catissue/test_case.rb +12 -12
  107. data/test/lib/examples/galena/tissue/domain/examples_test.rb +1 -1
  108. data/test/lib/examples/galena/tissue/migration/annotation_test.rb +9 -7
  109. data/test/lib/examples/galena/tissue/migration/frozen_test.rb +1 -1
  110. data/test/lib/examples/galena/tissue/migration/general_test.rb +1 -1
  111. data/test/lib/examples/galena/tissue/migration/registration_test.rb +3 -9
  112. data/test/lib/examples/galena/tissue/migration/seedify.rb +3 -3
  113. data/test/lib/examples/pcbin/migration_test.rb +37 -16
  114. metadata +24 -10
  115. data/History.txt +0 -50
@@ -43,11 +43,11 @@ module CaTissue
43
43
 
44
44
  # @param [Annotation] (see #create)
45
45
  def create_annotation(annotation)
46
- # get the hook
46
+ # get the hook
47
47
  hook = annotation.hook
48
48
  # If no hook, then this is not a primary annotation. In that case, find a referenced
49
49
  # primary annotation.
50
- # If no hook, then this is not a primary annotation. In that case, find a referenced
50
+ # If no hook, then this is not a primary annotation. In that case, find a referenced
51
51
  # primary annotation.
52
52
  if hook then
53
53
  create_primary_annotation(annotation, hook)
@@ -92,9 +92,9 @@ module CaTissue
92
92
  end
93
93
  # The next database identifier.
94
94
  annotation.identifier = EntityFacade.instance.next_identifier(annotation)
95
- # Ensure that the proxy record is up-to-date.
96
- annotation.ensure_proxy_reflects_hook
97
-
95
+ # Ensure that there is a proxy hook.
96
+ pxy = annotation.proxy
97
+ if pxy then pxy.ensure_hook_exists end
98
98
  # Delegate to standard record create.
99
99
  app_service.create_object(annotation)
100
100
  logger.debug { "Created annotation object #{annotation}." }
@@ -18,8 +18,8 @@ module CaTissue
18
18
  # @param [String] name the service name
19
19
  # @return [Annotation::AnnotationService] the annotation service
20
20
  def create_annotation_service(mod, name)
21
- intgr = Annotation::Integrator.new(mod)
22
- Annotation::AnnotationService.new(@database, name, intgr)
21
+ @integrator = Annotation::Integrator.new(mod)
22
+ Annotation::AnnotationService.new(@database, name, @integrator)
23
23
  end
24
24
  end
25
25
  end
@@ -38,10 +38,10 @@ module CaTissue
38
38
  @idgen.next_identifier(table)
39
39
  end
40
40
 
41
- # caTissue alert - unlike the hook entity id lookup, the annotation entity id lookup strips the leading
42
- # package prefix from the annotation class name. caTissue DE API requires this undocumented inconsistency.
41
+ # @quirk caTissue unlike the hook entity id lookup, the annotation entity id lookup strips the leading
42
+ # package prefix from the annotation class name. caTissue DE API requires this undocumented inconsistency.
43
43
  #
44
- # caTissue alert - call into caTissue to get entity id doesn't work. caRuby uses direct SQL instead.
44
+ # @quirk caTissue call into caTissue to get entity id doesn't work. caRuby uses direct SQL instead.
45
45
  #
46
46
  # @param [Class] klass the {Annotation} primary class
47
47
  # @param [Boolean] validate flag indicating whether to raise an exception if the class is not primary
@@ -70,9 +70,9 @@ module CaTissue
70
70
  eid
71
71
  end
72
72
 
73
- # caTissue alert - call into caTissue to get entity id doesn't work for non-primary object.
74
- # Furthermore, the SQL used for the #{#annotation_entity_id} doesn't work for associated annotation
75
- # classes. Use alternative SQL instead.
73
+ # @quirk caTissue call into caTissue to get entity id doesn't work for non-primary object.
74
+ # Furthermore, the SQL used for the #{#annotation_entity_id} doesn't work for associated annotation
75
+ # classes. Use alternative SQL instead.
76
76
  #
77
77
  # @param [Integer] eid the referencing entity id
78
78
  # @param [String] eid the association property name
@@ -89,11 +89,11 @@ module CaTissue
89
89
  ref_eid
90
90
  end
91
91
 
92
- # caTissue alert - Annotation classes are incorrectly mapped to entity ids, which in turn are
93
- # incorrectly mapped to a table name. A candidate work-around is to bypass the caTissue DE
94
- # mechanism and hit the DE Hibernate config files directly. However, the DE Hibernate mappings
95
- # are incorrect and possibly no longer used. Therefore, the table must be obtained by SQL
96
- # work-arounds.
92
+ # @quirk caTissue Annotation classes are incorrectly mapped to entity ids, which in turn are
93
+ # incorrectly mapped to a table name. A candidate work-around is to bypass the caTissue DE
94
+ # mechanism and hit the DE Hibernate config files directly. However, the DE Hibernate mappings
95
+ # are incorrect and possibly no longer used. Therefore, the table must be obtained by SQL
96
+ # work-arounds.
97
97
  #
98
98
  # @param [Annotation] obj the annotation object
99
99
  # @return [String] the entity table name
@@ -116,17 +116,17 @@ module CaTissue
116
116
 
117
117
  # Obtains the undocumented caTisue container id for the given primary entity id.
118
118
  #
119
- # caTissue alert - EntityManager.getContainerIdForEntitycontainer uses incorrect table
120
- # (cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=421&sid=5252d951301e598eebf3e90036da43cb).
121
- # The standard DE API call submits the query:
122
- # SELECT IDENTIFIER FROM dyextn_container WHERE ENTITY_ID = ?
123
- # This results in the error:
124
- # Unknown column 'ENTITY_ID' in 'where clause'
125
- # The correct SQL is as follows:
126
- # SELECT IDENTIFIER FROM dyextn_container WHERE ABSTRACT_ENTITY_ID = ?
127
- # The work-around is to call this SQL directly.
119
+ # @quirk caTissue EntityManager.getContainerIdForEntitycontainer uses incorrect table
120
+ # (cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=421&sid=5252d951301e598eebf3e90036da43cb).
121
+ # The standard DE API call submits the query:
122
+ # SELECT IDENTIFIER FROM dyextn_container WHERE ENTITY_ID = ?
123
+ # This results in the error:
124
+ # Unknown column 'ENTITY_ID' in 'where clause'
125
+ # The correct SQL is as follows:
126
+ # SELECT IDENTIFIER FROM dyextn_container WHERE ABSTRACT_ENTITY_ID = ?
127
+ # The work-around is to call this SQL directly.
128
128
  #
129
- # caTissue alert - in 1.2, there are deprecated primary annotations with an entity id but no container id.
129
+ # @quirk caTissue in 1.2, there are deprecated primary annotations with an entity id but no container id.
130
130
  #
131
131
  # @return [Integer] eid the primary entity id
132
132
  def container_id(eid)
@@ -170,8 +170,11 @@ module CaTissue
170
170
  # @param (see #nonrecursive_annotation_entity_id)
171
171
  # @return [(String, String)] the entity group name and the entity name
172
172
  def split_annotation_entity_class_name(klass)
173
+ # the Java class full name
173
174
  jname = klass.java_class.name
175
+ # the Java package and base class name
174
176
  pkg, base = Java.split_class_name(jname)
177
+ # A wustl domain class is in the core group.
175
178
  if pkg =~ CORE_PKG_REGEX then
176
179
  [CORE_GROUP, jname]
177
180
  elsif pkg.nil? or pkg['.'] then
@@ -8,33 +8,33 @@ module CaTissue
8
8
  @executor = CaTissue::Database.instance.executor
9
9
  end
10
10
 
11
- # caTissue alert - DE API subquery search fails.
12
- # EntityManager.getNextIdentifierForEntity(EntityManager.java:2689) returns zero for some, but not all, DEs.
13
- # This is a cascading error that is difficult to trace. The EntityManager.getNextIdentifierForEntity error
14
- # is printed to the console rather than propagated up the call stack. A subsequent create then fails because
15
- # the identifier is not set.
11
+ # @quirk caTissue DE API subquery search fails.
12
+ # EntityManager.getNextIdentifierForEntity(EntityManager.java:2689) returns zero for some, but not all, DEs.
13
+ # This is a cascading error that is difficult to trace. The EntityManager.getNextIdentifierForEntity error
14
+ # is printed to the console rather than propagated up the call stack. A subsequent create then fails because
15
+ # the identifier is not set.
16
16
  #
17
- # A candidate work-around is to resolve the DE table name by issuing a direct SQL call and pass this
18
- # to DE API EntityManagerUtil.getNextIdentifier. However, EntityManagerUtil is broken as well, for a
19
- # different reason.
17
+ # A candidate work-around is to resolve the DE table name by issuing a direct SQL call and pass this
18
+ # to DE API EntityManagerUtil.getNextIdentifier. However, EntityManagerUtil is broken as well, for a
19
+ # different reason.
20
20
  #
21
- # Another candidate work-around is to get the next id manually from the caTissue DYEXTN_ID_GENERATOR table.
22
- # However, this table is suspect since it is not defined as a database sequence generator and is not
23
- # referenced in the caTissue source code. It is not used by the caTissue GUI when creating an annotation.
21
+ # Another candidate work-around is to get the next id manually from the caTissue DYEXTN_ID_GENERATOR table.
22
+ # However, this table is suspect since it is not defined as a database sequence generator and is not
23
+ # referenced in the caTissue source code. It is not used by the caTissue GUI when creating an annotation.
24
24
  #
25
- # The work-around to the work-around to the work-around is to call the following SQL directly:
26
- # select max(identifier) from <table>
27
- # where \<table\> is the result of the EntityManager work-around query. The EntityManager work-around query
28
- # is described in
29
- # https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=404&p=2785&sid=febe0a1271b3d00020927741a94e9bff#p2785.
25
+ # The work-around to the work-around to the work-around is to call the following SQL directly:
26
+ # select max(identifier) from <table>
27
+ # where \<table\> is the result of the EntityManager work-around query. The EntityManager work-around query
28
+ # is described in
29
+ # https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=404&p=2785&sid=febe0a1271b3d00020927741a94e9bff#p2785.
30
30
  #
31
- # Unfortunately, the +select max+ work-around is hampered by the obvious concurrent access race condition.
32
- # For an unknown reason, caTissue DE does not use database sequence generators to make DE identifiers.
33
- # Even if the caTissue DE API worked, it might suffer from the same race condition. The DE API
34
- # EntityManagerUtil caches identifiers. The API call is synchronized, but it is unclear whether each DE
35
- # client accesses the same EntityManagerUtil instance as the GUI DE action processor. If not, then the
36
- # caTissue DE API, assuming that it were functional, would be open to an even more serious concurrency
37
- # conflict than the work-around race condition.
31
+ # Unfortunately, the +select max+ work-around is hampered by the obvious concurrent access race condition.
32
+ # For an unknown reason, caTissue DE does not use database sequence generators to make DE identifiers.
33
+ # Even if the caTissue DE API worked, it might suffer from the same race condition. The DE API
34
+ # EntityManagerUtil caches identifiers. The API call is synchronized, but it is unclear whether each DE
35
+ # client accesses the same EntityManagerUtil instance as the GUI DE action processor. If not, then the
36
+ # caTissue DE API, assuming that it were functional, would be open to an even more serious concurrency
37
+ # conflict than the work-around race condition.
38
38
  #
39
39
  # @param [String] the entity table
40
40
  # @return [Integer] a new identifier for the given annotation object
@@ -47,11 +47,11 @@ module CaTissue
47
47
  sql = TABLE_MAX_ID_SQL_TMPL % table
48
48
  result = @executor.execute { |dbh| dbh.select_one(sql) }
49
49
  max = result ? result[0].to_i : 0
50
- identifier = max + 1
50
+ next_id = max + 1
51
51
  # End of work-around
52
52
 
53
- logger.debug { "Next #{table} identifier is #{identifier}." }
54
- identifier
53
+ logger.debug { "Next #{table} identifier is #{next_id}." }
54
+ next_id
55
55
  end
56
56
 
57
57
  private
@@ -4,15 +4,13 @@ module CaTissue
4
4
  module Annotation
5
5
  # An IntegrationService fetches and saves CaTissue 1.1.x hook-annotation associations.
6
6
  class IntegrationService < CaRuby::PersistenceService
7
- SERVICE_NAME = 'deintegration'
8
-
9
- # The caTissue
7
+ # Import the caTissue classes.
10
8
  java_import Java::deintegration.EntityMap
11
9
  java_import Java::deintegration.EntityMapRecord
12
10
  java_import Java::deintegration.FormContext
13
11
 
14
12
  def initialize
15
- super(SERVICE_NAME, CaTissue::Database.instance.access_properties)
13
+ super(SVC_NAME, CaTissue::Database.instance.access_properties)
16
14
  end
17
15
 
18
16
  # Associates the given hook domain object to the annotation.
@@ -29,6 +27,8 @@ module CaTissue
29
27
  end
30
28
 
31
29
  private
30
+
31
+ SVC_NAME = 'deintegration'
32
32
 
33
33
  #### The cruft below is adapted from caTissue 1.1.2 ClientDemo_SCG.java and cleaned up (but still obscure). ####
34
34
 
@@ -73,10 +73,10 @@ module CaTissue
73
73
  ctxt
74
74
  end
75
75
 
76
- # caTissue alert - the entity map is associated with a domain class in the hook class hierarchy.
77
- # The generic approach to determining the entity map for a given hook object and annotation object
78
- # is to iterate over the hook class hierarchy until a matching ENTITY_MAP record is found for the
79
- # hook class ancestor and the annotation container id.
76
+ # @quirk caTissue the entity map is associated with a domain class in the hook class hierarchy.
77
+ # The generic approach to determining the entity map for a given hook object and annotation object
78
+ # is to iterate over the hook class hierarchy until a matching ENTITY_MAP record is found for the
79
+ # hook class ancestor and the annotation container id.
80
80
  #
81
81
  # @param (see #associate)
82
82
  # @return [EntityMap] the entity map
@@ -12,6 +12,13 @@ module CaTissue
12
12
 
13
13
  # Associates the given hook domain object to the annotation.
14
14
  #
15
+ # @quirk caTissue The static hook entity is associated with the annotation
16
+ # by creating a record entry hook proxy. Even though the record entry class
17
+ # includes Java properties for each primary annotation in the annotation
18
+ # Java package, the record entry instance only references a single annotation.
19
+ # The record entry database table +dyextn_abstract_record_entry+ has foreign
20
+ # key to a ABSTRACT_FORM_CONTEXT_ID a separate record entry is created for each annotation.
21
+ #
15
22
  # @param [Annotatable] hook the hook entity
16
23
  # @param [Annotation] annotation the annotation entity
17
24
  def associate(hook, annotation)
@@ -25,12 +32,17 @@ module CaTissue
25
32
  # @return [Object] yet another association record which associates the hook to the
26
33
  # annotation in the {REC_ENTRY_PKG}
27
34
  def create_record_entry(hook, annotation)
28
- # the record entry object
29
- re = @mod.record_entry_class.new
30
- # the activity status must be set for the DE to show up
31
- re.activity_status = 'Active'
35
+ # the DE integration record entry class
36
+ klass = hook.class.de_integration_proxy_class
37
+ if klass.nil? then
38
+ # Should not be nil by construction, but doesn't hurt to check.
39
+ raise AnnotationError.new("Cannot create a #{hook} annotation record entry, since #{hook.class.qp} does not have a DE Integration proxy class")
40
+ end
41
+ # the DE integration record entry object
42
+ re = klass.new
32
43
  # the form context
33
44
  re.form_context = form_context(hook, annotation)
45
+ # set the hook
34
46
  re.send(@mod.record_entry_hook_writer, hook)
35
47
  # dispatch to the application service
36
48
  toxic = hook.persistence_service.create(re)
@@ -49,13 +61,19 @@ module CaTissue
49
61
  # @return (see #form_context)
50
62
  def fetch_form_context(hook, annotation)
51
63
  tmpl = StudyFormContext.new
52
- tmpl.container_id = annotation.class.container_id
64
+ ctr_id = annotation.class.container_id
65
+ if ctr_id.nil? then
66
+ raise AnnotationError.new("#{hook.class.qp} annotation #{annotation.class} doesn't have the required container id")
67
+ end
68
+ tmpl.container_id = ctr_id
53
69
  ctxts = hook.persistence_service.query(tmpl)
54
- case ctxts.size
70
+ ctxt = case ctxts.size
55
71
  when 0 then raise AnnotationError.new("Form context not found for annotation class #{annotation.class.qp}")
56
72
  when 1 then ctxts.first
57
73
  else raise AnnotationError.new("Multiple form contexts found for annotation class #{annotation.class.qp}")
58
74
  end
75
+ logger.debug { "#{annotation.qp} form context is #{ctxt}." }
76
+ ctxt
59
77
  end
60
78
  end
61
79
  end
@@ -5,7 +5,7 @@ module CaTissue
5
5
  # DYEXT tables of the introspected Java annotation class properties.
6
6
  class ReferenceWriter
7
7
  # @param [Integer] eid the referencing annotation entity id
8
- # @param [CaRuby::AttributeMetadata] attr_md the annotation attribute metadata of the attribute to save
8
+ # @param [CaRuby::Domain::Attribute] attr_md the annotation attribute metadata of the attribute to save
9
9
  # @param [Integer, nil] assn_eid the referenced annotation entity id
10
10
  def initialize(eid, attr_md, assn_eid=nil)
11
11
  logger.debug { "Mapping annotation #{attr_md.declarer.qp}.#{attr_md} role attributes to database columns..." }
@@ -89,9 +89,10 @@ module CaTissue
89
89
  hash = klass.nondomain_attributes.to_compact_hash do |attr|
90
90
  nondomain_attribute_column(klass, attr, eid)
91
91
  end
92
- # the owner attribute column
93
- ownr_attr = klass.owner_attribute
94
- if ownr_attr then hash[ownr_attr] = owner_attribute_column(klass, ownr_attr, eid) end
92
+ # the owner attribute columns
93
+ klass.owner_attributes.each do |oattr|
94
+ hash[oattr] = owner_attribute_column(klass, oattr, eid)
95
+ end
95
96
  hash
96
97
  end
97
98
 
@@ -109,10 +110,23 @@ module CaTissue
109
110
  col
110
111
  end
111
112
 
113
+ # @quirk caTissue The caTissue 1.1.2 DYNEXT_ROLE table omits the target name for seven annotations,
114
+ # e.g. SCG RadicalProstatectomyMargin. Work-around is to try the query with a null role name.
115
+ #
116
+ # @param [AnnotationClass] klass the annotation class
117
+ # @param [Symbol] attribute the owner attribute
118
+ # @param [Integer] eid the annotation entity id
119
+ # @return [String] the owner reference SQL column name
112
120
  def owner_attribute_column(klass, attribute, eid)
113
121
  logger.debug { "Finding #{klass.qp} #{attribute} column in the context of entity id #{eid}..." }
114
- result = CaTissue::Database.instance.executor.execute { |dbh| dbh.select_one(OWNER_COLUMN_SQL, eid) }
122
+ # The referenced class name (confusingly called a source role in the caTissue schema).
123
+ tgt_nm = klass.attribute_metadata(attribute).type.name.demodulize
124
+ result = CaTissue::Database.instance.executor.execute { |dbh| dbh.select_one(OWNER_COLUMN_SQL, eid, tgt_nm) }
115
125
  col = result[0] if result
126
+ if col.nil? then
127
+ result = CaTissue::Database.instance.executor.execute { |dbh| dbh.select_one(ALT_1_1_OWNER_COLUMN_SQL, eid) }
128
+ col = result[0] if result
129
+ end
116
130
  if col.nil? then raise AnnotationError.new("Column not found for #{klass.qp} owner attribute #{attribute}") end
117
131
  col
118
132
  end
@@ -141,9 +155,22 @@ EOS
141
155
  # The target entity id is obtained by calling {EntityFacade#associated_entity_id}.
142
156
  OWNER_COLUMN_SQL = <<EOS
143
157
  select cst.TARGET_ENTITY_KEY
144
- from DYEXTN_CONSTRAINT_PROPERTIES cst, DYEXTN_ASSOCIATION assn
158
+ from DYEXTN_CONSTRAINT_PROPERTIES cst, DYEXTN_ASSOCIATION assn, dyextn_role role
159
+ where cst.ASSOCIATION_ID = assn.IDENTIFIER
160
+ and assn.SOURCE_ROLE_ID = role.IDENTIFIER
161
+ and assn.TARGET_ENTITY_ID = ?
162
+ and role.name = ?
163
+ EOS
164
+
165
+ # SQL to get the annotation reference column name for a given annotation target entity id.
166
+ # The target entity id is obtained by calling {EntityFacade#associated_entity_id}.
167
+ ALT_1_1_OWNER_COLUMN_SQL = <<EOS
168
+ select cst.TARGET_ENTITY_KEY
169
+ from DYEXTN_CONSTRAINT_PROPERTIES cst, DYEXTN_ASSOCIATION assn, dyextn_role role
145
170
  where cst.ASSOCIATION_ID = assn.IDENTIFIER
171
+ and assn.SOURCE_ROLE_ID = role.IDENTIFIER
146
172
  and assn.TARGET_ENTITY_ID = ?
173
+ and role.name IS NULL
147
174
  EOS
148
175
  end
149
176
  end
@@ -0,0 +1,26 @@
1
+ require 'caruby/domain'
2
+ require 'catissue/resource'
3
+ require 'catissue/annotation/annotatable_class'
4
+ require 'catissue/wustl/logger'
5
+
6
+ module CaTissue
7
+
8
+ private
9
+
10
+ # The required Java package name.
11
+ PKG = 'edu.wustl.catissuecore.domain'
12
+
13
+ # The domain class definitions.
14
+ SRC_DIR = File.join(File.dirname(__FILE__), 'domain')
15
+
16
+ # Enable the resource metadata aspect.
17
+ md_proc = Proc.new { |klass| AnnotatableClass.extend_class(klass) }
18
+ CaRuby::Domain.extend_module(self, :mixin => Resource, :metadata => md_proc, :package => PKG)
19
+
20
+ # Set up the caTissue client logger before loading the class definitions.
21
+ Wustl::Logger.configure
22
+
23
+ # Load the class definitions.
24
+ load_dir(SRC_DIR)
25
+ end
26
+
@@ -17,6 +17,6 @@ module CaTissue
17
17
  offset_attribute(:column => :position_dimension_one, :row => :position_dimension_two)
18
18
 
19
19
  # add the synthetic {#location} attribute
20
- add_attribute(:location)
20
+ add_attribute(:location, Location)
21
21
  end
22
22
  end
@@ -22,28 +22,28 @@ module CaTissue
22
22
  :event_parameters => :specimen_events,
23
23
  :characteristics => :specimen_characteristics)
24
24
 
25
- # caTissue alert - initial_quantity must be set (cf. Bug #160)
25
+ # @quirk caTissue initial_quantity must be set (cf. Bug #160)
26
26
  add_attribute_defaults(:initial_quantity => 0.0, :pathological_status => 'Not Specified', :specimen_type => 'Not Specified')
27
27
 
28
28
  add_mandatory_attributes(:lineage, :pathological_status, :specimen_class, :specimen_type, :specimen_characteristics)
29
29
 
30
- # caTissue alert - Specimen characteristics are auto-generated but SpecimenRequirement
31
- # characteristics are not. It is safe to set the :autogenerated flag for both
32
- # AbstractSpecimen subclasses. This results in an unnecessary SpecimenRequirement
33
- # create database query, but SpecimenRequirement create is rare and there is no harm.
30
+ # @quirk caTissue Specimen characteristics are auto-generated but SpecimenRequirement
31
+ # characteristics are not. It is safe to set the :autogenerated flag for both
32
+ # AbstractSpecimen subclasses. This results in an unnecessary SpecimenRequirement
33
+ # create database query, but SpecimenRequirement create is rare and there is no harm.
34
34
  #
35
- # caTissue alert - Specimen characteristics is cascaded but is not an exclusive dependent,
36
- # since it is shared by aliquots.
35
+ # @quirk caTissue Specimen characteristics is cascaded but is not an exclusive dependent,
36
+ # since it is shared by aliquots.
37
37
  #
38
- # caTissue alert - Bug 166: API update Specimen ignores a SpecimenCharacteristics with a
39
- # different id. Guard against updating a Specimen with a SpecimenCharacteristics whose id
40
- # differs from the existing id.
38
+ # @quirk caTissue Bug 166: API update Specimen ignores a SpecimenCharacteristics with a
39
+ # different id. Guard against updating a Specimen with a SpecimenCharacteristics whose id
40
+ # differs from the existing id.
41
41
  #
42
- # caTissue alert - Unlike other dependents, AbstractSpecimen characteristics, events and child
43
- # specimens have cascade style 'all'. This implies that an AbstractSpecimen update does not
44
- # create a referenced dependent. AbstractSpecimen create cascades to create and AbstractSpecimen
45
- # update cascades to update, but AbstractSpecimen update does not cascade to create.
46
- # The :no_cascade_update_to_create flag is set to handle this feature of cascade style 'all'.
42
+ # @quirk caTissue Unlike other dependents, AbstractSpecimen characteristics, events and child
43
+ # specimens have cascade style 'all'. This implies that an AbstractSpecimen update does not
44
+ # create a referenced dependent. AbstractSpecimen create cascades to create and AbstractSpecimen
45
+ # update cascades to update, but AbstractSpecimen update does not cascade to create.
46
+ # The :no_cascade_update_to_create flag is set to handle this feature of cascade style 'all'.
47
47
  qualify_attribute(:specimen_characteristics, :cascaded, :fetched, :autogenerated, :no_cascade_update_to_create)
48
48
 
49
49
  # The :no_cascade_update_to_create flag is set since events has cascade style 'all'.
@@ -248,7 +248,7 @@ module CaTissue
248
248
  # infer the specimen domain class from the specimen_class prefix and Specimen or SpecimenRequirement suffix
249
249
  cls_nm = opt.to_s.capitalize_first + 'Specimen'
250
250
  cls_nm += 'Requirement' if CaTissue::SpecimenRequirement === self
251
- CaTissue.domain_type_with_name(cls_nm)
251
+ CaTissue.const_get(cls_nm)
252
252
  end
253
253
 
254
254
  # Creates a derived specimen.