caruby-tissue 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/bin/crtdump +11 -3
- data/bin/{seed → crtseed} +0 -0
- data/conf/annotation/pathology_scg/AdditionalFinding.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/BasePathologyAnnotation.hbm.xml +260 -0
- data/conf/annotation/pathology_scg/BreastMargin.hbm.xml +21 -0
- data/conf/annotation/pathology_scg/BreastMarginInvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/BreastMarginUninvolved.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/CNSMargin.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/CNSMarginLocation.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/CarcinomaInSituStatus.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ColorectalLocalExcisionMarginUninvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ColorectalResectedMarginUninvolved.hbm.xml +22 -0
- data/conf/annotation/pathology_scg/Cytogenetics.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/DeepMelanomaMargin.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/Details.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/DirectExtensionOfTumor.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/DistalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/DistanceFromAnalVerge.hbm.xml +23 -0
- data/conf/annotation/pathology_scg/DistantMetastasis.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/ExcionalBiopsyMarginUninvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExcisionalBiopsyColorectalDeepMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExcisionalBiopsyColorectalLateralOrMucosalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExtraprostaticExtension.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/ExtraprostaticExtensionTissueSites.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/GleasonScore.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/HistologicGrade.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/HistologicType.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/HistologicVariantType.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ImmunoPhenotyping.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/Invasion.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/KidneyMarginLocation.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/KidneyNephrectomyMargin.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/LateralMelanomaMargin.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/LocalExcisionColorectalDeepMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/LocalExcisionColorectalLateralMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/LungResectionMargin.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/LungResectionMarginsUninvolved.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/MacroscopicExtentOfTumor.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/MesentricMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/MetastasisTissueSite.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/Microcalcification.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/NottinghamHistologicScore.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/OtherResectedOrgans.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PancreasMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/PancreasMarginInvolvedByInvasiveCarcinoma.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PancreasMarginUninvolvedByInvasiveCarcinoma.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/PathologicalStaging.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/PolypConfiguration.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PrimaryTumorStage.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ProstateMarginLocation.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ProximalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/RadialMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/RadicalProstatectomyMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/RegionalLymphNode.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/SatelliteNodule.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/SpecimenCollectionGroup.hbm.xml +87 -0
- data/conf/annotation/pathology_scg/SpecimenIntegrity.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/SpecimenSize.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/TissueSide.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/TumorSize.hbm.xml +29 -0
- data/conf/annotation/pathology_scg/TumorTissueSite.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/UninvolvedMelanomaMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_specimen/AdditionalFinding.hbm.xml +19 -0
- data/conf/annotation/pathology_specimen/AdditionalPathologicFinding.hbm.xml +18 -0
- data/conf/annotation/pathology_specimen/Details.hbm.xml +15 -0
- data/conf/annotation/pathology_specimen/GleasonScore.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/HistologicGrade.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/HistologicType.hbm.xml +19 -0
- data/conf/annotation/pathology_specimen/HistologicVariantType.hbm.xml +14 -0
- data/conf/annotation/pathology_specimen/Invasion.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/NottinghamHistologicScore.hbm.xml +17 -0
- data/conf/annotation/pathology_specimen/Specimen.hbm.xml +52 -0
- data/conf/annotation/pathology_specimen/SpecimenBaseSolidTissuePathologyAnnotation.hbm.xml +73 -0
- data/examples/galena/lib/galena/cli/seed.rb +0 -21
- data/examples/galena/lib/galena/migration/frozen_shims.rb +6 -5
- data/examples/galena/lib/galena/seed/defaults.rb +0 -5
- data/{lib → examples/galena/lib}/galena.rb +0 -0
- data/lib/catissue/annotation/annotatable.rb +37 -0
- data/lib/catissue/annotation/annotatable_class.rb +255 -0
- data/lib/catissue/annotation/annotation.rb +49 -0
- data/lib/catissue/annotation/annotation_class.rb +277 -0
- data/lib/catissue/annotation/annotation_module.rb +77 -0
- data/lib/catissue/annotation/hibernate_mapping.rb +46 -0
- data/lib/catissue/annotation/proxy.rb +28 -0
- data/lib/catissue/annotation/proxy_class.rb +68 -0
- data/lib/catissue/cli/migrate.rb +2 -2
- data/lib/catissue/cli/smoke.rb +6 -4
- data/lib/catissue/database/annotation/annotation_service.rb +75 -61
- data/lib/catissue/database/annotation/annotator.rb +17 -76
- data/lib/catissue/database/annotation/entity_facade.rb +265 -0
- data/lib/catissue/database/annotation/id_generator.rb +62 -0
- data/lib/catissue/database/annotation/integration_service.rb +105 -59
- data/lib/catissue/database/annotation/reference_writer.rb +150 -0
- data/lib/catissue/database/controlled_values.rb +12 -12
- data/lib/catissue/database.rb +148 -58
- data/lib/catissue/domain/abstract_specimen.rb +40 -14
- data/lib/catissue/domain/abstract_specimen_collection_group.rb +1 -3
- data/lib/catissue/domain/collection_protocol.rb +13 -5
- data/lib/catissue/domain/collection_protocol_event.rb +1 -14
- data/lib/catissue/domain/consent_tier_response.rb +2 -0
- data/lib/catissue/domain/consent_tier_status.rb +5 -3
- data/lib/catissue/domain/container.rb +14 -10
- data/lib/catissue/domain/container_position.rb +8 -0
- data/lib/catissue/domain/container_type.rb +13 -6
- data/lib/catissue/domain/participant.rb +15 -10
- data/lib/catissue/domain/site.rb +9 -3
- data/lib/catissue/domain/specimen.rb +79 -40
- data/lib/catissue/domain/specimen_array.rb +11 -1
- data/lib/catissue/domain/specimen_collection_group.rb +79 -41
- data/lib/catissue/domain/specimen_event_parameters.rb +5 -8
- data/lib/catissue/domain/specimen_position.rb +0 -2
- data/lib/catissue/domain/specimen_requirement.rb +1 -1
- data/lib/catissue/domain/storage_container.rb +109 -48
- data/lib/catissue/domain/storage_type.rb +1 -1
- data/lib/catissue/migration/migrator.rb +6 -14
- data/lib/catissue/resource.rb +18 -8
- data/lib/catissue/util/position.rb +11 -1
- data/lib/catissue/util/storable.rb +18 -11
- data/lib/catissue/util/storage_type_holder.rb +44 -6
- data/lib/catissue/version.rb +1 -1
- metadata +86 -35
- data/bin/migrate.rb +0 -42
- data/bin/seed.rb +0 -43
- data/examples/galena/doc/CaTissue/Participant.html +0 -241
- data/examples/galena/doc/CaTissue/SpecimenCollectionGroup.html +0 -190
- data/examples/galena/doc/CaTissue/StorageContainer.html +0 -179
- data/examples/galena/doc/CaTissue/TissueSpecimen.html +0 -320
- data/examples/galena/doc/CaTissue.html +0 -93
- data/examples/galena/doc/Galena/Seed/Defaults.html +0 -650
- data/examples/galena/doc/Galena/Seed.html +0 -203
- data/examples/galena/doc/Galena.html +0 -172
- data/examples/galena/doc/_index.html +0 -181
- data/examples/galena/doc/class_list.html +0 -36
- data/examples/galena/doc/css/common.css +0 -1
- data/examples/galena/doc/css/full_list.css +0 -53
- data/examples/galena/doc/css/style.css +0 -307
- data/examples/galena/doc/file.README.html +0 -153
- data/examples/galena/doc/file_list.html +0 -38
- data/examples/galena/doc/frames.html +0 -13
- data/examples/galena/doc/index.html +0 -153
- data/examples/galena/doc/js/app.js +0 -202
- data/examples/galena/doc/js/full_list.js +0 -149
- data/examples/galena/doc/js/jquery.js +0 -154
- data/examples/galena/doc/method_list.html +0 -163
- data/examples/galena/doc/top-level-namespace.html +0 -112
- data/lib/README.html +0 -33
- data/lib/catissue/database/annotation/annotatable_service.rb +0 -25
- data/lib/catissue/database/annotation/entity_manager.rb +0 -10
- data/lib/galena/cli/seed.rb +0 -43
- data/lib/galena/migration/filter_shims.rb +0 -43
- data/lib/galena/migration/frozen_shims.rb +0 -53
- data/lib/galena/seed/defaults.rb +0 -109
@@ -28,18 +28,6 @@ module CaTissue
|
|
28
28
|
class ControlledValues
|
29
29
|
include Singleton
|
30
30
|
|
31
|
-
PUBLIC_ID_ROOTS_STMT = "select identifier, value from catissue_permissible_value where public_id = ? and parent_identifier is null or parent_identifier = 0"
|
32
|
-
|
33
|
-
CHILDREN_STMT = "select identifier, value from catissue_permissible_value where parent_identifier = ?"
|
34
|
-
|
35
|
-
INSERT_STMT = "insert into catissue_permissible_value (identifier, parent_identifier, public_id, value) values (?, ?, ?, ?)"
|
36
|
-
|
37
|
-
DELETE_STMT = "delete from catissue_permissible_value where identifier = ?"
|
38
|
-
|
39
|
-
MAX_ID_STMT = "select max(identifier) from catissue_permissible_value"
|
40
|
-
|
41
|
-
SEARCH_STMT = "select identifier from catissue_permissible_value where value collate latin1_bin = ?"
|
42
|
-
|
43
31
|
def initialize
|
44
32
|
# the default database name, used for direct database access
|
45
33
|
CaTissue.access_properties[:database] ||= CaTissue::Database::DEF_DATABASE_NAME
|
@@ -99,6 +87,18 @@ module CaTissue
|
|
99
87
|
|
100
88
|
private
|
101
89
|
|
90
|
+
PUBLIC_ID_ROOTS_STMT = "select identifier, value from catissue_permissible_value where public_id = ? and parent_identifier is null or parent_identifier = 0"
|
91
|
+
|
92
|
+
CHILDREN_STMT = "select identifier, value from catissue_permissible_value where parent_identifier = ?"
|
93
|
+
|
94
|
+
INSERT_STMT = "insert into catissue_permissible_value (identifier, parent_identifier, public_id, value) values (?, ?, ?, ?)"
|
95
|
+
|
96
|
+
DELETE_STMT = "delete from catissue_permissible_value where identifier = ?"
|
97
|
+
|
98
|
+
MAX_ID_STMT = "select max(identifier) from catissue_permissible_value"
|
99
|
+
|
100
|
+
SEARCH_STMT = "select identifier from catissue_permissible_value where value collate latin1_bin = ?"
|
101
|
+
|
102
102
|
def load_pid_cvs(pid)
|
103
103
|
fetch_cvs_with_public_id(pid, @pid_value_cv_hash[pid])
|
104
104
|
end
|
data/lib/catissue/database.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'caruby/util/topological_sync_enumerator'
|
3
3
|
require 'caruby/database'
|
4
|
-
|
5
|
-
#require 'catissue/database/annotation/annotator'
|
4
|
+
require 'catissue/database/annotation/annotator'
|
6
5
|
require 'catissue/domain/scg_event_parameters'
|
7
6
|
|
8
7
|
module CaTissue
|
@@ -12,20 +11,58 @@ module CaTissue
|
|
12
11
|
# around caTissue and caCORE bugs.
|
13
12
|
class Database < CaRuby::Database
|
14
13
|
include Singleton
|
15
|
-
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
# The default database name
|
20
|
-
DEF_DATABASE_NAME = 'catissue'
|
14
|
+
|
15
|
+
# return [CaRuby::SQLExecutor] a utility SQL executor
|
16
|
+
attr_reader :executor
|
21
17
|
|
22
18
|
# Creates a new Database with the {SERVICE_NAME} service and {CaTissue.access_properties}.
|
23
19
|
def initialize
|
24
20
|
super(SERVICE_NAME, CaTissue.access_properties)
|
21
|
+
@executor = CaRuby::SQLExecutor.new(CaTissue.access_properties)
|
25
22
|
end
|
26
23
|
|
24
|
+
# @return [Annotator] the annotator utility
|
25
|
+
def annotator
|
26
|
+
@annotator ||= Annotator.new(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
# If the given domain object is an {Annotation}, then this method returns the {AnnotationService}
|
30
|
+
# for the object {AnnotationModule}, otherwise this method returns the standard {CaTissue::Database}
|
31
|
+
# service.
|
32
|
+
#
|
33
|
+
# @return (see CaRuby::Database#persistence_service)
|
34
|
+
def persistence_service(obj)
|
35
|
+
Annotation === obj ? obj.class.domain_module.persistence_service : super
|
36
|
+
end
|
37
|
+
|
38
|
+
# Augments {CaRuby::Database#ensure_exists} to ensure that an {Annotation::Proxy} reference identifier
|
39
|
+
# reflects the hook identifier.
|
40
|
+
#
|
41
|
+
# @param (see CaRuby::Database#ensure_exists)
|
42
|
+
def ensure_exists(ref)
|
43
|
+
if Annotation::Proxy === ref then
|
44
|
+
ref.ensure_identifier_reflects_hook
|
45
|
+
end
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
27
49
|
private
|
28
50
|
|
51
|
+
# The application service name
|
52
|
+
SERVICE_NAME = 'catissuecore'
|
53
|
+
|
54
|
+
# The default database name
|
55
|
+
DEF_DATABASE_NAME = 'catissue'
|
56
|
+
|
57
|
+
# Returns whether the given specimens are compatible. The target is compatible with the source
|
58
|
+
# if each of the following conditions hold:
|
59
|
+
# * The specimen types are equal or the source specimen type is +Not Specified+
|
60
|
+
# * The specimen pathological statuses are equal or the source pathological status is +Not Specified+
|
61
|
+
# * The parent specimens are compatible, if they exist
|
62
|
+
#
|
63
|
+
# @param [Resource] target the mnerge target specimen
|
64
|
+
# @param [Resource] source the mnerge source specimen
|
65
|
+
# @return [Boolean] whether the specimens are compatible
|
29
66
|
def specimen_compatible?(target, source)
|
30
67
|
target.class === source and
|
31
68
|
specimen_parent_compatible?(target, source) and
|
@@ -33,6 +70,7 @@ module CaTissue
|
|
33
70
|
(target.pathological_status == source.pathological_status or source.pathological_status == 'Not Specified')
|
34
71
|
end
|
35
72
|
|
73
|
+
# @see #specimen_compatible?
|
36
74
|
def specimen_parent_compatible?(target, source)
|
37
75
|
if target.parent then
|
38
76
|
source.parent and source.parent.identifier == target.parent.identifier
|
@@ -50,6 +88,11 @@ module CaTissue
|
|
50
88
|
# s1.identifier == s3.identifier. Thus, enforcing reference consistency requires a post-fetch step
|
51
89
|
# that matches the fetched objects to the original query result on identifier and resets the
|
52
90
|
# references.
|
91
|
+
#
|
92
|
+
# Not yet enabled. TODO - plug this into fetch_object.
|
93
|
+
#
|
94
|
+
# @param [<Resource>] refs the fetched domain objects
|
95
|
+
# @param [Symbol] attribute the owner attribute
|
53
96
|
def resolve_parent(refs, attribute)
|
54
97
|
id_ref_hash = refs.to_compact_hash { |ref| ref.identifier }.invert
|
55
98
|
refs.each do |ref|
|
@@ -68,7 +111,7 @@ module CaTissue
|
|
68
111
|
# @return (see CaRuby::Database#update_object)
|
69
112
|
def update_object(obj)
|
70
113
|
if scg_event_parameters?(obj) then
|
71
|
-
|
114
|
+
save_scg_event_parameters(obj)
|
72
115
|
else
|
73
116
|
if CaTissue::Specimen === obj
|
74
117
|
# Specimen activity status is not always set to default; don't know why.
|
@@ -94,12 +137,16 @@ module CaTissue
|
|
94
137
|
|
95
138
|
# Returns whether operation is the second SCG Update described in {#recursive_save?}.
|
96
139
|
def scg_event_update_workaround?(obj, operation)
|
97
|
-
|
140
|
+
# Is this an SCG update?
|
141
|
+
return false unless CaTissue::SpecimenCollectionGroup === obj and operation == :update
|
98
142
|
last = @operations.last
|
143
|
+
# Is the nesting operation on an SEP?
|
99
144
|
return false unless last and scg_event_parameters?(last.subject)
|
100
145
|
ev = last.subject
|
146
|
+
# Is the SEP SCG the same as the target SCG?
|
101
147
|
return false unless ev.specimen_collection_group == obj
|
102
148
|
penultimate = @operations[-2]
|
149
|
+
# Is the operation which nests the SEP operation a SCG update on the same SCG?
|
103
150
|
penultimate and penultimate.subject == obj
|
104
151
|
end
|
105
152
|
|
@@ -178,9 +225,9 @@ module CaTissue
|
|
178
225
|
SCGEventParameters === obj and obj.specimen_collection_group
|
179
226
|
end
|
180
227
|
|
181
|
-
# @param [SCGEventParameters] ep the SCG event parameters to
|
228
|
+
# @param [SCGEventParameters] ep the SCG event parameters to save
|
182
229
|
# @return (see CaRuby::Database#update_object)
|
183
|
-
def
|
230
|
+
def save_scg_event_parameters(ep)
|
184
231
|
scg = ep.specimen_collection_group
|
185
232
|
logger.debug { "Work around #{ep.qp} caTissue SCG SpecimenEventParameters update bug by updating the owner #{scg.qp} instead..." }
|
186
233
|
ensure_exists(scg)
|
@@ -238,10 +285,19 @@ module CaTissue
|
|
238
285
|
save_dependent(dsp)
|
239
286
|
end
|
240
287
|
end
|
288
|
+
|
289
|
+
# Overrides {CaRuby::Database#build_save_template} to return obj itself if
|
290
|
+
# obj is an {Annotation}, since annotations do not employ a separate template.
|
291
|
+
#
|
292
|
+
# @param (see CaRuby::Database#build_save_template)
|
293
|
+
# @return (see CaRuby::Database#build_save_template)
|
294
|
+
def build_save_template(obj, builder)
|
295
|
+
Annotation === obj ? obj : super
|
296
|
+
end
|
241
297
|
|
242
298
|
# Overrides {CaRuby::Database::Writer#save_with_template} to work around the following
|
243
299
|
# caTissue bugs:
|
244
|
-
# * caTissue alert - Bug
|
300
|
+
# * caTissue alert - Bug: CollectionProtocolRegistration must cascade through
|
245
301
|
# CP, but the CP events cannot cascade to SpecimenRequirement without raising an
|
246
302
|
# Exception. Work-around is to clear the template CP events.
|
247
303
|
# * caTissue alert - Bug #164: Update Specimen with unchanged ExternalIdentifier fails.
|
@@ -257,27 +313,43 @@ module CaTissue
|
|
257
313
|
end
|
258
314
|
logger.debug { "Work around caTissue Bug #164 by setting the #{obj.qp} update template #{template.qp} external_identifiers to nil." }
|
259
315
|
template.external_identifiers = nil
|
316
|
+
elsif Annotation === obj and obj.class.proxy_attribute then
|
317
|
+
copy_annotation_proxy_owner_to_template(obj, template)
|
260
318
|
end
|
261
319
|
super
|
262
320
|
end
|
321
|
+
|
322
|
+
# The annotation proxy is not copied because the attribute redirects to the hook rather
|
323
|
+
# than the proxy. Set the template copy source proxy to the target object proxy using
|
324
|
+
# the low-level Java property methods instead.
|
325
|
+
#
|
326
|
+
# @param [Annotation] obj the copy source
|
327
|
+
# @param [Annotation] template the copy target
|
328
|
+
def copy_annotation_proxy_owner_to_template(obj, template)
|
329
|
+
pxy_attr = obj.class.proxy_attribute
|
330
|
+
attr_md = obj.class.attribute_metadata(pxy_attr)
|
331
|
+
# Ignore the proxy attribute if it is defined by caRuby rather than caTissue.
|
332
|
+
return unless attr_md.java_property?
|
333
|
+
rdr, wtr = obj.class.attribute_metadata(pxy_attr).property_accessors
|
334
|
+
pxy = obj.send(rdr)
|
335
|
+
logger.debug { "Setting #{obj.qp} template #{template.qp} proxy owner to #{pxy}..." }
|
336
|
+
template.send(wtr, pxy)
|
337
|
+
end
|
263
338
|
|
264
339
|
# Augment {CaRuby::Database::Writer#create_object} for the following work-arounds:
|
265
340
|
# * caTissue alert - Bug #124: SpecimenEventParameters with SCG rather than Specimen fails validation.
|
266
|
-
# Work-around is to create the SEP
|
267
|
-
#
|
268
|
-
# * if obj is a CaTissue::Specimen with the is_available flag set to false, then work around the bug
|
341
|
+
# Work-around is to create the SEP by updating the SCG.
|
342
|
+
# * If obj is a CaTissue::Specimen with the is_available flag set to false, then work around the bug
|
269
343
|
# described in {#create_unavailable_specimen}.
|
270
344
|
# * caTissue alert - Bug #161: Specimen API disposal not reflected in result activity status.
|
271
345
|
# DisposalEventParameters create sets the owner Specimen activity_status to +Closed+ as a side-effect.
|
272
346
|
# Reflect this side-effect in the submitted DisposalEventParameters owner Specimen object.
|
273
|
-
#
|
274
|
-
#
|
275
|
-
# CPR CP references as a pre-requisite. TODO - isolate, report and fix.
|
347
|
+
#
|
348
|
+
# @param [Resource] obj the dependent domain object to save
|
276
349
|
def create_object(obj)
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
if CaTissue::Specimen === obj then
|
350
|
+
if scg_event_parameters?(obj) then
|
351
|
+
save_scg_event_parameters(obj)
|
352
|
+
elsif CaTissue::Specimen === obj then
|
281
353
|
obj.add_defaults
|
282
354
|
if obj.is_available == false or obj.available_quantity.zero? then
|
283
355
|
# Note that the obj.is_available == false test is required as opposed to obj.is_available?,
|
@@ -363,10 +435,8 @@ module CaTissue
|
|
363
435
|
|
364
436
|
def fetch_alternative(obj)
|
365
437
|
case obj
|
366
|
-
|
367
|
-
|
368
|
-
when CaTissue::Participant then
|
369
|
-
fetch_participant_alternative(obj)
|
438
|
+
when CaTissue::Specimen then fetch_specimen_alternative(obj)
|
439
|
+
when CaTissue::Participant then fetch_participant_alternative(obj)
|
370
440
|
end
|
371
441
|
end
|
372
442
|
|
@@ -386,28 +456,66 @@ module CaTissue
|
|
386
456
|
|
387
457
|
# caTissue alert - Bug #147: SpecimenRequirement query ignores CPE.
|
388
458
|
# Work around this bug by an inverted query on the referenced CPE.
|
459
|
+
#
|
460
|
+
# caTissue alert - Accessing an annotation hook DE proxy attribute uses a separate mechanism.
|
461
|
+
# Redirect the query to the annotation integration service in that case.
|
462
|
+
#
|
463
|
+
# caTissue alert - Bug #169: ContainerPosition occupied container query returns parent
|
464
|
+
# container instead. Substitute a hard-coded HQL search for this case.
|
465
|
+
#
|
466
|
+
# @see CaRuby::Database#query_object
|
389
467
|
def query_object(obj, attribute=nil)
|
390
|
-
if
|
468
|
+
if hook_proxy_attribute?(obj, attribute) then
|
469
|
+
query_hook_proxy(obj, attribute)
|
470
|
+
elsif CaTissue::SpecimenRequirement === obj and not obj.identifier and obj.collection_protocol_event then
|
391
471
|
query_requirement_using_cpe_inversion(obj, attribute)
|
472
|
+
elsif CaTissue::ContainerPosition === obj and obj.identifier and attribute == :occupied_container then
|
473
|
+
query_container_position_occupied_container(obj, attribute)
|
392
474
|
else
|
393
475
|
super
|
394
476
|
end
|
395
477
|
end
|
396
|
-
|
478
|
+
|
479
|
+
def query_container_position_occupied_container(obj, attribute)
|
480
|
+
logger.debug { "Work around caTissue bug by querying #{obj} #{attribute} using HQL..." }
|
481
|
+
src = obj.class.java_class.name
|
482
|
+
query("select pos.occupiedContainer from #{src} pos where pos.id = #{obj.identifier}")
|
483
|
+
end
|
484
|
+
|
485
|
+
# @param (see #query_object)
|
486
|
+
# @return [Boolean] whether the given attribute is a reference from an {Annotatable} to a #{Annotation}
|
487
|
+
def hook_proxy_attribute?(obj, attribute)
|
488
|
+
return false if attribute.nil?
|
489
|
+
attr_md = obj.class.attribute_metadata(attribute)
|
490
|
+
attr_md.declarer < Annotatable and attr_md.type < Annotation
|
491
|
+
end
|
492
|
+
|
493
|
+
# Queries on the given object attribute using the {Annotation::IntegationService}.
|
494
|
+
#
|
495
|
+
# @param (see #query_object)
|
496
|
+
# @result (see #query_object)
|
497
|
+
def query_hook_proxy(hook, attribute)
|
498
|
+
unless hook.identifier then
|
499
|
+
logger.debug { "Querying annotation hook #{hook.qp} proxy reference #{attribute} by collecting the matching #{hook.class.qp} proxy references..." }
|
500
|
+
return query(hook).map { |ref| query_hook_proxy(ref, attribute) }.flatten
|
501
|
+
end
|
502
|
+
proxy = hook.annotation_proxy(attribute)
|
503
|
+
# update the proxy identifier if necessary
|
504
|
+
proxy.identifier ||= hook.identifier
|
505
|
+
# delegate to the integration service to find the referenced hook annotation proxies
|
506
|
+
logger.debug { "Delegating #{hook.qp} annotation #{attribute} query to proxy #{proxy} integration service query..." }
|
507
|
+
annotator.integration_service.query(proxy, attribute)
|
508
|
+
end
|
509
|
+
|
397
510
|
# caCORE alert - Override {CaRuby::Database::Reader#invertible_query?} to enable the Bug #147 work
|
398
511
|
# around in {#query_object}. Invertible queries are performed to work around Bug #79. However, this
|
399
512
|
# work-around induces Bug #147, so we disable the Bug #79 work-around here for the special case of
|
400
513
|
# a CPE in order to enable the Bug #147 work-around. And so it goes....
|
514
|
+
#
|
515
|
+
# @see CaRuby::Database#invertible_query?
|
401
516
|
def invertible_query?(obj, attribute)
|
402
|
-
super and not (
|
403
|
-
|
404
|
-
|
405
|
-
# Returns the Annotation::Annotator service for klass, or nil if klass is neither annotatable nor an annotation.
|
406
|
-
def annotation_service(klass)
|
407
|
-
# create the single annotator on demand
|
408
|
-
@annotator ||= CaTissue::Annotation::Annotator.new(self)
|
409
|
-
# find the service or return nil if kla
|
410
|
-
@annotator.service(klass)
|
517
|
+
super and not (hook_proxy_attribute?(obj, attribute) or
|
518
|
+
(CaTissue::CollectionProtocolEvent === obj and attribute == :specimen_requirements))
|
411
519
|
end
|
412
520
|
|
413
521
|
def fetch_participant_alternative(pnt)
|
@@ -427,23 +535,6 @@ module CaTissue
|
|
427
535
|
pmi = pnt.medical_identifiers.first
|
428
536
|
return if pmi.nil?
|
429
537
|
logger.debug { "Using alternative Participant fetch strategy to find Participant by medical record number..." }
|
430
|
-
|
431
|
-
#
|
432
|
-
# TODO - hack to work around intricate add_default logic; ties in with the create participant hack in this class.
|
433
|
-
# FIX THIS!!
|
434
|
-
#
|
435
|
-
if pmi.site.nil? then
|
436
|
-
# fetch Participant CPR protocols if necessary
|
437
|
-
pnt.registrations.each do |reg|
|
438
|
-
pcl = reg.protocol || next
|
439
|
-
pcl.find unless pcl.identifier
|
440
|
-
reg.add_defaults
|
441
|
-
end
|
442
|
-
pnt.add_defaults
|
443
|
-
end
|
444
|
-
|
445
|
-
# END OF HACK
|
446
|
-
|
447
538
|
return unless exists?(pmi)
|
448
539
|
candidates = query(pmi.copy, :participant)
|
449
540
|
candidates.first if candidates.size == 1
|
@@ -463,11 +554,10 @@ module CaTissue
|
|
463
554
|
query(spc)
|
464
555
|
end
|
465
556
|
|
466
|
-
def query_requirement_using_cpe_inversion(rqmt,
|
557
|
+
def query_requirement_using_cpe_inversion(rqmt, *path)
|
467
558
|
cpe = rqmt.collection_protocol_event
|
468
559
|
logger.debug { "Using alternative SpecimenRequirement query strategy to find SpecimenRequirements by inverted CPE reference #{cpe}..." }
|
469
|
-
path
|
470
|
-
path << attribute if attribute
|
560
|
+
path.unshift(:specimen_requirements)
|
471
561
|
query(cpe, *path)
|
472
562
|
end
|
473
563
|
end
|
@@ -9,6 +9,8 @@ module CaTissue
|
|
9
9
|
|
10
10
|
# Sets the specimen type to the specified value. The value can be a permissible caTissue String value or
|
11
11
|
# the shortcut symbols :fresh, :fixed and :frozen.
|
12
|
+
#
|
13
|
+
# @param [String, Symbol, nil] value the value to set
|
12
14
|
def specimen_type=(value)
|
13
15
|
value = value.to_s.capitalize_first + ' Tissue' if Symbol === value
|
14
16
|
setSpecimenType(value)
|
@@ -24,7 +26,7 @@ module CaTissue
|
|
24
26
|
# caTissue alert - initial_quantity must be set (cf. Bug #160)
|
25
27
|
add_attribute_defaults(:initial_quantity => 0.0, :pathological_status => 'Not Specified', :specimen_type => 'Not Specified')
|
26
28
|
|
27
|
-
add_mandatory_attributes(:lineage, :pathological_status, :specimen_class, :specimen_type)
|
29
|
+
add_mandatory_attributes(:lineage, :pathological_status, :specimen_class, :specimen_type, :specimen_characteristics)
|
28
30
|
|
29
31
|
# Specimen characteristics are auto-generated but SpecimenRequirement characteristics are not.
|
30
32
|
# It is safe to set the :autogenerated flag for both AbstractSpecimen subclasses. This results
|
@@ -35,18 +37,21 @@ module CaTissue
|
|
35
37
|
# Guard against updating a Specimen with a SpecimenCharacteristics whose id differs from
|
36
38
|
# the existing id.
|
37
39
|
#
|
40
|
+
# caTissue alert - Unlike most dependents, AbstractSpecimen characteristics, events and child
|
41
|
+
# specimens have cascade style 'all'. This implies that an AbstractSpecimen update does not
|
42
|
+
# create a referenced dependent. AbstractSpecimen create cascades to create and AbstractSpecimen
|
43
|
+
# update cascades to update, but AbstractSpecimen update does not cascade to create.
|
44
|
+
#
|
38
45
|
# The :no_cascade_update_to_create flag is set since characteristics have cascade style 'all'.
|
39
46
|
add_dependent_attribute(:specimen_characteristics, :autogenerated, :no_cascade_update_to_create)
|
40
47
|
|
48
|
+
# The :no_cascade_update_to_create flag is set since events has cascade style 'all'.
|
41
49
|
add_dependent_attribute(:specimen_events, :create_only, :disjoint, :no_cascade_update_to_create)
|
50
|
+
|
51
|
+
# The :no_cascade_update_to_create flag is set since child specimens has cascade style 'all'.
|
52
|
+
add_dependent_attribute(:child_specimens, :unfetched, :no_cascade_update_to_create)
|
42
53
|
|
43
54
|
set_attribute_inverse(:parent_specimen, :child_specimens)
|
44
|
-
|
45
|
-
# caTissue alert - SCG specimens query result does not set the Specimen children and parent, even though they are
|
46
|
-
# guaranteed to be in the SCG specimens result set. The children and parent must be fetched separately, resulting
|
47
|
-
# in multiple copies of the same Specimen and additional fetches.
|
48
|
-
qualify_attribute(:parent_specimen)
|
49
|
-
qualify_attribute(:child_specimens, :no_cascade_update_to_create)
|
50
55
|
|
51
56
|
class SpecimenClass
|
52
57
|
TISSUE = 'Tissue'
|
@@ -64,6 +69,10 @@ module CaTissue
|
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
72
|
+
# Initializes this AbstractSpecimen. The default +specimen_class+ is inferred from this
|
73
|
+
# AbstractSpecimen instance's subclass.
|
74
|
+
#
|
75
|
+
# @param [{Symbol => Object}] params the specimen attribute => value hash
|
67
76
|
def initialize(params=nil)
|
68
77
|
super
|
69
78
|
self.specimen_class ||= infer_specimen_class(self.class)
|
@@ -140,9 +149,8 @@ module CaTissue
|
|
140
149
|
# e.g. 3090_3 for the third child in parent specimen with label 3090.
|
141
150
|
#
|
142
151
|
# @return the new derived specimen if _count_ is one, otherwise an Array of _count_ derived specimens
|
143
|
-
#
|
144
|
-
#
|
145
|
-
# or the derived specimen quantities exceed the parent _available_quantity_.
|
152
|
+
# @raise [ValidationError] if an aliquoted parent available quantity is not greater than zero
|
153
|
+
# or the derived specimen quantities exceed the parent available quantity
|
146
154
|
def derive(params={})
|
147
155
|
# add defaults
|
148
156
|
add_defaults if specimen_class.nil?
|
@@ -195,6 +203,9 @@ module CaTissue
|
|
195
203
|
|
196
204
|
# Sets special aliquot parameters for the given count of aliquots.
|
197
205
|
# This default implementation is a no-op. Subclasses can override.
|
206
|
+
#
|
207
|
+
# @param [{Symbol => Object}] params the specimen attribute => value hash
|
208
|
+
# @param [Integer] count the number of aliquots
|
198
209
|
def set_aliquot_parameters(params, count); end
|
199
210
|
|
200
211
|
def add_defaults_local
|
@@ -215,6 +226,9 @@ module CaTissue
|
|
215
226
|
# 'SpecimenRequirement' depending on this AbstractSpecimen's subclass. If the
|
216
227
|
# :specimen_class parameter is missing and there is a :specimen_requirement parameter,
|
217
228
|
# then the specimen requirement specimen_class attribute value is used.
|
229
|
+
#
|
230
|
+
# @param [{Symbol => Object}] params the specimen attribute => value hash
|
231
|
+
# @return [Class] the AbstactSpecimen subclass to use
|
218
232
|
def infer_class(params)
|
219
233
|
opt = params[:specimen_class]
|
220
234
|
if opt.nil? then
|
@@ -229,6 +243,10 @@ module CaTissue
|
|
229
243
|
CaTissue.domain_type_with_name(cls_nm)
|
230
244
|
end
|
231
245
|
|
246
|
+
# Creates a derived specimen.
|
247
|
+
#
|
248
|
+
# @param [{Symbol => Object}] params the derived specimen attribute => value hash
|
249
|
+
# @return [Specimen] the derived specimen
|
232
250
|
def create_derived(params)
|
233
251
|
# Merge the non-domain attribute values from this specimen, unless there is a requirement.
|
234
252
|
# Precedence order is given params highest, requirements next, this specimen lowest
|
@@ -242,9 +260,11 @@ module CaTissue
|
|
242
260
|
spc
|
243
261
|
end
|
244
262
|
|
245
|
-
#
|
246
|
-
#
|
247
|
-
|
263
|
+
# Returns characteristics to use for a derived specimen. The new characteristics is copied from this
|
264
|
+
# parent specimen's characteristics, without the identifier.
|
265
|
+
#
|
266
|
+
# @return [CaTissue::SpecimenCharacteristics, nil] a copy of this Specimen's specimen_characteristics, or nil if none
|
267
|
+
def default_derived_characteristics
|
248
268
|
chrs = specimen_characteristics || return
|
249
269
|
attrs = chrs.class.nondomain_attributes.reject { |attr| attr == :identifier }
|
250
270
|
chrs.copy(attrs)
|
@@ -268,6 +288,8 @@ module CaTissue
|
|
268
288
|
# not just the same content. This odd condition is a caTissue artifact. A more sensible
|
269
289
|
# criterion is whether this Specimen and its parent share the same tissue_class and
|
270
290
|
# tissue_type, but so it goes.
|
291
|
+
#
|
292
|
+
# @return ['New', 'Aliqout', 'Derived'] the lineage to use
|
271
293
|
def default_lineage
|
272
294
|
if parent.nil? then
|
273
295
|
'New'
|
@@ -279,8 +301,12 @@ module CaTissue
|
|
279
301
|
end
|
280
302
|
|
281
303
|
# Infers the specimen class from the first word on the specified klass Ruby class name.
|
282
|
-
#
|
304
|
+
#
|
305
|
+
# @example
|
283
306
|
# infer_specimen_class(CaTissue::TissueRequirement) #=> "Tissue"
|
307
|
+
#
|
308
|
+
# @param [Class, nil] the AbstractSpecimen domain object class (default this specimen's class)
|
309
|
+
# @return [String] the +specimen_class+ value
|
284
310
|
def infer_specimen_class(klass=self.class)
|
285
311
|
klass.to_s[/(\w+?)(Specimen(Requirement)?)$/, 1] if klass
|
286
312
|
end
|
@@ -4,13 +4,11 @@ module CaTissue
|
|
4
4
|
class AbstractSpecimenCollectionGroup
|
5
5
|
include Resource
|
6
6
|
|
7
|
-
add_attribute_aliases(:
|
7
|
+
add_attribute_aliases(:diagnosis => :clinical_diagnosis)
|
8
8
|
|
9
9
|
add_attribute_defaults(:activity_status => 'Active', :clinical_status => 'Not Specified', :clinical_diagnosis => 'Not Specified')
|
10
10
|
|
11
11
|
add_mandatory_attributes(:activity_status)
|
12
|
-
|
13
|
-
qualify_attribute(:collection_site, :fetched)
|
14
12
|
|
15
13
|
# Overrides {CaRuby::Resource#each_dependent} to exclude Specimens or SpecimenRequirements with a parent,
|
16
14
|
# since parent is the immediate Specimen or SpecimenRequirement owner.
|
@@ -142,14 +142,14 @@ module CaTissue
|
|
142
142
|
# Returns the default protocol site, determined as follows:
|
143
143
|
# * If there is exactly one authorized site for this protocol, then that is the default site.
|
144
144
|
# * If there is exactly two authorized sites for this protocol, then the site other than the
|
145
|
-
# {CaTissue::Site
|
145
|
+
# {CaTissue::Site.default_site} is returned.
|
146
146
|
# * Otherwise, this method returns nil.
|
147
147
|
#
|
148
148
|
# @return [CaTissue::Site, nil] the default site
|
149
149
|
def default_site
|
150
150
|
case sites.size
|
151
151
|
when 1 then sites.first
|
152
|
-
when 2 then sites.select { |site| site.name != CaTissue::Site
|
152
|
+
when 2 then sites.select { |site| site.name != CaTissue::Site.default_site.name }
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
@@ -167,15 +167,23 @@ module CaTissue
|
|
167
167
|
self.title ||= short_title
|
168
168
|
self.short_title ||= title
|
169
169
|
self.start_date ||= Java::JavaUtil::Date.new
|
170
|
+
if sites.empty? then add_default_site end
|
170
171
|
if coordinators.empty? and sites.size == 1 then
|
171
172
|
coord = sites.first.coordinator
|
172
173
|
coordinators << coord if coord
|
173
|
-
elsif sites.empty? and coordinators.size == 1 then
|
174
|
-
site = coordinators.first.sites.first
|
175
|
-
sites << site if site
|
176
174
|
end
|
177
175
|
make_default_collection_event unless events.detect { |evt| CollectionProtocolEvent === evt }
|
178
176
|
end
|
177
|
+
|
178
|
+
def add_default_site
|
179
|
+
if coordinators.size == 1 then
|
180
|
+
site = coordinators.first.sites.first
|
181
|
+
else
|
182
|
+
site = CaTissue::Site.default_site
|
183
|
+
site.find unless site.identifier
|
184
|
+
end
|
185
|
+
sites << site
|
186
|
+
end
|
179
187
|
|
180
188
|
def make_default_collection_event
|
181
189
|
# make this protocol's CPE
|
@@ -33,10 +33,8 @@ module CaTissue
|
|
33
33
|
add_mandatory_attributes(:collection_protocol, :clinical_diagnosis, :specimen_requirements)
|
34
34
|
|
35
35
|
# caTissue alert - specimen_requirements is a cascaded dependent, but it is not fetched.
|
36
|
-
# It is marked as auto-generated, since it must be refetched and matched on CPE create.
|
37
36
|
# CollectionProtocol create cascades through each dependent CPE to each SpecimenRequirement.
|
38
|
-
|
39
|
-
add_dependent_attribute(:specimen_requirements, :autogenerated, :unfetched)
|
37
|
+
add_dependent_attribute(:specimen_requirements, :unfetched)
|
40
38
|
|
41
39
|
# The event point used for saving this CollectionProtocolEvent if none other is set.
|
42
40
|
DEFAULT_EVENT_POINT = 1.0
|
@@ -48,17 +46,6 @@ module CaTissue
|
|
48
46
|
self.specimen_collection_groups ||= Java::JavaUtil::LinkedHashSet.new
|
49
47
|
end
|
50
48
|
|
51
|
-
# Overrides {CaRuby::ResourceAttributes#mandatory_attributes} to correct the following caTissue bug:
|
52
|
-
#
|
53
|
-
# caTissue alert - specimen_collection_site is incorrectly attached in the caTissue class model
|
54
|
-
# to AbstractSpecimenCollectionGroup rather than SpecimenCollectionGroup. Since CollectionProtocolEvent
|
55
|
-
# is a subclass of AbstractSpecimenCollectionGroup and mandatory attributes are inherited,
|
56
|
-
# specimen_collection_site must be listed as optional here to counteract the effect of marking it
|
57
|
-
# as mandatory for a SCG (cf. caTissue Bug #116).
|
58
|
-
def mandatory_attributes
|
59
|
-
@mdtry_attrs_filter ||= @mandatory_attributes.filter { |attr| attr != :specimen_collection_site }
|
60
|
-
end
|
61
|
-
|
62
49
|
# Overrides the Java CollectionProtocolEvent hashCode to make the hash insensitive to identifier assignment.
|
63
50
|
def hash
|
64
51
|
# caTissue alert - caTissue determines the hashCode from the identifier. Consequently, a CollectionProtocolEvent
|
@@ -8,6 +8,8 @@ module CaTissue
|
|
8
8
|
add_mandatory_attributes(:consent_tier, :status)
|
9
9
|
|
10
10
|
add_attribute_defaults(:status => 'Not Specified')
|
11
|
+
|
12
|
+
qualify_attribute(:consent_tier, :fetched)
|
11
13
|
|
12
14
|
# Returns whether this ConsentTierStatus is minimally consistent with the other ConsentTierStatus.
|
13
15
|
# This method returns whether the referenced ConsentTier has the same identifer or statement text
|
@@ -21,9 +23,9 @@ module CaTissue
|
|
21
23
|
# Returns true if this ConsentTierStatus ConsentTier is nil, the other ConsentTierStatus ConsentTier is nil,
|
22
24
|
# both ConsentTier identifiers are equal, or both ConsentTier statements are equal.
|
23
25
|
def statement_match?(other)
|
24
|
-
ct =
|
25
|
-
oct = other.
|
26
|
-
ct
|
26
|
+
ct = consent_tier
|
27
|
+
oct = other.consent_tier
|
28
|
+
(ct.nil? or oct.nil?) or (ct.identifier == oct.identifier or ct.statement == oct.statement)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|