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.
Files changed (133) hide show
  1. data/History.txt +4 -0
  2. data/LEGAL +5 -0
  3. data/LICENSE +22 -0
  4. data/README.md +44 -0
  5. data/bin/crtdump +31 -0
  6. data/bin/crtexample +18 -0
  7. data/bin/crtextract +47 -0
  8. data/bin/crtmigrate +17 -0
  9. data/bin/crtsmoke +27 -0
  10. data/examples/galena/README.md +53 -0
  11. data/examples/galena/bin/migrate.rb +42 -0
  12. data/examples/galena/bin/seed.rb +43 -0
  13. data/examples/galena/conf/extract/simple_fields.yaml +4 -0
  14. data/examples/galena/conf/migration/filter_fields.yaml +7 -0
  15. data/examples/galena/conf/migration/filter_migration.yaml +9 -0
  16. data/examples/galena/conf/migration/frozen_fields.yaml +11 -0
  17. data/examples/galena/conf/migration/frozen_migration.yaml +9 -0
  18. data/examples/galena/conf/migration/general_fields.yaml +42 -0
  19. data/examples/galena/conf/migration/general_migration.yaml +9 -0
  20. data/examples/galena/conf/migration/simple_fields.yaml +30 -0
  21. data/examples/galena/conf/migration/simple_migration.yaml +7 -0
  22. data/examples/galena/conf/migration/small_fields.yaml +24 -0
  23. data/examples/galena/conf/migration/small_migration.yaml +9 -0
  24. data/examples/galena/data/filter.csv +1 -0
  25. data/examples/galena/data/frozen.csv +1 -0
  26. data/examples/galena/data/general.csv +1 -0
  27. data/examples/galena/data/minimal.csv +1 -0
  28. data/examples/galena/data/simple.csv +1 -0
  29. data/examples/galena/data/small.csv +1 -0
  30. data/examples/galena/doc/CaTissue.html +93 -0
  31. data/examples/galena/doc/CaTissue/CollectionProtocolRegistration.html +181 -0
  32. data/examples/galena/doc/CaTissue/Participant.html +241 -0
  33. data/examples/galena/doc/CaTissue/SpecimenCollectionGroup.html +190 -0
  34. data/examples/galena/doc/CaTissue/StorageContainer.html +179 -0
  35. data/examples/galena/doc/CaTissue/TissueSpecimen.html +320 -0
  36. data/examples/galena/doc/Galena.html +290 -0
  37. data/examples/galena/doc/Galena/Seed.html +203 -0
  38. data/examples/galena/doc/Galena/Seed/Defaults.html +646 -0
  39. data/examples/galena/doc/_index.html +188 -0
  40. data/examples/galena/doc/class_list.html +36 -0
  41. data/examples/galena/doc/css/common.css +1 -0
  42. data/examples/galena/doc/css/full_list.css +53 -0
  43. data/examples/galena/doc/css/style.css +307 -0
  44. data/examples/galena/doc/file.README.html +108 -0
  45. data/examples/galena/doc/file_list.html +38 -0
  46. data/examples/galena/doc/frames.html +13 -0
  47. data/examples/galena/doc/index.html +108 -0
  48. data/examples/galena/doc/js/app.js +202 -0
  49. data/examples/galena/doc/js/full_list.js +149 -0
  50. data/examples/galena/doc/js/jquery.js +154 -0
  51. data/examples/galena/doc/method_list.html +179 -0
  52. data/examples/galena/doc/top-level-namespace.html +112 -0
  53. data/examples/galena/lib/README.html +33 -0
  54. data/examples/galena/lib/galena.rb +8 -0
  55. data/examples/galena/lib/galena/cli/seed.rb +43 -0
  56. data/examples/galena/lib/galena/migration/filter_shims.rb +43 -0
  57. data/examples/galena/lib/galena/migration/frozen_shims.rb +54 -0
  58. data/examples/galena/lib/galena/seed/defaults.rb +97 -0
  59. data/lib/catissue.rb +26 -0
  60. data/lib/catissue/cli/command.rb +51 -0
  61. data/lib/catissue/cli/example.rb +31 -0
  62. data/lib/catissue/cli/migrate.rb +60 -0
  63. data/lib/catissue/cli/smoke.rb +45 -0
  64. data/lib/catissue/database.rb +451 -0
  65. data/lib/catissue/database/annotation/annotatable_service.rb +25 -0
  66. data/lib/catissue/database/annotation/annotation_service.rb +79 -0
  67. data/lib/catissue/database/annotation/annotator.rb +84 -0
  68. data/lib/catissue/database/annotation/entity_manager.rb +10 -0
  69. data/lib/catissue/database/annotation/integration_service.rb +87 -0
  70. data/lib/catissue/database/controlled_value_finder.rb +43 -0
  71. data/lib/catissue/database/controlled_values.rb +162 -0
  72. data/lib/catissue/domain/abstract_domain_object.rb +8 -0
  73. data/lib/catissue/domain/abstract_position.rb +22 -0
  74. data/lib/catissue/domain/abstract_specimen.rb +288 -0
  75. data/lib/catissue/domain/abstract_specimen_collection_group.rb +25 -0
  76. data/lib/catissue/domain/address.rb +13 -0
  77. data/lib/catissue/domain/cancer_research_group.rb +11 -0
  78. data/lib/catissue/domain/capacity.rb +34 -0
  79. data/lib/catissue/domain/check_in_check_out_event_parameter.rb +19 -0
  80. data/lib/catissue/domain/collection_event_parameters.rb +13 -0
  81. data/lib/catissue/domain/collection_protocol.rb +177 -0
  82. data/lib/catissue/domain/collection_protocol_event.rb +108 -0
  83. data/lib/catissue/domain/collection_protocol_registration.rb +108 -0
  84. data/lib/catissue/domain/consent_tier_response.rb +13 -0
  85. data/lib/catissue/domain/consent_tier_status.rb +29 -0
  86. data/lib/catissue/domain/container.rb +234 -0
  87. data/lib/catissue/domain/container_position.rb +21 -0
  88. data/lib/catissue/domain/container_type.rb +131 -0
  89. data/lib/catissue/domain/department.rb +13 -0
  90. data/lib/catissue/domain/disposal_event_parameters.rb +13 -0
  91. data/lib/catissue/domain/embedded_event_parameters.rb +10 -0
  92. data/lib/catissue/domain/external_identifier.rb +22 -0
  93. data/lib/catissue/domain/frozen_event_parameters.rb +10 -0
  94. data/lib/catissue/domain/institution.rb +13 -0
  95. data/lib/catissue/domain/new_specimen_array_order_item.rb +35 -0
  96. data/lib/catissue/domain/order_details.rb +25 -0
  97. data/lib/catissue/domain/participant.rb +138 -0
  98. data/lib/catissue/domain/participant_medical_identifier.rb +38 -0
  99. data/lib/catissue/domain/password.rb +11 -0
  100. data/lib/catissue/domain/race.rb +11 -0
  101. data/lib/catissue/domain/received_event_parameters.rb +25 -0
  102. data/lib/catissue/domain/scg_event_parameters.rb +11 -0
  103. data/lib/catissue/domain/site.rb +30 -0
  104. data/lib/catissue/domain/specimen.rb +456 -0
  105. data/lib/catissue/domain/specimen_array.rb +47 -0
  106. data/lib/catissue/domain/specimen_array_content.rb +19 -0
  107. data/lib/catissue/domain/specimen_array_type.rb +20 -0
  108. data/lib/catissue/domain/specimen_characteristics.rb +20 -0
  109. data/lib/catissue/domain/specimen_collection_group.rb +412 -0
  110. data/lib/catissue/domain/specimen_event_parameters.rb +111 -0
  111. data/lib/catissue/domain/specimen_position.rb +38 -0
  112. data/lib/catissue/domain/specimen_protocol.rb +34 -0
  113. data/lib/catissue/domain/specimen_requirement.rb +143 -0
  114. data/lib/catissue/domain/storage_container.rb +204 -0
  115. data/lib/catissue/domain/storage_type.rb +82 -0
  116. data/lib/catissue/domain/transfer_event_parameters.rb +53 -0
  117. data/lib/catissue/domain/user.rb +100 -0
  118. data/lib/catissue/extract/command.rb +31 -0
  119. data/lib/catissue/extract/delta.rb +62 -0
  120. data/lib/catissue/extract/extractor.rb +99 -0
  121. data/lib/catissue/migration/migrator.rb +101 -0
  122. data/lib/catissue/migration/shims.rb +108 -0
  123. data/lib/catissue/migration/uniquify.rb +111 -0
  124. data/lib/catissue/resource.rb +84 -0
  125. data/lib/catissue/util/controlled_value.rb +29 -0
  126. data/lib/catissue/util/location.rb +116 -0
  127. data/lib/catissue/util/log.rb +30 -0
  128. data/lib/catissue/util/person.rb +31 -0
  129. data/lib/catissue/util/position.rb +54 -0
  130. data/lib/catissue/util/storable.rb +34 -0
  131. data/lib/catissue/util/storage_type_holder.rb +30 -0
  132. data/lib/catissue/version.rb +7 -0
  133. metadata +212 -0
@@ -0,0 +1,82 @@
1
+ require 'caruby/util/collection'
2
+ require 'caruby/util/partial_order'
3
+ require 'catissue/util/storage_type_holder'
4
+
5
+ module CaTissue
6
+ # import the Java class
7
+ java_import('edu.wustl.catissuecore.domain.StorageType')
8
+
9
+ # The StorageType domain class.
10
+ class StorageType
11
+ include StorageTypeHolder, PartialOrder, Resource
12
+
13
+ add_attribute_aliases(:default_temperature => :default_temprature_in_centigrade)
14
+
15
+ qualify_attribute(:holds_storage_types, :fetched)
16
+
17
+ qualify_attribute(:holds_specimen_array_types, :fetched)
18
+
19
+ set_attribute_type(:holds_specimen_array_types, CaTissue::SpecimenArrayType)
20
+
21
+ set_attribute_type(:holds_specimen_classes, String)
22
+
23
+ set_attribute_type(:holds_storage_types, CaTissue::StorageType)
24
+
25
+ # @return StorageContainer
26
+ def container_class
27
+ CaTissue::StorageContainer
28
+ end
29
+
30
+ alias :add_child :add_child_type
31
+
32
+ alias :add :add_child_type
33
+
34
+ alias :<< :add_child_type
35
+
36
+ # @return whether this StorageType can hold a child of the given Storable storable type
37
+ def can_hold_child?(storable)
38
+ child_types.include?(storable.storable_type)
39
+ end
40
+
41
+ # Returns a StorageType array from this StorageType to a descendant StorageType which can
42
+ # hold the given storable, or nil if no such path exists.
43
+ def path_to(storable)
44
+ return [self] if can_hold_child?(storable)
45
+ path = holds_storage_types.detect_value { |child| child.path_to(storable) }
46
+ return path.unshift(self) if path
47
+ end
48
+
49
+ # @return the closure of ContainerTypes held by this ContainerType, including self
50
+ def closure
51
+ cts = [self]
52
+ child_types.each { |ct| cts.concat(ct.closure) if StorageType === ct }
53
+ cts
54
+ end
55
+
56
+ # @return whether this StorageType has a non-nil name equal to the other name or is {#equal?} to this StorageType
57
+ #
58
+ # This method is a work-around for caTissue Bug #70: StorageType and non-StorageType are equal.
59
+ def ==(other)
60
+ equal?(other) or (StorageType === other and name and name == other.name)
61
+ end
62
+
63
+ alias :eql? :==
64
+
65
+ # Returns -1, 0, or 1 if self is contained in, contains or the same as the other
66
+ # StorageType, resp.
67
+ def <=>(other)
68
+ raise TypeError.new("Can't compare #{qp} to #{other}") unless StorageType === self
69
+ return 0 if eql?(other)
70
+ return 1 if holds_storage_types.detect { |child| child >= other }
71
+ -1 if other > self
72
+ end
73
+
74
+ # Overrides the Java StorageType hashCode to make the hash insensitive to identifier assignment.
75
+ #
76
+ # @see #==
77
+ def hash
78
+ # caTissue alert - bad caTissue API hashCode leads to ugly cascading errors when using a CP in a Set
79
+ (object_id * 31) + 17
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,53 @@
1
+ require 'caruby/util/validation'
2
+ require 'catissue/util/location'
3
+
4
+ module CaTissue
5
+ # import the Java class
6
+ java_import('edu.wustl.catissuecore.domain.TransferEventParameters')
7
+
8
+ # The +caTissue+ TransferEventParameters class is augmented with zero-based
9
+ # +from_row+, +from_column+, +to_row+ and +to_column+ methods wrapping the corresponding one-based dimension attributes.
10
+ class TransferEventParameters
11
+ include Resource
12
+
13
+ add_attribute_aliases(:from_container => :from_storage_container, :to_container => :to_storage_container)
14
+
15
+ # column and row are the zero-offset counterparts of position_dimension_one and position_dimension_two, resp.
16
+ offset_attribute(:from_column => :from_position_dimension_one, :from_row => :from_position_dimension_two,
17
+ :to_column => :to_position_dimension_one, :to_row => :to_position_dimension_two)
18
+
19
+ add_mandatory_attributes(:to_container, :to_position_dimension_one, :to_position_dimension_two)
20
+
21
+ # Returns the from Location.
22
+ def from
23
+ Location.new(:in => from_container, :at => [from_column, from_row]) if from_container
24
+ end
25
+
26
+ # Sets the from Location.
27
+ def from=(location)
28
+ if location then
29
+ self.from_container = location.container
30
+ self.from_row = location.row
31
+ self.from_column = location.column
32
+ end
33
+ location
34
+ end
35
+
36
+ add_attribute(:from)
37
+
38
+ # Returns the to Location.
39
+ def to
40
+ Location.new(:in => to_container, :at => [to_column, to_row]) if to_container
41
+ end
42
+
43
+ # Sets the to Location.
44
+ def to=(location)
45
+ if location.nil? then raise ArgumentError.new("Specimen cannot be moved to an empty location") end
46
+ self.to_container = location.container
47
+ self.to_row = location.row
48
+ self.to_column = location.column
49
+ end
50
+
51
+ add_attribute(:to)
52
+ end
53
+ end
@@ -0,0 +1,100 @@
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.User')
8
+
9
+ # The User domain class.
10
+ class User
11
+ include Person, Resource
12
+
13
+ # caTissue alert - work-around for caTissue Bug #66 - Client missing CSException class et al.
14
+ # caTissue User class initializes roleId to "", which triggers a client exception on subsequent
15
+ # getRoleId call. Use a private variable instead and bypass getRoleId.
16
+ def role_id
17
+ # TODO - uncomment following and get rid of @role_id i.v. when bug is fixed.
18
+ #value = send(old_method)
19
+ #return if value == ''
20
+ #value.to_i
21
+ @role_id
22
+ end
23
+
24
+ # Sets the role id to the given value, which can be either a String or an Integer.
25
+ # An empty or zero value is converted to nil.
26
+ #
27
+ # caTissue alert - caTissue API roleId is a String although the intended value domain is the
28
+ # integer csm_role.identifier.
29
+ def role_id=(value)
30
+ # value as an integer (nil is zero)
31
+ value_i = value.to_i
32
+ # set the Bug #66 work-around i.v.
33
+ @role_id = value_i.zero? ? nil : value_i
34
+ # value as a String (if non-nil)
35
+ value_s = @role_id.to_s if @role_id
36
+ # call Java with a String
37
+ setRoleId(value_s)
38
+ end
39
+
40
+ # make the convenience Person name a first-class attribute
41
+ add_attribute(:name)
42
+
43
+ # caTissue alert - clinical study is unsupported by caTissue.
44
+ remove_attribute(:clinical_studies)
45
+
46
+ # clarify that collection_protocols is a coordinator -> protocol association.
47
+ # make assigned protocol and site attribute names consistent.
48
+ add_attribute_aliases(:coordinated_protocols => :collection_protocols, :protocols => :assigned_protocols, :assigned_sites => :sites)
49
+
50
+ # login_name is a database unique key.
51
+ set_secondary_key_attributes(:login_name)
52
+
53
+ # email_address is expected to be unique, and is enforced by the caTissue business logic.
54
+ set_alternate_key_attributes(:email_address)
55
+
56
+ # Set defaults as follows:
57
+ # * page_of is the value set when creating a User in the GUI
58
+ # * role id is 7 = Scientist (public)
59
+ # * initial password is 'changeMe1'
60
+ add_attribute_defaults(:activity_status => 'Active', :page_of => 'pageOfUserAdmin', :role_id => 7, :new_password => 'changeMe1')
61
+
62
+ # caTissue alert - obscure GUI artifact User page_of attribute is insinuated into the data
63
+ # layer as a required attribute. Work-around is to simulate the GUI with a default value.
64
+ add_mandatory_attributes(:activity_status, :address, :cancer_research_group, :department,
65
+ :email_address, :first_name, :institution, :last_name, :page_of, :role_id)
66
+
67
+ add_dependent_attribute(:address)
68
+
69
+ add_dependent_attribute(:passwords)
70
+
71
+ set_attribute_inverse(:protocols, :assigned_protocol_users)
72
+
73
+ set_attribute_inverse(:sites, :assigned_site_users)
74
+
75
+ qualify_attribute(:cancer_research_group, :fetched)
76
+
77
+ qualify_attribute(:department, :fetched)
78
+
79
+ qualify_attribute(:institution, :fetched)
80
+
81
+ qualify_attribute(:protocols, :saved, :fetched)
82
+
83
+ qualify_attribute(:sites, :saved)
84
+
85
+ qualify_attribute(:page_of, :unfetched)
86
+
87
+ qualify_attribute(:new_password, :unfetched)
88
+
89
+ qualify_attribute(:role_id, :unfetched)
90
+
91
+ private
92
+
93
+ # By default, the emailAddress is the same as the loginName.
94
+ def add_defaults_local
95
+ super
96
+ self.login_name ||= email_address
97
+ self.email_address ||= login_name
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,31 @@
1
+ require 'catissue/cli/command'
2
+ require 'catissue/extract/delta'
3
+ require 'catissue/extract/extractor'
4
+
5
+ module CaTissue
6
+ # ExtractCommand extracts target CaTissue domain class objects whose modification date is
7
+ # within a time interval to a CSV file based on a CSV mapping file.
8
+ class ExtractCommand < CaTissue::Command
9
+ # Creates a new ExtractCommand.
10
+ # The delta range is given by the required :since option and optional :before option.
11
+ # The default before value is the current DateTime. These are used to build a Delta
12
+ # which is passed to {CaRuby::Command#initialize} as the :ids option.
13
+ # The :log option specifies a log file.
14
+ # Other supported options are described in {Extractor#initialize}.
15
+ def initialize
16
+ # prep the options
17
+ since = opts.delete(:since)
18
+ raise ArgumentError.new("Missing required beginning of date selection range option") unless since
19
+ before = opts.delete(:before) || DateTime.now
20
+ # the data acquirer
21
+ opts[:ids] = Delta.new(@target, since, before)
22
+ # make the command
23
+ super(opts)
24
+ end
25
+
26
+ # Starts an Extractor with the command-line options.
27
+ def run
28
+ super { |opts| Extractor.new(opts) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ require 'date'
2
+ require 'caruby/csv/csvio'
3
+ require 'caruby/util/log'
4
+ require 'caruby/util/collection'
5
+ require 'caruby/util/pretty_print'
6
+ require 'caruby/database/sql_executor'
7
+
8
+ module CaTissue
9
+ # Delta determines caTissue objects which changed within a time interval.
10
+ class Delta
11
+ include Enumerable
12
+
13
+ private
14
+
15
+ SQL_FILE = File.join(File.dirname(__FILE__), '..', '..', '..', 'sql', 'delta.sql')
16
+
17
+ public
18
+
19
+ # Creates a new Delta for objects of the given target type which changed
20
+ # at or after the since Date and earlier but not at the before Date.
21
+ # The default before Date is now.
22
+ def initialize(target, since, before=nil)
23
+ # convert the required target to a CaTissue class if necessary
24
+ @matcher = create_table_regex(target)
25
+ @since = since
26
+ @before = before || DateTime.now
27
+ end
28
+
29
+ # Calls the given block on each caTissue identifier satisfying the delta condition.
30
+ # This method submits the delta SQL and filters the result on the target class.
31
+ # This method always submits the query; the caller is responsible for preserving
32
+ # the result if necessary using {#to_a}.
33
+ def each(&block)
34
+ execute_query(&block)
35
+ end
36
+
37
+ private
38
+
39
+ # Returns the result of running the delta SQL on the target CaTissue domain class.
40
+ def execute_query
41
+ sql = File.open(SQL_FILE) { |file| file.read }
42
+ logger.debug { "Executing identifier change set selection range #{@since} - #{@before}, SQL:\n#{sql}" }
43
+ CaRuby::SQLExecutor.new(CaTissue.access_properties).execute do |dbh|
44
+ dbh.select_all(sql, @since, @before) do |row|
45
+ table, identifier = row
46
+ yield identifier.to_i if table =~ @matcher
47
+ end
48
+ end
49
+ end
50
+
51
+ # Returns the table match REs for the given target class.
52
+ def create_table_regex(target)
53
+ # The class => table RE hash. Make this hash rather than defining a constant in order to enable
54
+ # logging before touching a domain class.
55
+ @cls_tbl_hash ||= {
56
+ CaTissue::Specimen => /catissue_[[:alpha:]]+_specimen/i,
57
+ CaTissue::SpecimenCollectionGroup => /catissue_specimen_coll_group/i
58
+ }
59
+ @cls_tbl_hash.detect_value { |klass, table| table if target <= klass }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,99 @@
1
+ require 'caruby/util/properties'
2
+ require 'caruby/csv/csv_mapper'
3
+ require 'caruby/csv/csvio'
4
+
5
+ module CaTissue
6
+ # Extracts caTissue objects.
7
+ class Extractor
8
+ include Enumerable
9
+
10
+ # The default name of this migrator.
11
+ DEF_NAME = 'caTissue Extractor'
12
+
13
+ # The extract output file
14
+ attr_reader :output
15
+
16
+ # Creates a new Extractor with the given options.
17
+ #
18
+ # @option options [String] :file the extract configuration file name
19
+ # @option options [String] :name name of this Migrator (default is +caTissue Migrator+)
20
+ # @option options [String] :output optional output CSV file name
21
+ # @option options [String] :target required target domain class or class name
22
+ # @option options [String] :ids the database identifiers of the target objects to extract
23
+ # @option options [String] :log log file (default +log/extract.log+)
24
+ def initialize(options={})
25
+ conf_file = options.delete(:file)
26
+ if conf_file then
27
+ CaRuby::Properties.new(conf_file, :array => [:shims]).each { |key, value| options[key.to_sym] ||= value }
28
+ end
29
+ # tailor the options
30
+ name = options[:name] || DEF_NAME
31
+ super(name)
32
+ @ids = options[:ids]
33
+ raise ArgumentError.new("Missing required ids option") unless @ids
34
+ # convert the required target to a CaTissue class if necessary
35
+ @target = target_class_from_option(options[:target])
36
+ @target ||= CaTissue::Specimen
37
+ # the CSV output file
38
+ @output = options[:output]
39
+ raise ArgumentError.new("Missing required extract output file option") unless @output
40
+ # the field mapping configuration
41
+ fld_conf = options[:mapping]
42
+ mapper = CaRuby::CsvMapper.new(fld_conf, @target, @output, :mode => "w")
43
+ @csvio = mapper.csvio
44
+ @fld_path_hash = {}
45
+ mapper.paths.each do |path|
46
+ fld = mapper.header(path)
47
+ # the path node is either an attribute symbol or attribute metadata;
48
+ # if metadata, then use the reader method.
49
+ @fld_path_hash[fld] = path.map { |attr_or_md| CaRuby::AttributeMetadata === attr_or_md ? attr_or_md.reader : attr_or_md }
50
+ end
51
+ logger.debug { "Extract field => path map: #{@fld_path_hash.transform { |path| path.join('.') }.pp_s}" }
52
+ end
53
+
54
+ # Exports the selected target records from the database to the output file.
55
+ def run
56
+ begin
57
+ extract { |obj| write(obj) }
58
+ ensure
59
+ @csvio.close
60
+ end
61
+ end
62
+
63
+ # Executes this extractor CSV file and calls the block given to this method on each target domain object.
64
+ def extract
65
+ logger.debug { "Found #{@ids.size} extract targets." }
66
+ CaTissue::Database.instance.open do
67
+ @ids.each do |identifier|
68
+ obj = @target.new(:identifier => identifier)
69
+ logger.debug { "Finding extract target #{obj}..." }
70
+ if obj.find then
71
+ logger.debug { "Extractor fetched #{obj}." }
72
+ yield obj
73
+ else
74
+ logger.debug { "Extract target #{obj} not found." }
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ alias :each :extract
81
+
82
+ private
83
+
84
+ def write(obj)
85
+ # collect the field values in order by resolving the path on obj
86
+ rec = @csvio.headers.map do |fld|
87
+ obj.path_value(@fld_path_hash[fld])
88
+ end
89
+ @csvio << rec
90
+ logger.debug { "Extractor wrote #{obj} to CSV output file." }
91
+ end
92
+
93
+ def target_class_from_option(option)
94
+ return if option.nil?
95
+ return option if Class === option
96
+ CaTissue.const_get(option)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,101 @@
1
+ require 'caruby/util/properties'
2
+ require 'caruby/migration/migrator'
3
+ require 'catissue/resource'
4
+ require 'catissue/database/controlled_values'
5
+ require 'catissue/database/controlled_value_finder'
6
+
7
+ module CaTissue
8
+ # Even though Migratable is included in CaRuby::Resource, the Migratable methods
9
+ # are not appended to a CaTissue Resource class since the class already includes
10
+ # CaRuby::Resource. In Ruby, A include B followed by B include C does not imply
11
+ # that A includes C. Therefore, notify CaTissue that its mixin has changed and each
12
+ # loaded class must reinclude the mixin.
13
+ CaTissue.mixin_changed
14
+
15
+ # Migrates a CSV extract to caTissue. See the {#initialize} documentation for usage options.
16
+ #
17
+ # See the Galena Cancer Center Tissue Bank Migration Example for further information
18
+ # about how the options tailor migration, esp. the use of the field mappings and shims.
19
+ class Migrator < CaRuby::Migrator
20
+ # The default name of this migrator.
21
+ NAME = 'caTissue Migrator'
22
+
23
+ DEF_CONF_FILE = File.join('conf', 'migration.yaml')
24
+
25
+ # The built-in caTissue migration shims.
26
+ SHIM_FILE = File.join(File.dirname(__FILE__), 'shims.rb')
27
+
28
+ # Creates a new Migrator with the given options.
29
+ #
30
+ # This migrator must include sufficient information to build a well-formed migration target object.
31
+ # For example, if the target object is a new SpecimenCollectionGroup, then the migration must also be
32
+ # able to build that SCG's CollectionProtocolRegistration. The CPR in turn must either exist in the
33
+ # database or the migration must build a Participant and a CollectionProtocol.
34
+ #
35
+ # @option (see CaRuby::Migrator#initialize)
36
+ def initialize(opts={})
37
+ # if there is a configuration file, then add config options into the parameter options
38
+ conf_file = opts.delete(:file)
39
+ if conf_file then
40
+ conf = CaRuby::Properties.new(conf_file, :array => [:shims])
41
+ # add config options but don't override the parameter options
42
+ opts.merge!(conf, :deep) { |key, oldval, newval| oldval }
43
+ end
44
+
45
+
46
+ # TODO - move opt parsing to CaTissue::CLI::Migrate and call that from test cases
47
+ # Migrate then calls this Migrator with parsed options
48
+
49
+
50
+ # open the log file before building structure
51
+ log_file = opts[:log]
52
+ CaRuby::Log.instance.open(log_file, :debug => opts[:debug]) if log_file
53
+
54
+ # tailor the options
55
+ opts[:name] ||= NAME
56
+ opts[:database] ||= CaTissue::Database.instance
57
+ # prepend this migrator's shims
58
+ shims = opts[:shims] ||= []
59
+ shims.unshift(SHIM_FILE)
60
+
61
+ # call the CaRuby::Migrator initializer with the augmented options
62
+ super
63
+
64
+ # the options specific to this CaTissue::Migrator subclass
65
+ tissue_sites = opts[:tissue_sites]
66
+ if tissue_sites then
67
+ CaTissue::SpecimenCharacteristics.tissue_site_cv_finder = ControlledValueFinder.new(:tissue_site, tissue_sites)
68
+ logger.info("Migrator enabled controlled value lookup.")
69
+ end
70
+ diagnoses = opts[:diagnoses]
71
+ if diagnoses then
72
+ CaTissue::SpecimenCollectionGroup.diagnosis_cv_finder = ControlledValueFinder.new(:clinical_diagnosis, diagnoses)
73
+ logger.info("Migrator enabled controlled value lookup.")
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # Clears the migration protocol CPR and SCG references.
80
+ # This action frees up memory for the next iteration, thereby ensuring that migration is an
81
+ # O(1) rather than O(n) operation.
82
+ def clear(target)
83
+ pcl = target_protocol(target) || return
84
+ logger.debug { "Clearing #{pcl.qp} CPR and SCG references..." }
85
+ pcl.suspend_lazy_loader do
86
+ pcl.registrations.clear
87
+ pcl.events.each { |event| event.suspend_lazy_loader { event.specimen_collection_groups.clear } }
88
+ end
89
+ end
90
+
91
+ def target_protocol(target)
92
+ case target
93
+ when CaTissue::SpecimenCollectionGroup then
94
+ cpe = target.collection_protocol_event
95
+ cpe.collection_protocol if cpe
96
+ when CaTissue::Specimen then
97
+ target_protocol(target.specimen_collection_group)
98
+ end
99
+ end
100
+ end
101
+ end