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.
- data/History.md +53 -0
- data/bin/crtdump +1 -6
- data/bin/crtexample +1 -6
- data/bin/crtmigrate +1 -6
- data/bin/crtsmoke +1 -6
- data/conf/migration/filter_fields.yaml +1 -1
- data/conf/migration/general_fields.yaml +1 -1
- data/conf/migration/simple_fields.yaml +1 -1
- data/conf/migration/small_fields.yaml +1 -1
- data/examples/galena/README.md +34 -25
- data/examples/galena/bin/seed +2 -7
- data/examples/galena/conf/migration/annotation_fields.yaml +1 -1
- data/examples/galena/conf/migration/filter_fields.yaml +1 -1
- data/examples/galena/conf/migration/frozen_fields.yaml +2 -2
- data/examples/galena/conf/migration/general_fields.yaml +1 -1
- data/examples/galena/conf/migration/registration_fields.yaml +1 -0
- data/examples/galena/conf/migration/simple_fields.yaml +1 -1
- data/examples/galena/data/frozen.csv +1 -1
- data/examples/galena/data/general.csv +1 -1
- data/examples/galena/data/registration.csv +1 -1
- data/examples/galena/lib/galena/tissue/migration/frozen_shims.rb +8 -4
- data/examples/galena/lib/galena/tissue/seed/defaults.rb +16 -9
- data/examples/pcbin/README.md +8 -8
- data/examples/pcbin/conf/biopsy_fields.yaml +1 -1
- data/examples/pcbin/conf/patient_fields.yaml +1 -1
- data/examples/pcbin/conf/surgery_fields.yaml +1 -1
- data/examples/pcbin/conf/t_stage_fields.yaml +1 -1
- data/examples/pcbin/conf/therapy_fields.yaml +1 -1
- data/lib/catissue.rb +1 -1
- data/lib/catissue/annotation/annotatable.rb +12 -22
- data/lib/catissue/annotation/annotatable_class.rb +87 -114
- data/lib/catissue/annotation/annotation.rb +9 -44
- data/lib/catissue/annotation/annotation_class.rb +238 -145
- data/lib/catissue/annotation/annotation_module.rb +47 -59
- data/lib/catissue/annotation/de_integration.rb +12 -2
- data/lib/catissue/annotation/proxy.rb +11 -17
- data/lib/catissue/annotation/proxy_1_1.rb +47 -0
- data/lib/catissue/annotation/proxy_class.rb +55 -37
- data/lib/catissue/annotation/record_entry_proxy.rb +20 -0
- data/lib/catissue/database.rb +164 -112
- data/lib/catissue/database/annotation/annotation_service.rb +5 -5
- data/lib/catissue/database/annotation/annotator.rb +2 -2
- data/lib/catissue/database/annotation/entity_facade.rb +24 -21
- data/lib/catissue/database/annotation/id_generator.rb +26 -26
- data/lib/catissue/database/annotation/integration_service.rb +8 -8
- data/lib/catissue/database/annotation/record_entry_integrator.rb +24 -6
- data/lib/catissue/database/annotation/reference_writer.rb +33 -6
- data/lib/catissue/domain.rb +26 -0
- data/lib/catissue/domain/abstract_position.rb +1 -1
- data/lib/catissue/domain/abstract_specimen.rb +16 -16
- data/lib/catissue/domain/check_in_check_out_event_parameter.rb +1 -1
- data/lib/catissue/domain/collection_event_parameters.rb +1 -1
- data/lib/catissue/domain/collection_protocol.rb +9 -13
- data/lib/catissue/domain/collection_protocol_event.rb +4 -4
- data/lib/catissue/domain/collection_protocol_registration.rb +4 -4
- data/lib/catissue/domain/container.rb +12 -21
- data/lib/catissue/domain/container_type.rb +65 -64
- data/lib/catissue/domain/disposal_event_parameters.rb +1 -1
- data/lib/catissue/domain/hash_code.rb +3 -6
- data/lib/catissue/domain/new_specimen_array_order_item.rb +4 -4
- data/lib/catissue/domain/order_details.rb +3 -3
- data/lib/catissue/domain/participant.rb +28 -20
- data/lib/catissue/domain/participant/clinical/chemotherapy.rb +21 -0
- data/lib/catissue/domain/participant/clinical/duration.rb +11 -0
- data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +21 -0
- data/lib/catissue/domain/participant_medical_identifier.rb +2 -2
- data/lib/catissue/domain/site.rb +6 -6
- data/lib/catissue/domain/specimen.rb +41 -34
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +18 -0
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +13 -8
- data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +21 -0
- data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +30 -7
- data/lib/catissue/domain/specimen/pathology/specimen_details.rb +18 -0
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +18 -0
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +22 -6
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +18 -0
- data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +18 -0
- data/lib/catissue/domain/specimen_array.rb +8 -8
- data/lib/catissue/domain/specimen_array_content.rb +4 -4
- data/lib/catissue/domain/specimen_collection_group.rb +43 -41
- data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +16 -0
- data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +16 -0
- data/lib/catissue/domain/specimen_position.rb +3 -3
- data/lib/catissue/domain/specimen_protocol.rb +7 -7
- data/lib/catissue/domain/specimen_requirement.rb +9 -9
- data/lib/catissue/domain/storage_container.rb +13 -13
- data/lib/catissue/domain/storage_type.rb +12 -7
- data/lib/catissue/domain/transfer_event_parameters.rb +2 -2
- data/lib/catissue/domain/user.rb +15 -15
- data/lib/catissue/extract/extractor.rb +1 -1
- data/lib/catissue/resource.rb +8 -36
- data/lib/catissue/util/location.rb +0 -13
- data/lib/catissue/util/person.rb +2 -1
- data/lib/catissue/util/position.rb +1 -11
- data/lib/catissue/util/uniquify.rb +1 -1
- data/lib/catissue/version.rb +1 -1
- data/lib/catissue/wustl/logger.rb +17 -16
- data/test/fixtures/lib/catissue/defaults_test_fixture.rb +6 -4
- data/test/lib/catissue/domain/collection_protocol_test.rb +0 -1
- data/test/lib/catissue/domain/participant_test.rb +74 -19
- data/test/lib/catissue/domain/specimen_collection_group_test.rb +14 -10
- data/test/lib/catissue/domain/specimen_test.rb +36 -60
- data/test/lib/catissue/domain/storage_type_test.rb +5 -5
- data/test/lib/catissue/domain/transfer_event_parameters_test.rb +14 -12
- data/test/lib/catissue/migration/test_case.rb +0 -1
- data/test/lib/catissue/test_case.rb +12 -12
- data/test/lib/examples/galena/tissue/domain/examples_test.rb +1 -1
- data/test/lib/examples/galena/tissue/migration/annotation_test.rb +9 -7
- data/test/lib/examples/galena/tissue/migration/frozen_test.rb +1 -1
- data/test/lib/examples/galena/tissue/migration/general_test.rb +1 -1
- data/test/lib/examples/galena/tissue/migration/registration_test.rb +3 -9
- data/test/lib/examples/galena/tissue/migration/seedify.rb +3 -3
- data/test/lib/examples/pcbin/migration_test.rb +37 -16
- metadata +24 -10
- 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
|
-
|
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
|
-
|
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
|
96
|
-
annotation.
|
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
|
-
|
22
|
-
Annotation::AnnotationService.new(@database, name,
|
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
|
42
|
-
#
|
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
|
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
|
74
|
-
#
|
75
|
-
#
|
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
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
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
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
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
|
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
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
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
|
-
#
|
18
|
-
#
|
19
|
-
#
|
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
|
-
#
|
22
|
-
#
|
23
|
-
#
|
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
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
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
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
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
|
-
|
50
|
+
next_id = max + 1
|
51
51
|
# End of work-around
|
52
52
|
|
53
|
-
logger.debug { "Next #{table} identifier is #{
|
54
|
-
|
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
|
-
|
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(
|
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
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
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
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
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::
|
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
|
93
|
-
|
94
|
-
|
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
|
-
|
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
|
+
|
@@ -22,28 +22,28 @@ module CaTissue
|
|
22
22
|
:event_parameters => :specimen_events,
|
23
23
|
:characteristics => :specimen_characteristics)
|
24
24
|
|
25
|
-
# caTissue
|
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
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
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
|
36
|
-
#
|
35
|
+
# @quirk caTissue Specimen characteristics is cascaded but is not an exclusive dependent,
|
36
|
+
# since it is shared by aliquots.
|
37
37
|
#
|
38
|
-
# caTissue
|
39
|
-
#
|
40
|
-
#
|
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
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
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.
|
251
|
+
CaTissue.const_get(cls_nm)
|
252
252
|
end
|
253
253
|
|
254
254
|
# Creates a derived specimen.
|