caruby-tissue 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/LEGAL +5 -0
- data/LICENSE +22 -0
- data/README.md +44 -0
- data/bin/crtdump +31 -0
- data/bin/crtexample +18 -0
- data/bin/crtextract +47 -0
- data/bin/crtmigrate +17 -0
- data/bin/crtsmoke +27 -0
- data/examples/galena/README.md +53 -0
- data/examples/galena/bin/migrate.rb +42 -0
- data/examples/galena/bin/seed.rb +43 -0
- data/examples/galena/conf/extract/simple_fields.yaml +4 -0
- data/examples/galena/conf/migration/filter_fields.yaml +7 -0
- data/examples/galena/conf/migration/filter_migration.yaml +9 -0
- data/examples/galena/conf/migration/frozen_fields.yaml +11 -0
- data/examples/galena/conf/migration/frozen_migration.yaml +9 -0
- data/examples/galena/conf/migration/general_fields.yaml +42 -0
- data/examples/galena/conf/migration/general_migration.yaml +9 -0
- data/examples/galena/conf/migration/simple_fields.yaml +30 -0
- data/examples/galena/conf/migration/simple_migration.yaml +7 -0
- data/examples/galena/conf/migration/small_fields.yaml +24 -0
- data/examples/galena/conf/migration/small_migration.yaml +9 -0
- data/examples/galena/data/filter.csv +1 -0
- data/examples/galena/data/frozen.csv +1 -0
- data/examples/galena/data/general.csv +1 -0
- data/examples/galena/data/minimal.csv +1 -0
- data/examples/galena/data/simple.csv +1 -0
- data/examples/galena/data/small.csv +1 -0
- data/examples/galena/doc/CaTissue.html +93 -0
- data/examples/galena/doc/CaTissue/CollectionProtocolRegistration.html +181 -0
- data/examples/galena/doc/CaTissue/Participant.html +241 -0
- data/examples/galena/doc/CaTissue/SpecimenCollectionGroup.html +190 -0
- data/examples/galena/doc/CaTissue/StorageContainer.html +179 -0
- data/examples/galena/doc/CaTissue/TissueSpecimen.html +320 -0
- data/examples/galena/doc/Galena.html +290 -0
- data/examples/galena/doc/Galena/Seed.html +203 -0
- data/examples/galena/doc/Galena/Seed/Defaults.html +646 -0
- data/examples/galena/doc/_index.html +188 -0
- data/examples/galena/doc/class_list.html +36 -0
- data/examples/galena/doc/css/common.css +1 -0
- data/examples/galena/doc/css/full_list.css +53 -0
- data/examples/galena/doc/css/style.css +307 -0
- data/examples/galena/doc/file.README.html +108 -0
- data/examples/galena/doc/file_list.html +38 -0
- data/examples/galena/doc/frames.html +13 -0
- data/examples/galena/doc/index.html +108 -0
- data/examples/galena/doc/js/app.js +202 -0
- data/examples/galena/doc/js/full_list.js +149 -0
- data/examples/galena/doc/js/jquery.js +154 -0
- data/examples/galena/doc/method_list.html +179 -0
- data/examples/galena/doc/top-level-namespace.html +112 -0
- data/examples/galena/lib/README.html +33 -0
- data/examples/galena/lib/galena.rb +8 -0
- data/examples/galena/lib/galena/cli/seed.rb +43 -0
- data/examples/galena/lib/galena/migration/filter_shims.rb +43 -0
- data/examples/galena/lib/galena/migration/frozen_shims.rb +54 -0
- data/examples/galena/lib/galena/seed/defaults.rb +97 -0
- data/lib/catissue.rb +26 -0
- data/lib/catissue/cli/command.rb +51 -0
- data/lib/catissue/cli/example.rb +31 -0
- data/lib/catissue/cli/migrate.rb +60 -0
- data/lib/catissue/cli/smoke.rb +45 -0
- data/lib/catissue/database.rb +451 -0
- data/lib/catissue/database/annotation/annotatable_service.rb +25 -0
- data/lib/catissue/database/annotation/annotation_service.rb +79 -0
- data/lib/catissue/database/annotation/annotator.rb +84 -0
- data/lib/catissue/database/annotation/entity_manager.rb +10 -0
- data/lib/catissue/database/annotation/integration_service.rb +87 -0
- data/lib/catissue/database/controlled_value_finder.rb +43 -0
- data/lib/catissue/database/controlled_values.rb +162 -0
- data/lib/catissue/domain/abstract_domain_object.rb +8 -0
- data/lib/catissue/domain/abstract_position.rb +22 -0
- data/lib/catissue/domain/abstract_specimen.rb +288 -0
- data/lib/catissue/domain/abstract_specimen_collection_group.rb +25 -0
- data/lib/catissue/domain/address.rb +13 -0
- data/lib/catissue/domain/cancer_research_group.rb +11 -0
- data/lib/catissue/domain/capacity.rb +34 -0
- data/lib/catissue/domain/check_in_check_out_event_parameter.rb +19 -0
- data/lib/catissue/domain/collection_event_parameters.rb +13 -0
- data/lib/catissue/domain/collection_protocol.rb +177 -0
- data/lib/catissue/domain/collection_protocol_event.rb +108 -0
- data/lib/catissue/domain/collection_protocol_registration.rb +108 -0
- data/lib/catissue/domain/consent_tier_response.rb +13 -0
- data/lib/catissue/domain/consent_tier_status.rb +29 -0
- data/lib/catissue/domain/container.rb +234 -0
- data/lib/catissue/domain/container_position.rb +21 -0
- data/lib/catissue/domain/container_type.rb +131 -0
- data/lib/catissue/domain/department.rb +13 -0
- data/lib/catissue/domain/disposal_event_parameters.rb +13 -0
- data/lib/catissue/domain/embedded_event_parameters.rb +10 -0
- data/lib/catissue/domain/external_identifier.rb +22 -0
- data/lib/catissue/domain/frozen_event_parameters.rb +10 -0
- data/lib/catissue/domain/institution.rb +13 -0
- data/lib/catissue/domain/new_specimen_array_order_item.rb +35 -0
- data/lib/catissue/domain/order_details.rb +25 -0
- data/lib/catissue/domain/participant.rb +138 -0
- data/lib/catissue/domain/participant_medical_identifier.rb +38 -0
- data/lib/catissue/domain/password.rb +11 -0
- data/lib/catissue/domain/race.rb +11 -0
- data/lib/catissue/domain/received_event_parameters.rb +25 -0
- data/lib/catissue/domain/scg_event_parameters.rb +11 -0
- data/lib/catissue/domain/site.rb +30 -0
- data/lib/catissue/domain/specimen.rb +456 -0
- data/lib/catissue/domain/specimen_array.rb +47 -0
- data/lib/catissue/domain/specimen_array_content.rb +19 -0
- data/lib/catissue/domain/specimen_array_type.rb +20 -0
- data/lib/catissue/domain/specimen_characteristics.rb +20 -0
- data/lib/catissue/domain/specimen_collection_group.rb +412 -0
- data/lib/catissue/domain/specimen_event_parameters.rb +111 -0
- data/lib/catissue/domain/specimen_position.rb +38 -0
- data/lib/catissue/domain/specimen_protocol.rb +34 -0
- data/lib/catissue/domain/specimen_requirement.rb +143 -0
- data/lib/catissue/domain/storage_container.rb +204 -0
- data/lib/catissue/domain/storage_type.rb +82 -0
- data/lib/catissue/domain/transfer_event_parameters.rb +53 -0
- data/lib/catissue/domain/user.rb +100 -0
- data/lib/catissue/extract/command.rb +31 -0
- data/lib/catissue/extract/delta.rb +62 -0
- data/lib/catissue/extract/extractor.rb +99 -0
- data/lib/catissue/migration/migrator.rb +101 -0
- data/lib/catissue/migration/shims.rb +108 -0
- data/lib/catissue/migration/uniquify.rb +111 -0
- data/lib/catissue/resource.rb +84 -0
- data/lib/catissue/util/controlled_value.rb +29 -0
- data/lib/catissue/util/location.rb +116 -0
- data/lib/catissue/util/log.rb +30 -0
- data/lib/catissue/util/person.rb +31 -0
- data/lib/catissue/util/position.rb +54 -0
- data/lib/catissue/util/storable.rb +34 -0
- data/lib/catissue/util/storage_type_holder.rb +30 -0
- data/lib/catissue/version.rb +7 -0
- metadata +212 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module CaTissue
|
2
|
+
# import the Java class
|
3
|
+
java_import('edu.wustl.catissuecore.domain.ContainerPosition')
|
4
|
+
|
5
|
+
class ContainerPosition
|
6
|
+
include Resource
|
7
|
+
|
8
|
+
add_mandatory_attributes(:parent_container)
|
9
|
+
|
10
|
+
add_attribute_aliases(:parent => :parent_container, :holder => :parent_container, :occupant => :occupied_container)
|
11
|
+
|
12
|
+
# Each ContainerPosition has a container and there is only one position per container.
|
13
|
+
set_secondary_key_attributes(:occupied_container)
|
14
|
+
|
15
|
+
set_attribute_inverse(:parent_container, :occupied_positions)
|
16
|
+
|
17
|
+
set_attribute_inverse(:occupied_container, :located_at_position)
|
18
|
+
|
19
|
+
qualify_attribute(:parent_container, :fetched)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'caruby/util/options'
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
# import the Java class
|
5
|
+
java_import('edu.wustl.catissuecore.domain.ContainerType')
|
6
|
+
|
7
|
+
# The caTissue ContainerType domain class wrapper.
|
8
|
+
# Each {ContainerType} subclass is required to implement the container_class method.
|
9
|
+
#
|
10
|
+
# caTissue alert - the ContainerType and Container class hierarchy is a confusing
|
11
|
+
# olio of entangled relationships. Conceptually, specimens are contained in boxes,
|
12
|
+
# vials and specimen arrays of various types. When specimens are frozen, these
|
13
|
+
# containers are placed on a rack in a freezer.
|
14
|
+
#
|
15
|
+
# This conceptual model is implemented in caTissue as follows:
|
16
|
+
# * The specimen collection container type, e.g. +Citrate Vacutainer+, is captured
|
17
|
+
# as a {CaTissue::CollectionEventParameters#container} String. There is no separate
|
18
|
+
# collection container instance or container type instance.
|
19
|
+
# * A tissue specimen storage box is captured as a {CaTissue::StorageContainer}
|
20
|
+
# instance constrained to a {CaTissue::StorageType} instance. Boxes with different
|
21
|
+
# types are instances of the same {CaTissue::StorageContainer} class but belong
|
22
|
+
# to different {CaTissue::StorageType} instances.
|
23
|
+
# * {CaTissue::SpecimenArray} is a {CaTissue::Container} but not a {CaTissue::StorageContainer}.
|
24
|
+
# The specimen array class is {CaTissue::SpecimenArray}, but its type is a
|
25
|
+
# {CaTissue::SpecimenArrayType} instance, which is a {CaTissue::ContainerType} but not
|
26
|
+
# a {CaTissue::StorageType}.
|
27
|
+
# * A rack is a {CaTissue::StorageContainer} instance whose type is a {CaTissue::StorageType}
|
28
|
+
# instance which can hold the box {CaTissue::StorageType}.
|
29
|
+
# * A freezer is a {CaTissue::StorageContainer} instance whose type is a {CaTissue::StorageType}
|
30
|
+
# instance which can hold the rack {CaTissue::StorageType}.
|
31
|
+
# * Each {CaTissue::StorageContainer} belongs to a given {CaTissue::Site}. A child
|
32
|
+
# {CaTissue::StorageContainer} site defaults to its parent container site.
|
33
|
+
# Site consistency is not enforced by caTissue, i.e. it is possible to create
|
34
|
+
# a rack whose site differs from that of its parent freezer and child boxes.
|
35
|
+
# * {CaTissue::SpecimenArray} is not associated to a site.
|
36
|
+
# * The container children are partitioned into three methods for the three different
|
37
|
+
# types and pseudo-types of contained items: {CaTissue::StorageContainer},
|
38
|
+
# {CaTissue::SpecimenArray} and {CaTissue::Specimen#class}.
|
39
|
+
# * {CaTissue::SpecimenArray} holds {CaTissue::SpecimenArrayContent} positions, which
|
40
|
+
# are the functional equivalent of {CaTissue::SpecimenPosition} adapted for specimen
|
41
|
+
# arrays, although {CaTissue::SpecimenArrayContent} is not a {CaTissue::SpecimenPosition}
|
42
|
+
# or even an {CaTissue::AbstractPosition}. {CaTissue::SpecimenPosition} is functionally
|
43
|
+
# a specimen position in a box, whereas {CaTissue::SpecimenArrayContent} is functionally
|
44
|
+
# a specimen position in a specimen array.
|
45
|
+
#
|
46
|
+
# The ContainerType/Container mish-mash is partially alleviated in caRuby as follows:
|
47
|
+
# * {CaTissue::StorageType} and {CaTissue::StorageContainer} include the
|
48
|
+
# {CaTissue::StorageTypeHolder} module, which unifies treatment of contained
|
49
|
+
# types.
|
50
|
+
# * Similarly, {CaTissue::AbstractPosition} and {CaTissue::SpecimenArrayContent} include
|
51
|
+
# the {CaTissue::Position} module, which unifies treatment of positions.
|
52
|
+
# * Contained child types are consolidated into {CaTissue::StorageTypeHolder#child_types}
|
53
|
+
# * Similarly, {CaTissue::StorageContainer} child items are consolidated into
|
54
|
+
# {CaTissue::StorageContainer#child_types}
|
55
|
+
# * The various container and position classes are augmented with helper methods to
|
56
|
+
# add, move and find specimens and subcontainers. These methods hide the mind-numbing
|
57
|
+
# eccentricity of caTissue specimen storage interaction.
|
58
|
+
class ContainerType
|
59
|
+
include Resource
|
60
|
+
|
61
|
+
add_attribute_aliases(:column_label => :oneDimensionLabel, :row_label => :twoDimensionLabel)
|
62
|
+
|
63
|
+
add_attribute_defaults(:activity_status => 'Active')
|
64
|
+
|
65
|
+
set_secondary_key_attributes(:name)
|
66
|
+
|
67
|
+
add_mandatory_attributes(:activity_status, :capacity, :one_dimension_label, :two_dimension_label)
|
68
|
+
|
69
|
+
# caTissue alert - although capacity is not marked cascaded in Hibernate, it is created when the
|
70
|
+
# ContainerType is created.
|
71
|
+
add_dependent_attribute(:capacity)
|
72
|
+
|
73
|
+
# Override default {CaRuby::Resource#merge_attributes} to support the Capacity :rows and :columns
|
74
|
+
# pseudo-attributes.
|
75
|
+
#
|
76
|
+
# @param (see CaRuby::Resource#merge_attributes)
|
77
|
+
def merge_attributes(other, attributes=nil)
|
78
|
+
if Hash === other then
|
79
|
+
# partition the other hash into the Capacity attributes and ContainerType attributes
|
80
|
+
cp_hash, ct_hash = other.partition { |key, value| key == :rows or key == :columns }
|
81
|
+
self.capacity ||= Capacity.new(cp_hash).add_defaults unless cp_hash.empty?
|
82
|
+
super(ct_hash, attributes)
|
83
|
+
else
|
84
|
+
super(other, attributes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [CaTissue::Site] site the site where the candidate containers are located
|
89
|
+
# @param opts (see CaRuby::Writer#find)
|
90
|
+
# @option (see CaRuby::Writer#find)
|
91
|
+
# @return an available container of this ContainerType which is not
|
92
|
+
# {CaTissue::Container#completely_full?}.
|
93
|
+
def find_available(site, opts=nil)
|
94
|
+
find_containers(:site => site).detect { |ctr| not ctr.completely_full? } or
|
95
|
+
(create_container(:site => site).create if Options.get(:create, opts))
|
96
|
+
end
|
97
|
+
|
98
|
+
# Fetches containers of this ContainerType from the database.
|
99
|
+
#
|
100
|
+
# @param [<Symbol => Object>] params the optional search attribute => value hash
|
101
|
+
# @return the containers of this type which satisfy the search parameters
|
102
|
+
def find_containers(params=nil)
|
103
|
+
tmpl = create_container(params)
|
104
|
+
logger.debug { "Finding #{name} containers..." }
|
105
|
+
tmpl.query
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns a new Container instance of this ContainerType with an optional attribute => value hash.
|
109
|
+
# The container_type of the new Container is this ContainerType.
|
110
|
+
#
|
111
|
+
# @param [{Symbol => Object}] vh the attribute => value hash
|
112
|
+
# @return [Container] the new container
|
113
|
+
def create_container(vh=nil)
|
114
|
+
vh ||= {}
|
115
|
+
vh[:container_type] = self
|
116
|
+
container_class.new(vh)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Adds an empty capacity and default dimension labels, if necessary.
|
122
|
+
# The default {#one_dimension_label} is 'Column' if there is a non-zero dimension capacity, 'Unused' otherwise.
|
123
|
+
# The default {#two_dimension_label} is 'Row' if there is a non-zero dimension capacity, 'Unused' otherwise.
|
124
|
+
def add_defaults_local
|
125
|
+
super
|
126
|
+
self.capacity ||= Capacity.new.add_defaults
|
127
|
+
self.row_label ||= capacity.rows && capacity.rows > 0 ? 'Row' : 'Unused'
|
128
|
+
self.column_label ||= capacity.columns && capacity.columns > 0 ? 'Column' : 'Unused'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CaTissue
|
2
|
+
# import the Java class
|
3
|
+
java_import('edu.wustl.catissuecore.domain.DisposalEventParameters')
|
4
|
+
|
5
|
+
class DisposalEventParameters
|
6
|
+
include Resource
|
7
|
+
|
8
|
+
add_attribute_defaults(:activity_status => 'Closed')
|
9
|
+
|
10
|
+
# caTissue alert - DisposalEventParameters activity status is transient.
|
11
|
+
qualify_attribute(:activity_status, :unfetched)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
# import the Java class
|
5
|
+
java_import('edu.wustl.catissuecore.domain.ExternalIdentifier')
|
6
|
+
|
7
|
+
# The ExternalIdentifier domain class.
|
8
|
+
class ExternalIdentifier
|
9
|
+
include Resource
|
10
|
+
|
11
|
+
# Sets this ExternalIdentifier value to the given value.
|
12
|
+
# A Numeric value is converted to a String.
|
13
|
+
def value=(value)
|
14
|
+
value = value.to_s if value
|
15
|
+
setValue(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
add_mandatory_attributes(:value)
|
19
|
+
|
20
|
+
set_secondary_key_attributes(:specimen, :name)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'catissue/resource'
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
# import the Java class
|
5
|
+
java_import('edu.wustl.catissuecore.domain.NewSpecimenArrayOrderItem')
|
6
|
+
|
7
|
+
# The NewSpecimenArrayOrderItem domain class.
|
8
|
+
class NewSpecimenArrayOrderItem
|
9
|
+
include Resource
|
10
|
+
|
11
|
+
# caTissue alert - Bug #64: Some domain collection properties not initialized.
|
12
|
+
# Initialize order_items if necessary.
|
13
|
+
#
|
14
|
+
# @return [Java::JavaUtil::Set] the items
|
15
|
+
def order_items
|
16
|
+
getOrderItemCollection or (self.order_items = Java::JavaUtil::LinkedHashSet.new)
|
17
|
+
end
|
18
|
+
|
19
|
+
# caTissue alert - Bug #64: Some domain collection properties not initialized.
|
20
|
+
# Initialize distributions if necessary.
|
21
|
+
def distributions
|
22
|
+
getDistributionCollection or (self.distributions = Java::JavaUtil::LinkedHashSet.new)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(params=nil)
|
26
|
+
super
|
27
|
+
# jRuby bug? - Java methods not acceesible until respond_to? called; TODO - reconfirm this
|
28
|
+
respond_to?(:order_items)
|
29
|
+
respond_to?(:distributions)
|
30
|
+
# work around caTissue Bug #64
|
31
|
+
self.order_items ||= Java::JavaUtil::LinkedHashSet.new
|
32
|
+
self.distributions ||= Java::JavaUtil::LinkedHashSet.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
java_import('edu.wustl.catissuecore.domain.OrderDetails')
|
5
|
+
|
6
|
+
# The OrderDetails domain class.
|
7
|
+
class OrderDetails
|
8
|
+
include Resource
|
9
|
+
|
10
|
+
# caTissue alert - Bug #64: Some domain collection properties not initialized.
|
11
|
+
# Initialize order_items if necessary.
|
12
|
+
#
|
13
|
+
# @return [Java::JavaUtil::Set] the items
|
14
|
+
def order_items
|
15
|
+
getOrderItemCollection or (self.order_items = Java::JavaUtil::LinkedHashSet.new)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(params=nil)
|
19
|
+
super
|
20
|
+
respond_to?(:order_items)
|
21
|
+
# caTissue alert - work around caTissue Bug #64
|
22
|
+
self.order_items ||= Java::JavaUtil::LinkedHashSet.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'caruby/util/validation'
|
2
|
+
require 'catissue/resource'
|
3
|
+
require 'catissue/util/person'
|
4
|
+
|
5
|
+
module CaTissue
|
6
|
+
# import the Java class
|
7
|
+
java_import('edu.wustl.catissuecore.domain.Participant')
|
8
|
+
|
9
|
+
# The Participant domain class.
|
10
|
+
class Participant
|
11
|
+
include Resource, Person
|
12
|
+
|
13
|
+
# The convenience Person name aggregate is not a Java property but is added as a transient attribute
|
14
|
+
# which is reflected in the saved Java property name subfields.
|
15
|
+
add_attribute(:name)
|
16
|
+
|
17
|
+
# caTissue alert - clinical study is unsupported by caTissue.
|
18
|
+
remove_attribute(:clinical_study_registrations)
|
19
|
+
|
20
|
+
add_attribute_aliases(:collection_registrations => :collection_protocol_registrations,
|
21
|
+
:registrations => :collection_protocol_registrations,
|
22
|
+
:medical_identifiers => :participant_medical_identifiers)
|
23
|
+
|
24
|
+
set_secondary_key_attributes(:social_security_number)
|
25
|
+
|
26
|
+
# Clarification on defaults:
|
27
|
+
# * 'Unknown': value is unknown by anybody
|
28
|
+
# * 'Unspecified': value is known by somebody, but the data was not communicated to the bank
|
29
|
+
# cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=16&t=672&p=2343&e=2343
|
30
|
+
add_attribute_defaults(:activity_status => 'Active', :ethnicity => 'Unknown', :gender => 'Unspecified',
|
31
|
+
:sex_genotype => 'Unknown', :vital_status => 'Unknown')
|
32
|
+
|
33
|
+
# caTissue alert - Bug #154: Participant gender is specified by caTissue as optional, but if it is not set then
|
34
|
+
# it appears as Female in the GUI even though it is null in the database.
|
35
|
+
add_mandatory_attributes(:activity_status, :gender)
|
36
|
+
|
37
|
+
add_dependent_attribute(:collection_protocol_registrations, :logical)
|
38
|
+
|
39
|
+
add_dependent_attribute(:races)
|
40
|
+
|
41
|
+
# PMI is not cascaded, but insert is done in the bizlogic.
|
42
|
+
add_dependent_attribute(:participant_medical_identifiers)
|
43
|
+
|
44
|
+
# SSN is a key, if present, but is not required.
|
45
|
+
qualify_attribute(:social_security_number, :optional)
|
46
|
+
|
47
|
+
qualify_attribute(:collection_protocol_registrations, :fetched)
|
48
|
+
|
49
|
+
qualify_attribute(:participant_medical_identifiers, :fetched)
|
50
|
+
|
51
|
+
def merge_attribute_value(attribute, oldval, newval)
|
52
|
+
# caTissue alert - remove the autogenerated blank PMI.
|
53
|
+
# TODO - file bug
|
54
|
+
# @see CaTissue::Database#query_safe
|
55
|
+
if attribute == :participant_medical_identifiers and newval then
|
56
|
+
CaTissue::Participant.remove_empty_medical_identifier(newval)
|
57
|
+
end
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the SSN if it exists, otherwise the first ParticipantMedicalIdentifier, if any, otherwise nil.
|
62
|
+
def key
|
63
|
+
super or medical_identifiers.first
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns a new ParticipantMedicalIdentifier which adds this Participant to the given site
|
67
|
+
# with Medical Record Number mrn.
|
68
|
+
def add_mrn(site, mrn)
|
69
|
+
CaTissue::ParticipantMedicalIdentifier.new(:participant => self, :site => site, :medical_record_number => mrn)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns this Participant's medical record numbers. Each medical record number is Site-specific.
|
73
|
+
# @see the medical_identifiers attribute for MRN-site associations
|
74
|
+
def medical_record_numbers
|
75
|
+
medical_identifiers.map { |pmi| pmi.medicalRecordNumber }
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns all specimens collected from this Participant.
|
79
|
+
def specimens
|
80
|
+
Flattener.new(registrations.specimens.map { |cpr| cpr.specimens })
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns this Participant's CollectionProtocolRegistration protocols.
|
84
|
+
def collection_protocols
|
85
|
+
collection_registrations.map { |reg| reg.protocol }.uniq
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the MRN for this participant. If this Participant does not have exactly one
|
89
|
+
# MRN, then this method returns nil. This method is a convenience for the common situation
|
90
|
+
# where a participant is enrolled at one site.
|
91
|
+
def medical_record_number
|
92
|
+
return medical_identifiers.first.medical_record_number if medical_identifiers.size == 1
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the collection site for which this participant has a MRN. If there is not exactly one
|
96
|
+
# such site, then this method returns nil. This method is a convenience for the common situation
|
97
|
+
# where a participant is enrolled at one site.
|
98
|
+
def collection_site
|
99
|
+
return unless medical_identifiers.size == 1
|
100
|
+
site = medical_identifiers.first.site
|
101
|
+
return if site.nil?
|
102
|
+
site.site_type == Site::SiteType::COLLECTION ? site : nil
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def self.remove_empty_medical_identifier(mids)
|
108
|
+
bogus = mids.detect { |mid| mid.medical_record_number.nil? }
|
109
|
+
if bogus then
|
110
|
+
logger.debug { "Work around caTissue bug by removing empty fetched #{bogus.participant.qp} #{bogus.qp}..." }
|
111
|
+
# dissociate the participant
|
112
|
+
bogus.participant = nil
|
113
|
+
# remove the bogus medical identifier
|
114
|
+
mids.delete(bogus)
|
115
|
+
end
|
116
|
+
mids
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Returns the first Medical Record Number qualified by the MRN site, if this exists.
|
122
|
+
def alternate_key
|
123
|
+
return if medical_identifiers.empty?
|
124
|
+
pmi = medical_identifiers.first
|
125
|
+
pmi.key if pmi
|
126
|
+
end
|
127
|
+
|
128
|
+
# Adds a default Unknown Race, if necessary. Although Race is not strictly mandatory in the caTissue
|
129
|
+
# API, setting this default emulates the caTissue UI Add Participant page.
|
130
|
+
def add_defaults_local
|
131
|
+
super
|
132
|
+
# Make a new default Race which references this Participant, if necessary. Setting the Race
|
133
|
+
# participant to self automatically adds the Race to this Participant's races collection.
|
134
|
+
# The Race name defaults to Unknown.
|
135
|
+
if races.empty? then CaTissue::Race.new(:participant => self).add_defaults end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|