caruby-tissue 1.5.6 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +17 -0
- data/History.md +5 -1
- data/README.md +2 -2
- data/bin/crtdump +2 -8
- data/bin/crtexample +2 -5
- data/bin/crtmigrate +3 -6
- data/bin/crtsmoke +3 -8
- data/conf/wustl/{log4j.properties → linux/log4j.properties} +3 -3
- data/conf/wustl/windows/log4j.properties +40 -0
- data/examples/galena/Gemfile +16 -0
- data/examples/galena/Gemfile.lock +88 -0
- data/examples/galena/README.md +16 -16
- data/examples/galena/Rakefile +30 -0
- data/examples/galena/bin/seed +5 -11
- data/examples/galena/conf/annotation/defaults.yaml +2 -0
- data/examples/galena/conf/{migration/annotation_fields.yaml → annotation/fields.yaml} +2 -4
- data/examples/galena/conf/defaults.yaml +9 -0
- data/examples/galena/conf/{migration/filter_fields.yaml → filter/fields.yaml} +0 -1
- data/examples/galena/conf/filter/values.yaml +8 -0
- data/examples/galena/conf/{migration/frozen_defaults.yaml → frozen/defaults.yaml} +0 -0
- data/examples/galena/conf/{migration/frozen_fields.yaml → frozen/fields.yaml} +0 -2
- data/examples/galena/conf/{migration/general_fields.yaml → general/fields.yaml} +0 -24
- data/examples/galena/conf/registration/fields.yaml +6 -0
- data/examples/galena/conf/{migration/simple_fields.yaml → simple/fields.yaml} +1 -6
- data/examples/galena/data/annotation.csv +1 -1
- data/examples/galena/data/filter.csv +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/data/simple.csv +1 -1
- data/examples/galena/galena.gemspec +24 -0
- data/examples/galena/lib/galena/filter.rb +25 -0
- data/examples/galena/lib/galena/{tissue/migration/frozen_shims.rb → frozen.rb} +6 -10
- data/examples/galena/lib/galena/seed.rb +126 -0
- data/examples/galena/lib/galena/version.rb +3 -0
- data/examples/galena/lib/galena.rb +18 -7
- data/examples/galena/log/galena.log +37351 -0
- data/examples/galena/log/galena.log.0 +147830 -0
- data/examples/galena/spec/annotation_spec.rb +46 -0
- data/examples/galena/spec/filter_spec.rb +94 -0
- data/examples/galena/spec/frozen_spec.rb +39 -0
- data/examples/galena/spec/general_spec.rb +62 -0
- data/examples/galena/spec/registration_spec.rb +37 -0
- data/examples/galena/spec/seed.rb +107 -0
- data/examples/galena/spec/simple_spec.rb +58 -0
- data/examples/galena/spec/spec_helper.rb +11 -0
- data/examples/galena/spec/support/migration.rb +70 -0
- data/lib/catissue/annotation/annotatable.rb +10 -8
- data/lib/catissue/annotation/annotation.rb +7 -7
- data/lib/catissue/annotation/de_integration.rb +9 -20
- data/lib/catissue/annotation/importer.rb +148 -0
- data/lib/catissue/annotation/introspector.rb +32 -0
- data/lib/catissue/annotation/metadata.rb +422 -0
- data/lib/catissue/annotation/proxy.rb +2 -2
- data/lib/catissue/annotation/proxy_class.rb +45 -30
- data/lib/catissue/annotation/record_entry_proxy.rb +2 -2
- data/lib/catissue/cli/command.rb +14 -24
- data/lib/catissue/cli/example.rb +5 -3
- data/lib/catissue/cli/migrate.rb +45 -37
- data/lib/catissue/cli/smoke.rb +2 -3
- data/lib/catissue/database/annotation/annotation_service.rb +8 -17
- data/lib/catissue/database/annotation/entity_facade.rb +33 -30
- data/lib/catissue/database/annotation/id_generator.rb +1 -1
- data/lib/catissue/database/annotation/integration_service.rb +11 -4
- data/lib/catissue/database/annotation/reference_writer.rb +38 -38
- data/lib/catissue/database/controlled_value_finder.rb +13 -28
- data/lib/catissue/database/controlled_values.rb +73 -45
- data/lib/catissue/database.rb +637 -277
- data/lib/catissue/domain/abstract_domain_object.rb +5 -0
- data/lib/catissue/domain/abstract_position.rb +3 -5
- data/lib/catissue/domain/abstract_specimen.rb +79 -65
- data/lib/catissue/domain/abstract_specimen_collection_group.rb +3 -6
- data/lib/catissue/domain/address.rb +0 -2
- data/lib/catissue/domain/cancer_research_group.rb +0 -3
- data/lib/catissue/domain/capacity.rb +2 -4
- data/lib/catissue/domain/check_in_check_out_event_parameter.rb +0 -3
- data/lib/catissue/domain/collection_event_parameters.rb +2 -7
- data/lib/catissue/domain/collection_protocol.rb +11 -16
- data/lib/catissue/domain/collection_protocol_event.rb +19 -12
- data/lib/catissue/domain/collection_protocol_registration.rb +8 -12
- data/lib/catissue/domain/consent_tier_response.rb +0 -4
- data/lib/catissue/domain/consent_tier_status.rb +1 -4
- data/lib/catissue/domain/container.rb +10 -10
- data/lib/catissue/domain/container_position.rb +4 -7
- data/lib/catissue/domain/container_type.rb +4 -7
- data/lib/catissue/domain/department.rb +0 -3
- data/lib/catissue/domain/disposal_event_parameters.rb +5 -5
- data/lib/catissue/domain/embedded_event_parameters.rb +1 -4
- data/lib/catissue/domain/external_identifier.rb +0 -12
- data/lib/catissue/domain/frozen_event_parameters.rb +1 -4
- data/lib/catissue/domain/institution.rb +0 -3
- data/lib/catissue/domain/new_specimen_array_order_item.rb +0 -5
- data/lib/catissue/domain/order_details.rb +0 -2
- data/lib/catissue/domain/participant/clinical/chemotherapy.rb +1 -3
- data/lib/catissue/domain/participant/clinical/duration.rb +2 -4
- data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +2 -4
- data/lib/catissue/domain/participant.rb +22 -24
- data/lib/catissue/domain/participant_medical_identifier.rb +0 -4
- data/lib/catissue/domain/password.rb +0 -4
- data/lib/catissue/domain/race.rb +0 -3
- data/lib/catissue/domain/received_event_parameters.rb +3 -6
- data/lib/catissue/domain/site.rb +1 -4
- data/lib/catissue/domain/specimen/pathology/additional_finding.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/details.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/gleason_score.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/histologic_grade.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/histologic_type.rb +19 -0
- data/lib/catissue/domain/specimen/pathology/histologic_variant_type.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/invasion.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +5 -11
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +12 -12
- data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +5 -14
- data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +6 -21
- data/lib/catissue/domain/specimen/pathology/specimen_details.rb +4 -10
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +4 -10
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +6 -14
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +5 -11
- data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +5 -11
- data/lib/catissue/domain/specimen.rb +113 -76
- data/lib/catissue/domain/specimen_array.rb +0 -3
- data/lib/catissue/domain/specimen_array_content.rb +1 -4
- data/lib/catissue/domain/specimen_array_type.rb +1 -4
- data/lib/catissue/domain/specimen_characteristics.rb +0 -3
- data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +2 -4
- data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +2 -4
- data/lib/catissue/domain/specimen_collection_group.rb +43 -53
- data/lib/catissue/domain/specimen_event_parameters.rb +24 -32
- data/lib/catissue/domain/specimen_position.rb +8 -5
- data/lib/catissue/domain/specimen_protocol.rb +3 -6
- data/lib/catissue/domain/specimen_requirement.rb +22 -20
- data/lib/catissue/domain/storage_container.rb +9 -12
- data/lib/catissue/domain/storage_type.rb +6 -10
- data/lib/catissue/domain/transfer_event_parameters.rb +3 -6
- data/lib/catissue/domain/user.rb +22 -29
- data/lib/catissue/{util → helpers}/collectible.rb +23 -18
- data/lib/catissue/helpers/collectible_event_parameters.rb +68 -0
- data/lib/catissue/helpers/controlled_value.rb +35 -0
- data/lib/catissue/{domain → helpers}/hash_code.rb +0 -0
- data/lib/catissue/{util → helpers}/location.rb +6 -5
- data/lib/catissue/helpers/log.rb +4 -0
- data/lib/catissue/{util → helpers}/person.rb +1 -1
- data/lib/catissue/{util → helpers}/position.rb +10 -8
- data/lib/catissue/helpers/properties_loader.rb +143 -0
- data/lib/catissue/{util → helpers}/storable.rb +2 -1
- data/lib/catissue/{util → helpers}/storage_type_holder.rb +9 -3
- data/lib/catissue/{annotation/annotatable_class.rb → metadata.rb} +73 -95
- data/lib/catissue/migration/migratable.rb +93 -44
- data/lib/catissue/migration/migrator.rb +26 -42
- data/lib/catissue/migration/shims.rb +1 -1
- data/lib/catissue/migration/unique.rb +76 -0
- data/lib/catissue/resource.rb +16 -20
- data/lib/catissue/version.rb +1 -1
- data/lib/catissue/wustl/logger.rb +52 -32
- data/lib/catissue.rb +38 -20
- data/test/lib/catissue/database/controlled_values_test.rb +22 -27
- data/test/lib/catissue/database/database_test.rb +18 -0
- data/test/lib/catissue/domain/address_test.rb +9 -11
- data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +5 -16
- data/test/lib/catissue/domain/capacity_test.rb +2 -2
- data/test/lib/catissue/domain/collection_event_parameters_test.rb +16 -8
- data/test/lib/catissue/domain/collection_protocol_event_test.rb +1 -1
- data/test/lib/catissue/domain/collection_protocol_registration_test.rb +26 -16
- data/test/lib/catissue/domain/collection_protocol_test.rb +2 -2
- data/test/lib/catissue/domain/container_position_test.rb +7 -4
- data/test/lib/catissue/domain/department_test.rb +3 -3
- data/test/lib/catissue/domain/disposal_event_parameters_test.rb +1 -1
- data/test/lib/catissue/domain/external_identifier_test.rb +5 -1
- data/test/lib/catissue/domain/location_test.rb +4 -4
- data/test/lib/catissue/domain/participant_medical_identifier_test.rb +3 -3
- data/test/lib/catissue/domain/participant_test.rb +33 -20
- data/test/lib/catissue/domain/received_event_parameters_test.rb +19 -0
- data/test/lib/catissue/domain/site_test.rb +2 -2
- data/test/lib/catissue/domain/specimen_array_test.rb +3 -3
- data/test/lib/catissue/domain/specimen_array_type_test.rb +6 -6
- data/test/lib/catissue/domain/specimen_characteristics_test.rb +1 -1
- data/test/lib/catissue/domain/specimen_collection_group_test.rb +49 -13
- data/test/lib/catissue/domain/specimen_event_parameters_test.rb +4 -4
- data/test/lib/catissue/domain/specimen_position_test.rb +1 -1
- data/test/lib/catissue/domain/specimen_requirement_test.rb +2 -2
- data/test/lib/catissue/domain/specimen_test.rb +58 -24
- data/test/lib/catissue/domain/storage_container_test.rb +3 -16
- data/test/lib/catissue/domain/storage_type_test.rb +3 -3
- data/test/lib/catissue/domain/transfer_event_parameters_test.rb +17 -17
- data/test/lib/catissue/domain/user_test.rb +32 -34
- data/test/lib/catissue/helpers/properties_loader_test.rb +19 -0
- data/test/lib/catissue/migration/{test_case.rb → helpers/test_case.rb} +30 -20
- data/test/lib/examples/galena/tissue/domain/examples_test.rb +28 -38
- data/test/lib/examples/galena/tissue/helpers/test_case.rb +24 -0
- metadata +175 -99
- data/bin/crtextract +0 -47
- data/examples/galena/conf/extract/simple_fields.yaml +0 -4
- data/examples/galena/conf/migration/annotation_defaults.yaml +0 -2
- data/examples/galena/conf/migration/filter_defaults.yaml +0 -1
- data/examples/galena/conf/migration/filter_values.yaml +0 -13
- data/examples/galena/conf/migration/participant_fields.yaml +0 -4
- data/examples/galena/conf/migration/registration_fields.yaml +0 -5
- data/examples/galena/data/participant.csv +0 -1
- data/examples/galena/lib/galena/tissue/migration/filter_shims.rb +0 -41
- data/examples/galena/lib/galena/tissue/seed/defaults.rb +0 -127
- data/examples/psbin/README.md +0 -45
- data/examples/psbin/conf/adjuvant_hormone_defaults.yaml +0 -2
- data/examples/psbin/conf/adjuvant_radiation_defaults.yaml +0 -3
- data/examples/psbin/conf/biopsy_defaults.yaml +0 -3
- data/examples/psbin/conf/biopsy_fields.yaml +0 -9
- data/examples/psbin/conf/neoadjuvant_hormone_defaults.yaml +0 -2
- data/examples/psbin/conf/neoadjuvant_radiation_defaults.yaml +0 -3
- data/examples/psbin/conf/patient_defaults.yaml +0 -3
- data/examples/psbin/conf/patient_fields.yaml +0 -5
- data/examples/psbin/conf/surgery_defaults.yaml +0 -4
- data/examples/psbin/conf/surgery_fields.yaml +0 -15
- data/examples/psbin/conf/t_stage_defaults.yaml +0 -1
- data/examples/psbin/conf/t_stage_fields.yaml +0 -4
- data/examples/psbin/conf/therapy_fields.yaml +0 -5
- data/examples/psbin/data/adjuvant_hormone.csv +0 -1
- data/examples/psbin/data/adjuvant_radiation.csv +0 -1
- data/examples/psbin/data/biopsy.csv +0 -1
- data/examples/psbin/data/neoadjuvant_hormone.csv +0 -1
- data/examples/psbin/data/neoadjuvant_radiation.csv +0 -1
- data/examples/psbin/data/patient.csv +0 -1
- data/examples/psbin/data/surgery.csv +0 -1
- data/examples/psbin/data/t_stage.csv +0 -1
- data/examples/psbin/lib/psbin/biopsy_shims.rb +0 -15
- data/examples/psbin/lib/psbin/surgery_shims.rb +0 -15
- data/lib/catissue/annotation/annotation_class.rb +0 -406
- data/lib/catissue/annotation/annotation_module.rb +0 -106
- data/lib/catissue/domain.rb +0 -26
- data/lib/catissue/extract/command.rb +0 -31
- data/lib/catissue/extract/delta.rb +0 -58
- data/lib/catissue/extract/extractor.rb +0 -99
- data/lib/catissue/migration/uniquify.rb +0 -2
- data/lib/catissue/util/collectible_event_parameters.rb +0 -71
- data/lib/catissue/util/controlled_value.rb +0 -29
- data/lib/catissue/util/uniquify.rb +0 -86
- data/test/fixtures/catissue/domain/conf/catissue_override.yaml +0 -9
- data/test/fixtures/catissue/extract/conf/scg_extract.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/scg_fields.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/spc_extract.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/spc_fields.yaml +0 -4
- data/test/fixtures/lib/catissue/defaults_test_fixture.rb +0 -206
- data/test/fixtures/lib/examples/galena/migration/alt_key_shims.rb +0 -7
- data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +0 -24
- data/test/lib/catissue/extract/delta_test.rb +0 -25
- data/test/lib/catissue/extract/extractor_test.rb +0 -43
- data/test/lib/catissue/import/importable_module_test.rb +0 -14
- data/test/lib/catissue/test_case.rb +0 -247
- data/test/lib/examples/galena/tissue/migration/annotation_test.rb +0 -29
- data/test/lib/examples/galena/tissue/migration/filter_test.rb +0 -29
- data/test/lib/examples/galena/tissue/migration/frozen_test.rb +0 -36
- data/test/lib/examples/galena/tissue/migration/general_test.rb +0 -56
- data/test/lib/examples/galena/tissue/migration/participant_test.rb +0 -61
- data/test/lib/examples/galena/tissue/migration/registration_test.rb +0 -17
- data/test/lib/examples/galena/tissue/migration/seedify.rb +0 -119
- data/test/lib/examples/galena/tissue/migration/simple_test.rb +0 -30
- data/test/lib/examples/galena/tissue/migration/test_case.rb +0 -72
- data/test/lib/examples/psbin/migration_test.rb +0 -153
@@ -45,7 +45,7 @@ module CaTissue
|
|
45
45
|
|
46
46
|
logger.debug { "Work around caTissue DE EntityManagerUtil bug by fetching the maximum #{table} identifier directly from the database..." }
|
47
47
|
sql = TABLE_MAX_ID_SQL_TMPL % table
|
48
|
-
result = @executor.
|
48
|
+
result = @executor.query(sql).first
|
49
49
|
max = result ? result[0].to_i : 0
|
50
50
|
next_id = max + 1
|
51
51
|
# End of work-around
|
@@ -35,6 +35,17 @@ module CaTissue
|
|
35
35
|
# Creates an entity map record with content (annotation entity id, annotation id, form context id).
|
36
36
|
# This record associates the static hook record to the annotation record qualified by the context.
|
37
37
|
#
|
38
|
+
# @quirk caTissue 1.1.2 The caTissue 1.1.2 ClientDemo*.java examples do not set the entity map record
|
39
|
+
# createdDate. This results in a caTissue 1.1.2 -> 1.2 migration error.
|
40
|
+
# The entity map record in question is +edu.common.dynamicextensions.domain.integration.EntityMapRecord+.
|
41
|
+
# However, that class is not referenced in the examples. Rather, the
|
42
|
+
# referenced class is +deintegration.EntityMapRecord+, which does not have a createdDate property.
|
43
|
+
# Therefore, there is no caRuby work-around for this caTissue bug. The only recourse is to set
|
44
|
+
# the created_date SQL column directly to today() prior to performing a 1.1.2-to-1.2 migration.
|
45
|
+
# 1.2 uses a different mechanism, so this bug is specific to 1.1.2, although, of course, this does
|
46
|
+
# not preclude the possibility of other obscure 1.2-to-2.0 caTissue migration bugs in a similar
|
47
|
+
# vein.
|
48
|
+
#
|
38
49
|
# @param (see #associate)
|
39
50
|
# @return [EntityMapRecord] the new entity map record
|
40
51
|
def create_entity_map_record(hook, annotation)
|
@@ -42,14 +53,12 @@ module CaTissue
|
|
42
53
|
emr = EntityMapRecord.new
|
43
54
|
emr.static_entity_record_id = hook.identifier
|
44
55
|
emr.dynamic_entity_record_id = annotation.identifier
|
45
|
-
|
46
56
|
# the form context
|
47
57
|
ctxt = form_context(hook, annotation)
|
48
58
|
if ctxt then
|
49
59
|
emr.form_context = ctxt
|
50
60
|
emr.form_context_id = ctxt.id
|
51
61
|
end
|
52
|
-
|
53
62
|
emr
|
54
63
|
end
|
55
64
|
|
@@ -57,7 +66,6 @@ module CaTissue
|
|
57
66
|
# @return [FormContent] an undocumented bit of caTissue presentation flotsam polluting the data layer
|
58
67
|
def form_context(hook, annotation)
|
59
68
|
map = entity_map(hook, annotation)
|
60
|
-
|
61
69
|
# the fetched form context
|
62
70
|
ctxts = map.form_context_collection
|
63
71
|
if ctxts.empty? then
|
@@ -69,7 +77,6 @@ module CaTissue
|
|
69
77
|
ctxt = ctxts.first
|
70
78
|
logger.debug { "#{hook} has form context id #{ctxt.id}." }
|
71
79
|
end
|
72
|
-
|
73
80
|
ctxt
|
74
81
|
end
|
75
82
|
|
@@ -5,20 +5,20 @@ 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 [
|
8
|
+
# @param [Jinx::Property] prop the annotation attribute metadata of the attribute to save
|
9
9
|
# @param [Integer, nil] assn_eid the referenced annotation entity id
|
10
|
-
def initialize(eid,
|
11
|
-
logger.debug { "Mapping annotation #{
|
10
|
+
def initialize(eid, prop, assn_eid=nil)
|
11
|
+
logger.debug { "Mapping annotation #{prop.declarer.qp}.#{prop} role attributes to database columns..." }
|
12
12
|
efcd = EntityFacade.instance
|
13
13
|
# the referenced annotation entity id
|
14
|
-
assn_eid ||= associated_entity_id(eid,
|
14
|
+
assn_eid ||= associated_entity_id(eid, prop)
|
15
15
|
# the referenced entity database table
|
16
16
|
@table = efcd.annotation_table_for_entity_id(assn_eid)
|
17
17
|
# map the attribute => column
|
18
|
-
attr_col_hash = map_attributes(
|
19
|
-
logger.debug { "Annotation #{
|
18
|
+
attr_col_hash = map_attributes(prop.type, assn_eid)
|
19
|
+
logger.debug { "Annotation #{prop.declarer.qp} #{prop} reference type #{prop.type.qp} maps to #{@table} as #{attr_col_hash.qp}" }
|
20
20
|
# the mapped attributes and columns
|
21
|
-
@
|
21
|
+
@attributes, cols = attr_col_hash.to_a.transpose
|
22
22
|
# the SQL parameters clause
|
23
23
|
params = Array.new(cols.size, '?').join(', ')
|
24
24
|
# the create SQL
|
@@ -26,7 +26,7 @@ module CaTissue
|
|
26
26
|
# the update SQL
|
27
27
|
@upd_sql = UPDATE_SQL % [@table, cols.map { |col| "#{col} = ?" }.join(', ')]
|
28
28
|
# the superclass writer for annotations with superclass DE forms
|
29
|
-
@parent = obtain_parent_writer(eid,
|
29
|
+
@parent = obtain_parent_writer(eid, prop)
|
30
30
|
end
|
31
31
|
|
32
32
|
# @param [Annotation] annotation the referenced annotation value
|
@@ -37,11 +37,10 @@ module CaTissue
|
|
37
37
|
annotation.identifier ||= next_identifier
|
38
38
|
# the values to bind to the SQL parameters
|
39
39
|
values = database_parameters(annotation)
|
40
|
-
logger.debug { "Saving #{annotation} to #{@table}..." }
|
40
|
+
logger.debug { "Saving annotation #{annotation} to #{@table}..." }
|
41
41
|
# dispatch the SQL update or create statement
|
42
|
-
|
43
|
-
|
44
|
-
end
|
42
|
+
Database.instance.executor.transact(sql, *values)
|
43
|
+
# Save the superclass attributes.
|
45
44
|
if @parent then
|
46
45
|
logger.debug { "Saving #{annotation} parent entity attributes..." }
|
47
46
|
@parent.save(annotation)
|
@@ -60,53 +59,54 @@ module CaTissue
|
|
60
59
|
# @param (see #initialize)
|
61
60
|
# @return [Integer] the entity id for the given attribute role
|
62
61
|
# @raise [AnnotationError] if the associated entity was not found
|
63
|
-
def associated_entity_id(eid,
|
64
|
-
EntityFacade.instance.associated_entity_id(eid,
|
65
|
-
raise AnnotationError.new("Associated entity not found for entity #{eid} attribute #{
|
62
|
+
def associated_entity_id(eid, prop)
|
63
|
+
EntityFacade.instance.associated_entity_id(eid, prop.property_descriptor.name) or
|
64
|
+
raise AnnotationError.new("Associated entity not found for entity #{eid} attribute #{prop}")
|
66
65
|
end
|
67
66
|
|
68
67
|
# @param (see #initialize)
|
69
68
|
# @return [Integer, nil] the superclass associated entity id for the given attribute role, or nil if none
|
70
|
-
def obtain_parent_writer(eid,
|
69
|
+
def obtain_parent_writer(eid, prop)
|
71
70
|
# the superclass entity id for annotations with superclass DE forms
|
72
71
|
peid = EntityFacade.instance.parent_entity_id(eid) || return
|
73
72
|
# the associated entity id
|
74
|
-
aeid = EntityFacade.instance.associated_entity_id(peid,
|
75
|
-
ReferenceWriter.new(peid,
|
73
|
+
aeid = EntityFacade.instance.associated_entity_id(peid, prop.property_descriptor.name)
|
74
|
+
ReferenceWriter.new(peid, prop, aeid) if aeid
|
76
75
|
end
|
77
76
|
|
78
77
|
# @param annotation (see #save)
|
79
78
|
# @return [Array] the save SQL call parameters
|
80
79
|
def database_parameters(annotation)
|
81
|
-
@
|
82
|
-
value = annotation.send(
|
80
|
+
@attributes.map do |pa|
|
81
|
+
value = annotation.send(pa)
|
83
82
|
Annotation === value ? value.identifier : value
|
84
83
|
end
|
85
84
|
end
|
86
85
|
|
87
86
|
def map_attributes(klass, eid)
|
88
|
-
# the non-domain
|
89
|
-
|
90
|
-
nondomain_attribute_column(klass,
|
87
|
+
# Fill in the attribute => column hash for non-domain attributes.
|
88
|
+
ach = klass.nondomain_attributes.to_compact_hash do |pas|
|
89
|
+
nondomain_attribute_column(klass, pas, eid)
|
91
90
|
end
|
92
|
-
# the owner attribute
|
91
|
+
# Add the owner attribute => column entries.
|
93
92
|
klass.owner_attributes.each do |oattr|
|
94
|
-
|
93
|
+
ach[oattr] = owner_attribute_column(klass, oattr, eid)
|
95
94
|
end
|
96
|
-
|
95
|
+
ach
|
97
96
|
end
|
98
97
|
|
99
98
|
def nondomain_attribute_column(klass, attribute, eid)
|
100
|
-
if attribute == :identifier
|
101
|
-
|
99
|
+
return IDENTIFIER_COL if attribute == :identifier
|
100
|
+
prop = klass.property(attribute)
|
102
101
|
# skip an attribute declared by the superclass
|
103
|
-
return unless
|
104
|
-
|
105
|
-
prop = attr_md.property_descriptor.name
|
102
|
+
return unless prop.declarer == klass
|
103
|
+
prop = prop.property_descriptor.name
|
106
104
|
logger.debug { "Finding #{klass.qp} #{attribute} column for entity id #{eid} and property #{prop}..." }
|
107
|
-
result =
|
105
|
+
result = Database.instance.executor.query(NONDOMAIN_COLUMN_SQL, prop, eid).first
|
108
106
|
col = result[0] if result
|
109
|
-
if col.nil? then
|
107
|
+
if col.nil? then
|
108
|
+
raise AnnotationError.new("Column not found for #{klass.qp} #{attribute}")
|
109
|
+
end
|
110
110
|
col
|
111
111
|
end
|
112
112
|
|
@@ -116,22 +116,22 @@ module CaTissue
|
|
116
116
|
# @quirk caTissue The role can be a mutation of the demodulized class name as follows:
|
117
117
|
# * decapitalization, e.g. role +specimenCollectionGroup+ for class +SpecimenCollectionGroup+
|
118
118
|
#
|
119
|
-
# @param [
|
119
|
+
# @param [Metadata] klass the annotation class
|
120
120
|
# @param [Symbol] attribute the owner attribute
|
121
121
|
# @param [Integer] eid the annotation entity id
|
122
122
|
# @return [String] the owner reference SQL column name
|
123
123
|
def owner_attribute_column(klass, attribute, eid)
|
124
124
|
logger.debug { "Finding #{klass.qp} #{attribute} column in the context of entity id #{eid}..." }
|
125
125
|
# The referenced class name (confusingly called a source role in the caTissue schema).
|
126
|
-
tgt_nm = klass.
|
127
|
-
result =
|
126
|
+
tgt_nm = klass.property(attribute).type.name.demodulize
|
127
|
+
result = Database.instance.executor.query(OWNER_COLUMN_SQL, eid, tgt_nm).first
|
128
128
|
col = result[0] if result
|
129
129
|
if col.nil? then
|
130
|
-
result =
|
130
|
+
result = Database.instance.executor.query(OWNER_COLUMN_SQL, eid, tgt_nm.decapitalize).first
|
131
131
|
col = result[0] if result
|
132
132
|
end
|
133
133
|
if col.nil? then
|
134
|
-
result =
|
134
|
+
result = Database.instance.executor.query(ALT_1_1_OWNER_COLUMN_SQL, eid).first
|
135
135
|
col = result[0] if result
|
136
136
|
end
|
137
137
|
if col.nil? then raise AnnotationError.new("Column not found for #{klass.qp} owner attribute #{attribute}") end
|
@@ -1,43 +1,28 @@
|
|
1
|
-
require 'caruby/util/log'
|
2
1
|
require 'catissue/database/controlled_values'
|
3
2
|
|
4
3
|
module CaTissue
|
4
|
+
class ControlledValueError < RuntimeError; end
|
5
|
+
|
5
6
|
# Finds attribute controlled values.
|
6
7
|
class ControlledValueFinder
|
7
8
|
# Creates a new ControlledValueFinder for the given attribute.
|
8
9
|
# The optional YAML properties file name maps input values to controlled values.
|
9
|
-
|
10
|
+
#
|
11
|
+
# @param [Symbol] attribute the CV attribute
|
12
|
+
def initialize(attribute)
|
10
13
|
@attribute = attribute
|
11
|
-
@remap_hash = load_controlled_value_hash(file)
|
12
14
|
end
|
13
15
|
|
14
|
-
# Returns the CV value for the given source value.
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
16
|
+
# Returns the CV value for the given source value. A case-insensitive lookup
|
17
|
+
# is performed on the CV.
|
18
|
+
#
|
19
|
+
# @param [String, nil] value the CV string value to find
|
20
|
+
# @raise [ControlledValueError] if the CV was not found
|
21
|
+
# @see ControlledValues#find
|
18
22
|
def controlled_value(value)
|
19
23
|
return if value.blank?
|
20
|
-
|
21
|
-
|
22
|
-
cv = supported_controlled_value(value)
|
23
|
-
logger.warn("#{@attribute} value '#{value}' ignored since it is not a recognized controlled value.") if cv.nil?
|
24
|
-
cv.value if cv
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def remapped_controlled_value(value)
|
30
|
-
@remap_hash[value]
|
31
|
-
end
|
32
|
-
|
33
|
-
def supported_controlled_value(value)
|
34
|
-
ControlledValues.instance.find(@attribute, value)
|
35
|
-
end
|
36
|
-
|
37
|
-
def load_controlled_value_hash(file)
|
38
|
-
return {} unless file and File.exists?(file)
|
39
|
-
logger.debug { "Loading controlled value map for #{@attribute} from #{file}..." }
|
40
|
-
YAML::load_file(file)
|
24
|
+
ControlledValues.instance.find(@attribute, value) or
|
25
|
+
raise ControlledValueError.new("#{@attribute} value '#{value}' is not a recognized controlled value.")
|
41
26
|
end
|
42
27
|
end
|
43
28
|
end
|
@@ -1,25 +1,26 @@
|
|
1
1
|
require 'singleton'
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
2
|
+
require 'jinx/helpers/collections'
|
3
|
+
require 'jinx/helpers/lazy_hash'
|
4
|
+
require 'jinx/helpers/case_insensitive_hash'
|
5
|
+
require 'jinx/helpers/options'
|
6
|
+
require 'jinx/helpers/visitor'
|
7
7
|
require 'catissue/database'
|
8
|
-
require 'catissue/
|
9
|
-
require 'caruby/domain/properties'
|
8
|
+
require 'catissue/helpers/controlled_value'
|
10
9
|
|
11
10
|
module CaTissue
|
12
11
|
# This ControlledValues class loads caTissue permissible values from the database.
|
13
|
-
# Use of this class requires the +dbi+ gem. See
|
12
|
+
# Use of this class requires the +dbi+ gem. See +CaRuby::SQLExecutor.initialize+
|
14
13
|
# for a description of the database access properties.
|
15
14
|
class ControlledValues
|
16
15
|
include Singleton
|
17
16
|
|
18
17
|
def initialize
|
19
|
-
@executor =
|
20
|
-
|
21
|
-
@
|
22
|
-
|
18
|
+
@executor = Database.instance.executor
|
19
|
+
# The pid => { value => CV } that associates each loaded parent CV to its children.
|
20
|
+
@pid_loaded_hash = Jinx::LazyHash.new { |pid| load_pid_cvs(pid) }
|
21
|
+
# The pid => { value => CV } that associates each fetched parent CV to its children.
|
22
|
+
@pid_value_cv_hash = Jinx::LazyHash.new do |pid|
|
23
|
+
Jinx::CaseInsensitiveHash.new { |hash, value| hash[value] = load_cv(pid, value) unless value.nil? }
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -27,37 +28,48 @@ module CaTissue
|
|
27
28
|
# The CVs are loaded from the database if necessary.
|
28
29
|
#
|
29
30
|
# The following public id aliases are supported:
|
30
|
-
# *
|
31
|
-
# *
|
31
|
+
# * +:tissue_site+
|
32
|
+
# * +:clinical_diagnosis+
|
32
33
|
#
|
33
|
-
|
34
|
-
# @return [<ControlledValue>] instances for the given public_id_or_alias
|
34
|
+
# @param [String, Symbol] public_id_or_alias the caTissue public id or an alias defined above
|
35
|
+
# @return [<CaRuby::ControlledValue>] instances for the given public_id_or_alias
|
35
36
|
def for_public_id(public_id_or_alias)
|
36
37
|
pid = ControlledValue.standard_public_id(public_id_or_alias)
|
37
38
|
@pid_loaded_hash[pid].values
|
38
39
|
end
|
39
40
|
|
40
|
-
# Returns the
|
41
|
-
#
|
41
|
+
# Returns the CV with the given public_id_or_alias and value. Loads the CV if necessary
|
42
|
+
# from the database. The loaded CV does not have a parent or children.
|
42
43
|
#
|
43
|
-
|
44
|
-
# @
|
45
|
-
|
44
|
+
# @param [String, Symbol] public_id_or_alias the caTissue public id or alias
|
45
|
+
# @param [String] value the CV value
|
46
|
+
# @param [Boolean] recursive whether to load the CV children as well.
|
47
|
+
# @return [CaRuby::ControlledValue, nil] the matching CV, or nil if no match
|
48
|
+
def find(public_id_or_alias, value, recursive=false)
|
46
49
|
pid = ControlledValue.standard_public_id(public_id_or_alias)
|
47
|
-
@pid_value_cv_hash[pid]
|
50
|
+
value_cv_hash = @pid_value_cv_hash[pid]
|
51
|
+
cv = value_cv_hash[value]
|
52
|
+
if recursive then
|
53
|
+
fetch_descendants(cv, value_cv_hash)
|
54
|
+
end
|
55
|
+
cv
|
48
56
|
end
|
49
57
|
|
50
58
|
# Creates a new controlled value record in the database from the given ControlledValue cv.
|
51
59
|
# The default identifier is the next identifier in the permissible values table.
|
52
60
|
#
|
53
61
|
# @param [ControlledValue] cv the controlled value to create
|
54
|
-
# @return
|
62
|
+
# @return [ControlledValue] the created CV
|
55
63
|
def create(cv)
|
64
|
+
if cv.public_id.nil? then
|
65
|
+
raise ArgumentError.new("Controlled value create is missing a public id")
|
66
|
+
end
|
67
|
+
if cv.value.nil? then
|
68
|
+
raise ArgumentError.new("Controlled value create is missing a value")
|
69
|
+
end
|
56
70
|
cv.identifier ||= next_id
|
57
|
-
raise ArgumentError.new("Controlled value create is missing a public id") if cv.public_id.nil?
|
58
|
-
raise ArgumentError.new("Controlled value create is missing a value") if cv.value.nil?
|
59
71
|
logger.debug { "Creating controlled value #{cv} in the database..." }
|
60
|
-
@executor.
|
72
|
+
@executor.transact(INSERT_STMT, cv.identifier, cv.parent_identifier, cv.public_id, cv.value)
|
61
73
|
logger.debug { "Controlled value #{cv.public_id} #{cv.value} created with identifier #{cv.identifier}" }
|
62
74
|
@pid_value_cv_hash[cv.public_id][cv.value] = cv
|
63
75
|
end
|
@@ -67,12 +79,16 @@ module CaTissue
|
|
67
79
|
#
|
68
80
|
# @param [ControlledValue] cv the controlled value to delete
|
69
81
|
def delete(cv)
|
70
|
-
@executor.
|
82
|
+
@executor.transact do |dbh|
|
83
|
+
sth = dbh.prepare(DELETE_STMT)
|
84
|
+
delete_recursive(cv, sth)
|
85
|
+
sth.finish
|
86
|
+
end
|
71
87
|
end
|
72
88
|
|
73
89
|
private
|
74
90
|
|
75
|
-
|
91
|
+
PID_ROOTS_STMT = "select identifier, value from catissue_permissible_value where public_id = ? and (parent_identifier is null or parent_identifier = 0)"
|
76
92
|
|
77
93
|
CHILDREN_STMT = "select identifier, value from catissue_permissible_value where parent_identifier = ?"
|
78
94
|
|
@@ -90,7 +106,7 @@ module CaTissue
|
|
90
106
|
|
91
107
|
def load_cv(public_id, value)
|
92
108
|
logger.debug { "Loading controlled value #{public_id} #{value} from the database..." }
|
93
|
-
row = @executor.
|
109
|
+
row = @executor.query(SEARCH_STMT, value).first
|
94
110
|
logger.debug { "Controlled value #{public_id} #{value} not found." } and return if row.nil?
|
95
111
|
identifier = row[0]
|
96
112
|
logger.debug { "Controlled value #{public_id} #{value} loaded with identifier #{identifier}." }
|
@@ -98,7 +114,7 @@ module CaTissue
|
|
98
114
|
end
|
99
115
|
|
100
116
|
def next_id
|
101
|
-
@executor.
|
117
|
+
@executor.query(MAX_ID_STMT).first[0].to_i + 1
|
102
118
|
end
|
103
119
|
|
104
120
|
def delete_recursive(cv, sth)
|
@@ -111,29 +127,41 @@ module CaTissue
|
|
111
127
|
logger.debug { "Controlled value #{cv} deleted." }
|
112
128
|
end
|
113
129
|
|
130
|
+
# @param [String] pid the public id to find
|
131
|
+
# @param [String => CaRuby::ControlledValue] the pid children value => CV hash
|
114
132
|
def fetch_cvs_with_public_id(pid, value_cv_hash)
|
115
|
-
id_cv_hash = {}
|
116
133
|
logger.debug { "Loading #{pid} controlled values from the database..." }
|
117
|
-
cvs =
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
# load the root CVs children
|
124
|
-
cvs.each { |cv| fetch_descendants(cv, dbh, value_cv_hash) }
|
134
|
+
cvs = @executor.query(PID_ROOTS_STMT, pid).map do |row|
|
135
|
+
identifier, value = row
|
136
|
+
cv = make_controlled_value(:identifier => identifier, :public_id => pid, :value => value)
|
137
|
+
value_cv_hash[value] ||= cv
|
138
|
+
cv
|
125
139
|
end
|
140
|
+
cvs.each { |cv| fetch_descendants(cv, value_cv_hash) }
|
141
|
+
logger.debug { "Loaded #{value_cv_hash.size} #{pid} controlled values from the database." }
|
126
142
|
value_cv_hash
|
127
143
|
end
|
128
144
|
|
129
|
-
def fetch_descendants(cv,
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
145
|
+
def fetch_descendants(cv, value_cv_hash)
|
146
|
+
logger.debug { "Fetching #{cv} descendants..." }
|
147
|
+
# load the root CVs children
|
148
|
+
@executor.execute do |dbh|
|
149
|
+
sth = dbh.prepare(CHILDREN_STMT)
|
150
|
+
fetch_descendants_recursive(cv, value_cv_hash, sth)
|
151
|
+
sth.finish
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def fetch_descendants_recursive(cv, value_cv_hash, sth)
|
156
|
+
pid = cv.public_id
|
157
|
+
# Collect the child CVs.
|
158
|
+
children = sth.execute(cv.identifier).map do |row|
|
159
|
+
identifier, value = row
|
160
|
+
child = make_controlled_value(:identifier => identifier, :public_id => pid, :parent => cv, :value => value)
|
161
|
+
value_cv_hash[value] = child
|
134
162
|
end
|
135
163
|
# recurse to chidren
|
136
|
-
children.each { |cv|
|
164
|
+
children.each { |cv| fetch_descendants_recursive(cv, value_cv_hash, sth) }
|
137
165
|
end
|
138
166
|
|
139
167
|
# Returns a new ControlledValue with attributes set by the given attribute => value hash.
|