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.
Files changed (255) hide show
  1. data/Gemfile +17 -0
  2. data/History.md +5 -1
  3. data/README.md +2 -2
  4. data/bin/crtdump +2 -8
  5. data/bin/crtexample +2 -5
  6. data/bin/crtmigrate +3 -6
  7. data/bin/crtsmoke +3 -8
  8. data/conf/wustl/{log4j.properties → linux/log4j.properties} +3 -3
  9. data/conf/wustl/windows/log4j.properties +40 -0
  10. data/examples/galena/Gemfile +16 -0
  11. data/examples/galena/Gemfile.lock +88 -0
  12. data/examples/galena/README.md +16 -16
  13. data/examples/galena/Rakefile +30 -0
  14. data/examples/galena/bin/seed +5 -11
  15. data/examples/galena/conf/annotation/defaults.yaml +2 -0
  16. data/examples/galena/conf/{migration/annotation_fields.yaml → annotation/fields.yaml} +2 -4
  17. data/examples/galena/conf/defaults.yaml +9 -0
  18. data/examples/galena/conf/{migration/filter_fields.yaml → filter/fields.yaml} +0 -1
  19. data/examples/galena/conf/filter/values.yaml +8 -0
  20. data/examples/galena/conf/{migration/frozen_defaults.yaml → frozen/defaults.yaml} +0 -0
  21. data/examples/galena/conf/{migration/frozen_fields.yaml → frozen/fields.yaml} +0 -2
  22. data/examples/galena/conf/{migration/general_fields.yaml → general/fields.yaml} +0 -24
  23. data/examples/galena/conf/registration/fields.yaml +6 -0
  24. data/examples/galena/conf/{migration/simple_fields.yaml → simple/fields.yaml} +1 -6
  25. data/examples/galena/data/annotation.csv +1 -1
  26. data/examples/galena/data/filter.csv +1 -1
  27. data/examples/galena/data/frozen.csv +1 -1
  28. data/examples/galena/data/general.csv +1 -1
  29. data/examples/galena/data/registration.csv +1 -1
  30. data/examples/galena/data/simple.csv +1 -1
  31. data/examples/galena/galena.gemspec +24 -0
  32. data/examples/galena/lib/galena/filter.rb +25 -0
  33. data/examples/galena/lib/galena/{tissue/migration/frozen_shims.rb → frozen.rb} +6 -10
  34. data/examples/galena/lib/galena/seed.rb +126 -0
  35. data/examples/galena/lib/galena/version.rb +3 -0
  36. data/examples/galena/lib/galena.rb +18 -7
  37. data/examples/galena/log/galena.log +37351 -0
  38. data/examples/galena/log/galena.log.0 +147830 -0
  39. data/examples/galena/spec/annotation_spec.rb +46 -0
  40. data/examples/galena/spec/filter_spec.rb +94 -0
  41. data/examples/galena/spec/frozen_spec.rb +39 -0
  42. data/examples/galena/spec/general_spec.rb +62 -0
  43. data/examples/galena/spec/registration_spec.rb +37 -0
  44. data/examples/galena/spec/seed.rb +107 -0
  45. data/examples/galena/spec/simple_spec.rb +58 -0
  46. data/examples/galena/spec/spec_helper.rb +11 -0
  47. data/examples/galena/spec/support/migration.rb +70 -0
  48. data/lib/catissue/annotation/annotatable.rb +10 -8
  49. data/lib/catissue/annotation/annotation.rb +7 -7
  50. data/lib/catissue/annotation/de_integration.rb +9 -20
  51. data/lib/catissue/annotation/importer.rb +148 -0
  52. data/lib/catissue/annotation/introspector.rb +32 -0
  53. data/lib/catissue/annotation/metadata.rb +422 -0
  54. data/lib/catissue/annotation/proxy.rb +2 -2
  55. data/lib/catissue/annotation/proxy_class.rb +45 -30
  56. data/lib/catissue/annotation/record_entry_proxy.rb +2 -2
  57. data/lib/catissue/cli/command.rb +14 -24
  58. data/lib/catissue/cli/example.rb +5 -3
  59. data/lib/catissue/cli/migrate.rb +45 -37
  60. data/lib/catissue/cli/smoke.rb +2 -3
  61. data/lib/catissue/database/annotation/annotation_service.rb +8 -17
  62. data/lib/catissue/database/annotation/entity_facade.rb +33 -30
  63. data/lib/catissue/database/annotation/id_generator.rb +1 -1
  64. data/lib/catissue/database/annotation/integration_service.rb +11 -4
  65. data/lib/catissue/database/annotation/reference_writer.rb +38 -38
  66. data/lib/catissue/database/controlled_value_finder.rb +13 -28
  67. data/lib/catissue/database/controlled_values.rb +73 -45
  68. data/lib/catissue/database.rb +637 -277
  69. data/lib/catissue/domain/abstract_domain_object.rb +5 -0
  70. data/lib/catissue/domain/abstract_position.rb +3 -5
  71. data/lib/catissue/domain/abstract_specimen.rb +79 -65
  72. data/lib/catissue/domain/abstract_specimen_collection_group.rb +3 -6
  73. data/lib/catissue/domain/address.rb +0 -2
  74. data/lib/catissue/domain/cancer_research_group.rb +0 -3
  75. data/lib/catissue/domain/capacity.rb +2 -4
  76. data/lib/catissue/domain/check_in_check_out_event_parameter.rb +0 -3
  77. data/lib/catissue/domain/collection_event_parameters.rb +2 -7
  78. data/lib/catissue/domain/collection_protocol.rb +11 -16
  79. data/lib/catissue/domain/collection_protocol_event.rb +19 -12
  80. data/lib/catissue/domain/collection_protocol_registration.rb +8 -12
  81. data/lib/catissue/domain/consent_tier_response.rb +0 -4
  82. data/lib/catissue/domain/consent_tier_status.rb +1 -4
  83. data/lib/catissue/domain/container.rb +10 -10
  84. data/lib/catissue/domain/container_position.rb +4 -7
  85. data/lib/catissue/domain/container_type.rb +4 -7
  86. data/lib/catissue/domain/department.rb +0 -3
  87. data/lib/catissue/domain/disposal_event_parameters.rb +5 -5
  88. data/lib/catissue/domain/embedded_event_parameters.rb +1 -4
  89. data/lib/catissue/domain/external_identifier.rb +0 -12
  90. data/lib/catissue/domain/frozen_event_parameters.rb +1 -4
  91. data/lib/catissue/domain/institution.rb +0 -3
  92. data/lib/catissue/domain/new_specimen_array_order_item.rb +0 -5
  93. data/lib/catissue/domain/order_details.rb +0 -2
  94. data/lib/catissue/domain/participant/clinical/chemotherapy.rb +1 -3
  95. data/lib/catissue/domain/participant/clinical/duration.rb +2 -4
  96. data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +2 -4
  97. data/lib/catissue/domain/participant.rb +22 -24
  98. data/lib/catissue/domain/participant_medical_identifier.rb +0 -4
  99. data/lib/catissue/domain/password.rb +0 -4
  100. data/lib/catissue/domain/race.rb +0 -3
  101. data/lib/catissue/domain/received_event_parameters.rb +3 -6
  102. data/lib/catissue/domain/site.rb +1 -4
  103. data/lib/catissue/domain/specimen/pathology/additional_finding.rb +12 -0
  104. data/lib/catissue/domain/specimen/pathology/details.rb +12 -0
  105. data/lib/catissue/domain/specimen/pathology/gleason_score.rb +12 -0
  106. data/lib/catissue/domain/specimen/pathology/histologic_grade.rb +12 -0
  107. data/lib/catissue/domain/specimen/pathology/histologic_type.rb +19 -0
  108. data/lib/catissue/domain/specimen/pathology/histologic_variant_type.rb +12 -0
  109. data/lib/catissue/domain/specimen/pathology/invasion.rb +12 -0
  110. data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +5 -11
  111. data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +12 -12
  112. data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +5 -14
  113. data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +6 -21
  114. data/lib/catissue/domain/specimen/pathology/specimen_details.rb +4 -10
  115. data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +4 -10
  116. data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +6 -14
  117. data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +5 -11
  118. data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +5 -11
  119. data/lib/catissue/domain/specimen.rb +113 -76
  120. data/lib/catissue/domain/specimen_array.rb +0 -3
  121. data/lib/catissue/domain/specimen_array_content.rb +1 -4
  122. data/lib/catissue/domain/specimen_array_type.rb +1 -4
  123. data/lib/catissue/domain/specimen_characteristics.rb +0 -3
  124. data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +2 -4
  125. data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +2 -4
  126. data/lib/catissue/domain/specimen_collection_group.rb +43 -53
  127. data/lib/catissue/domain/specimen_event_parameters.rb +24 -32
  128. data/lib/catissue/domain/specimen_position.rb +8 -5
  129. data/lib/catissue/domain/specimen_protocol.rb +3 -6
  130. data/lib/catissue/domain/specimen_requirement.rb +22 -20
  131. data/lib/catissue/domain/storage_container.rb +9 -12
  132. data/lib/catissue/domain/storage_type.rb +6 -10
  133. data/lib/catissue/domain/transfer_event_parameters.rb +3 -6
  134. data/lib/catissue/domain/user.rb +22 -29
  135. data/lib/catissue/{util → helpers}/collectible.rb +23 -18
  136. data/lib/catissue/helpers/collectible_event_parameters.rb +68 -0
  137. data/lib/catissue/helpers/controlled_value.rb +35 -0
  138. data/lib/catissue/{domain → helpers}/hash_code.rb +0 -0
  139. data/lib/catissue/{util → helpers}/location.rb +6 -5
  140. data/lib/catissue/helpers/log.rb +4 -0
  141. data/lib/catissue/{util → helpers}/person.rb +1 -1
  142. data/lib/catissue/{util → helpers}/position.rb +10 -8
  143. data/lib/catissue/helpers/properties_loader.rb +143 -0
  144. data/lib/catissue/{util → helpers}/storable.rb +2 -1
  145. data/lib/catissue/{util → helpers}/storage_type_holder.rb +9 -3
  146. data/lib/catissue/{annotation/annotatable_class.rb → metadata.rb} +73 -95
  147. data/lib/catissue/migration/migratable.rb +93 -44
  148. data/lib/catissue/migration/migrator.rb +26 -42
  149. data/lib/catissue/migration/shims.rb +1 -1
  150. data/lib/catissue/migration/unique.rb +76 -0
  151. data/lib/catissue/resource.rb +16 -20
  152. data/lib/catissue/version.rb +1 -1
  153. data/lib/catissue/wustl/logger.rb +52 -32
  154. data/lib/catissue.rb +38 -20
  155. data/test/lib/catissue/database/controlled_values_test.rb +22 -27
  156. data/test/lib/catissue/database/database_test.rb +18 -0
  157. data/test/lib/catissue/domain/address_test.rb +9 -11
  158. data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +5 -16
  159. data/test/lib/catissue/domain/capacity_test.rb +2 -2
  160. data/test/lib/catissue/domain/collection_event_parameters_test.rb +16 -8
  161. data/test/lib/catissue/domain/collection_protocol_event_test.rb +1 -1
  162. data/test/lib/catissue/domain/collection_protocol_registration_test.rb +26 -16
  163. data/test/lib/catissue/domain/collection_protocol_test.rb +2 -2
  164. data/test/lib/catissue/domain/container_position_test.rb +7 -4
  165. data/test/lib/catissue/domain/department_test.rb +3 -3
  166. data/test/lib/catissue/domain/disposal_event_parameters_test.rb +1 -1
  167. data/test/lib/catissue/domain/external_identifier_test.rb +5 -1
  168. data/test/lib/catissue/domain/location_test.rb +4 -4
  169. data/test/lib/catissue/domain/participant_medical_identifier_test.rb +3 -3
  170. data/test/lib/catissue/domain/participant_test.rb +33 -20
  171. data/test/lib/catissue/domain/received_event_parameters_test.rb +19 -0
  172. data/test/lib/catissue/domain/site_test.rb +2 -2
  173. data/test/lib/catissue/domain/specimen_array_test.rb +3 -3
  174. data/test/lib/catissue/domain/specimen_array_type_test.rb +6 -6
  175. data/test/lib/catissue/domain/specimen_characteristics_test.rb +1 -1
  176. data/test/lib/catissue/domain/specimen_collection_group_test.rb +49 -13
  177. data/test/lib/catissue/domain/specimen_event_parameters_test.rb +4 -4
  178. data/test/lib/catissue/domain/specimen_position_test.rb +1 -1
  179. data/test/lib/catissue/domain/specimen_requirement_test.rb +2 -2
  180. data/test/lib/catissue/domain/specimen_test.rb +58 -24
  181. data/test/lib/catissue/domain/storage_container_test.rb +3 -16
  182. data/test/lib/catissue/domain/storage_type_test.rb +3 -3
  183. data/test/lib/catissue/domain/transfer_event_parameters_test.rb +17 -17
  184. data/test/lib/catissue/domain/user_test.rb +32 -34
  185. data/test/lib/catissue/helpers/properties_loader_test.rb +19 -0
  186. data/test/lib/catissue/migration/{test_case.rb → helpers/test_case.rb} +30 -20
  187. data/test/lib/examples/galena/tissue/domain/examples_test.rb +28 -38
  188. data/test/lib/examples/galena/tissue/helpers/test_case.rb +24 -0
  189. metadata +175 -99
  190. data/bin/crtextract +0 -47
  191. data/examples/galena/conf/extract/simple_fields.yaml +0 -4
  192. data/examples/galena/conf/migration/annotation_defaults.yaml +0 -2
  193. data/examples/galena/conf/migration/filter_defaults.yaml +0 -1
  194. data/examples/galena/conf/migration/filter_values.yaml +0 -13
  195. data/examples/galena/conf/migration/participant_fields.yaml +0 -4
  196. data/examples/galena/conf/migration/registration_fields.yaml +0 -5
  197. data/examples/galena/data/participant.csv +0 -1
  198. data/examples/galena/lib/galena/tissue/migration/filter_shims.rb +0 -41
  199. data/examples/galena/lib/galena/tissue/seed/defaults.rb +0 -127
  200. data/examples/psbin/README.md +0 -45
  201. data/examples/psbin/conf/adjuvant_hormone_defaults.yaml +0 -2
  202. data/examples/psbin/conf/adjuvant_radiation_defaults.yaml +0 -3
  203. data/examples/psbin/conf/biopsy_defaults.yaml +0 -3
  204. data/examples/psbin/conf/biopsy_fields.yaml +0 -9
  205. data/examples/psbin/conf/neoadjuvant_hormone_defaults.yaml +0 -2
  206. data/examples/psbin/conf/neoadjuvant_radiation_defaults.yaml +0 -3
  207. data/examples/psbin/conf/patient_defaults.yaml +0 -3
  208. data/examples/psbin/conf/patient_fields.yaml +0 -5
  209. data/examples/psbin/conf/surgery_defaults.yaml +0 -4
  210. data/examples/psbin/conf/surgery_fields.yaml +0 -15
  211. data/examples/psbin/conf/t_stage_defaults.yaml +0 -1
  212. data/examples/psbin/conf/t_stage_fields.yaml +0 -4
  213. data/examples/psbin/conf/therapy_fields.yaml +0 -5
  214. data/examples/psbin/data/adjuvant_hormone.csv +0 -1
  215. data/examples/psbin/data/adjuvant_radiation.csv +0 -1
  216. data/examples/psbin/data/biopsy.csv +0 -1
  217. data/examples/psbin/data/neoadjuvant_hormone.csv +0 -1
  218. data/examples/psbin/data/neoadjuvant_radiation.csv +0 -1
  219. data/examples/psbin/data/patient.csv +0 -1
  220. data/examples/psbin/data/surgery.csv +0 -1
  221. data/examples/psbin/data/t_stage.csv +0 -1
  222. data/examples/psbin/lib/psbin/biopsy_shims.rb +0 -15
  223. data/examples/psbin/lib/psbin/surgery_shims.rb +0 -15
  224. data/lib/catissue/annotation/annotation_class.rb +0 -406
  225. data/lib/catissue/annotation/annotation_module.rb +0 -106
  226. data/lib/catissue/domain.rb +0 -26
  227. data/lib/catissue/extract/command.rb +0 -31
  228. data/lib/catissue/extract/delta.rb +0 -58
  229. data/lib/catissue/extract/extractor.rb +0 -99
  230. data/lib/catissue/migration/uniquify.rb +0 -2
  231. data/lib/catissue/util/collectible_event_parameters.rb +0 -71
  232. data/lib/catissue/util/controlled_value.rb +0 -29
  233. data/lib/catissue/util/uniquify.rb +0 -86
  234. data/test/fixtures/catissue/domain/conf/catissue_override.yaml +0 -9
  235. data/test/fixtures/catissue/extract/conf/scg_extract.yaml +0 -3
  236. data/test/fixtures/catissue/extract/conf/scg_fields.yaml +0 -3
  237. data/test/fixtures/catissue/extract/conf/spc_extract.yaml +0 -3
  238. data/test/fixtures/catissue/extract/conf/spc_fields.yaml +0 -4
  239. data/test/fixtures/lib/catissue/defaults_test_fixture.rb +0 -206
  240. data/test/fixtures/lib/examples/galena/migration/alt_key_shims.rb +0 -7
  241. data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +0 -24
  242. data/test/lib/catissue/extract/delta_test.rb +0 -25
  243. data/test/lib/catissue/extract/extractor_test.rb +0 -43
  244. data/test/lib/catissue/import/importable_module_test.rb +0 -14
  245. data/test/lib/catissue/test_case.rb +0 -247
  246. data/test/lib/examples/galena/tissue/migration/annotation_test.rb +0 -29
  247. data/test/lib/examples/galena/tissue/migration/filter_test.rb +0 -29
  248. data/test/lib/examples/galena/tissue/migration/frozen_test.rb +0 -36
  249. data/test/lib/examples/galena/tissue/migration/general_test.rb +0 -56
  250. data/test/lib/examples/galena/tissue/migration/participant_test.rb +0 -61
  251. data/test/lib/examples/galena/tissue/migration/registration_test.rb +0 -17
  252. data/test/lib/examples/galena/tissue/migration/seedify.rb +0 -119
  253. data/test/lib/examples/galena/tissue/migration/simple_test.rb +0 -30
  254. data/test/lib/examples/galena/tissue/migration/test_case.rb +0 -72
  255. data/test/lib/examples/psbin/migration_test.rb +0 -153
@@ -4,12 +4,12 @@ module CaTissue
4
4
  module Proxy
5
5
  # @return [Annotatable] the annotated domain object
6
6
  def hook
7
- send(self.class.owner_attribute_metadata.reader)
7
+ send(self.class.owner_property.reader)
8
8
  end
9
9
 
10
10
  # @param [Annotatable] obj the domain object to annotate
11
11
  def hook=(obj)
12
- send(self.class.owner_attribute_metadata.writer, obj)
12
+ send(self.class.owner_property.writer, obj)
13
13
  end
14
14
 
15
15
  # Ensures that this proxy's hook exists in the database.
@@ -1,6 +1,7 @@
1
1
  require 'set'
2
- require 'caruby/util/collection'
3
- require 'caruby/util/partial_order'
2
+ require 'jinx/helpers/collections'
3
+
4
+ require 'jinx/helpers/partial_order'
4
5
  require 'catissue/annotation/annotation'
5
6
  require 'catissue/annotation/proxy_1_1'
6
7
  require 'catissue/annotation/record_entry_proxy'
@@ -9,6 +10,9 @@ module CaTissue
9
10
  module Annotation
10
11
  # Annotation hook proxy class mix-in.
11
12
  module ProxyClass
13
+ # @return [CaRuby::Property] the hook class attribute meta-data for this proxy
14
+ attr_reader :hook_property
15
+
12
16
  # @param [Class] klass the proxy class
13
17
  def self.extended(klass)
14
18
  super
@@ -17,55 +21,67 @@ module CaTissue
17
21
  klass.class_eval { include mixin }
18
22
  end
19
23
 
20
- # @return [AnnotatableClass] the hook class for this proxy
24
+ # @return [Metadata] the hook class for this proxy
21
25
  def hook
22
- owner_type
26
+ hook_property.type
23
27
  end
24
28
 
25
29
  # Sets this proxy's hook to the given class and creates the
26
30
  # proxy => hook attribute with the given hook => proxy inverse.
27
31
  #
28
- # @param [AnnotatableClass] klass the annotated domain object class
32
+ # @param [Metadata] klass the annotated domain object class
29
33
  def hook=(klass)
30
34
  # Make a new hook reference attribute.
31
- attr = klass.name.demodulize.underscore
32
- attr_accessor(attr)
35
+ pa = klass.name.demodulize.underscore
36
+ attr_accessor(pa)
33
37
  # The attribute type is the given hook class.
34
- add_attribute(attr, klass)
35
- logger.debug { "Added #{klass.qp} annotation proxy => hook attribute #{attr}." }
38
+ @hook_property = add_attribute(pa, klass)
39
+ logger.debug { "Added #{klass.qp} annotation proxy => hook attribute #{pa}." }
36
40
  end
37
41
 
38
42
  # Adds each proxy => annotation reference as a dependent attribute.
39
43
  # Recursively adds dependents of all referenced annotations.
44
+ #
45
+ # This method defines a proxy attribute in each primary annotation class
46
+ # for each {#non_proxy_annotation_classes} class hierarchy.
40
47
  def build_annotation_dependency_hierarchy
41
48
  logger.debug { "Building annotation dependency hierarchy..." }
42
49
  non_proxy_annotation_classes.each do |klass|
43
- klass.annotation_hierarchy.each do |anc|
44
- if anc.primary? and anc.proxy_attribute.nil? then
45
- anc.define_proxy_attribute(self)
46
- end
47
- end
48
- logger.info(klass.pp_s)
50
+ ensure_primary_references_proxy(klass)
49
51
  end
50
52
  set_inverses
51
53
  add_dependent_attributes
52
54
  add_dependent_attribute_closure
53
55
  end
54
56
 
57
+ # Ensures that the given primary class references this proxy.
58
+ #
59
+ # @param [Metadata] klass the primary annotation class to check
60
+ def ensure_primary_references_proxy(klass)
61
+ # Define the superclass proxy attributes, starting with the most general class.
62
+ klass.annotation_hierarchy.to_a.reverse_each do |anc|
63
+ if anc.primary? and anc.proxy_attribute.nil? then
64
+ anc.define_proxy_attribute(self)
65
+ end
66
+ end
67
+ end
68
+
55
69
  # Creates a reference attribute from this proxy to the given primary {Annotation} class.
56
70
  #
57
- # @param [Class] klass the annotation class
71
+ # @param [Class] klass the target annotation class
72
+ # @return [Symbol] the new annotation reference attribute
58
73
  def create_annotation_attribute(klass)
59
74
  # the new attribute symbol
60
- attr = klass.name.demodulize.underscore.pluralize.to_sym
61
- logger.debug { "Creating annotation proxy #{qp} attribute #{attr} to hold primary annotation #{klass.qp} instances..." }
75
+ pa = klass.name.demodulize.underscore.pluralize.to_sym
76
+ logger.debug { "Creating annotation proxy #{qp} attribute #{pa} to hold primary annotation #{klass.qp} instances..." }
62
77
  # Define the access methods: the reader creates a new set on demand to hold the annotations.
63
- attr_create_on_demand_accessor(attr) { Set.new }
78
+ attr_create_on_demand_accessor(pa) { Set.new }
64
79
  # add the annotation collection attribute
65
- add_attribute(attr, klass, :collection)
80
+ add_attribute(pa, klass, :collection)
66
81
  # The annotation is dependent.
67
- add_dependent_attribute(attr, :logical)
68
- attr
82
+ add_dependent_attribute(pa, :logical)
83
+ logger.debug { "Created annotation proxy #{qp} dependent attribute #{pa}." }
84
+ pa
69
85
  end
70
86
 
71
87
  private
@@ -79,18 +95,17 @@ module CaTissue
79
95
  # The inverse is the direct, unwrapped proxy reference named by the annotation module.
80
96
  inv = annotation_module.name.demodulize.underscore.to_sym
81
97
  # The attributes in class hierarchy general-to-specific order
82
- attr_mds = annotation_attributes.enum_metadata.partial_sort_by { |attr_md| attr_md.type }.reverse
83
- logger.debug { "Setting #{self} inverses for annotation attributes #{attr_mds.to_series}." }
84
- attr_mds.each do |attr_md|
85
- attr_md.type.define_proxy_attribute(self)
86
- set_attribute_inverse(attr_md.to_sym, inv)
98
+ props = annotation_attributes.properties.partial_sort_by { |prop| prop.type }.reverse
99
+ logger.debug { "Setting #{self} inverses for annotation attributes #{props.to_series}." }
100
+ props.each do |prop|
101
+ prop.type.define_proxy_attribute(self)
102
+ set_attribute_inverse(prop.to_sym, inv)
87
103
  end
88
104
  end
89
105
 
90
- # @return <AnnotationClass> the non-proxy annotation classes
106
+ # @return <Metadata> the non-proxy annotation classes
91
107
  def non_proxy_annotation_classes
92
- consts = annotation_module.constants.map { |s| annotation_module.const_get(s) }
93
- consts.select { |c| Class === c and c < Annotation and not c < Proxy }
108
+ annotation_module.annotation_classes.filter { |klass| not klass < Proxy }
94
109
  end
95
110
  end
96
111
  end
@@ -8,12 +8,12 @@ module CaTissue
8
8
 
9
9
  # @return [Annotatable] the annotated domain object
10
10
  def hook
11
- send(self.class.owner_attribute_metadata.reader)
11
+ send(self.class.owner_property.reader)
12
12
  end
13
13
 
14
14
  # @param [Annotatable] obj the domain object to annotate
15
15
  def hook=(obj)
16
- send(self.class.owner_attribute_metadata.writer, obj)
16
+ send(self.class.owner_property.writer, obj)
17
17
  end
18
18
  end
19
19
  end
@@ -1,30 +1,19 @@
1
- # the standard log file
2
- DEF_LOG_FILE = 'log/catissue.log' unless defined?(DEF_LOG_FILE)
3
-
4
- begin
5
- require 'catissue'
6
- rescue Exception => e
7
- logger.error("caTissue client load was unsuccessful - #{e}:\n#{e.backtrace.qp}")
8
- puts "caTissue client load was unsuccessful - #{e}."
9
- puts "See the log at #{CaRuby::Log.instance.file} for more information."
10
- exit 1
11
- end
12
-
13
- require 'caruby/cli/command'
14
- require 'catissue/version'
1
+ require 'jinx/cli/command'
2
+ require 'catissue'
3
+ # defined check below guards against bundle exec redundant version.rb load.
4
+ require 'catissue/version' unless CaTissue.const_defined?('VERSION')
5
+ require 'caruby/database'
15
6
 
16
7
  module CaTissue
17
8
  module CLI
18
- # Augments {CaRuby::CLI::Command} with caTissue-specific command line option handlers.
19
- class Command < CaRuby::CLI::Command
20
- #
9
+ # Augments +CaRuby::CLI::Command+ with caTissue-specific command line option handlers.
10
+ class Command < Jinx::CLI::Command
21
11
  # Built-in options include those specified in +CaRuby::CLI::Command.initialize+
22
12
  # as well as the following:
23
- # * --version : print the version of caRuby Tissue as well as the supported caTissue releases and exit
13
+ # * +--version+ : print the version of caRuby Tissue as well as the supported
14
+ # caTissue releases and exit
24
15
  #
25
- # @param [(<Symbol>, <String, Class>)] specs the arguments and options
26
- # described in +CaRuby::CLI::Command.initialize+
27
- # @see {CaRuby::CLI::Command#initialize}
16
+ # @param (see CaRuby::CLI::Command#initialize)
28
17
  def initialize(specs=[])
29
18
  specs << VERSION_OPT
30
19
  super
@@ -43,10 +32,11 @@ module CaTissue
43
32
  super
44
33
  if opts[:version] then
45
34
  puts "#{CaTissue::VERSION} for caTissue v#{CaTissue::CATISSUE_VERSIONS}"
46
- else
47
- CaRuby::ACCESS_OPTS.each do |opt, *spec|
35
+ exit 0
36
+ elseuniqurify
37
+ CaRuby::Database::ACCESS_OPTS.each do |opt, *spec|
48
38
  value = opts.delete(opt)
49
- CaTissue.access_properties[opt] = value if value
39
+ CaTissue.properties[opt] = value if value
50
40
  end
51
41
  end
52
42
  end
@@ -1,5 +1,6 @@
1
- require 'catissue/cli/command'
2
- require 'caruby/util/collection'
1
+ require File.dirname(__FILE__) + '/command'
2
+ require 'jinx/helpers/collections'
3
+
3
4
 
4
5
  module CaTissue
5
6
  module CLI
@@ -16,7 +17,8 @@ module CaTissue
16
17
 
17
18
  # Lists the examples.
18
19
  def list
19
- root = CaTissue.path('examples')
20
+ root = File.expand_path('examples', File.dirname(__FILE__) + '/../../..')
21
+ raise RuntimeError.new("Examples directory not found: #{root}") unless File.exists?(root)
20
22
  Dir.foreach(root) do |f|
21
23
  path = File.expand_path(f, root)
22
24
  if File.directory?(path) and f[0, 1] != '.' then
@@ -1,7 +1,4 @@
1
- # the default log file
2
- DEF_LOG_FILE = 'log/migration.log'
3
-
4
- require 'catissue/cli/command'
1
+ require File.dirname(__FILE__) + '/command'
5
2
  require 'catissue/migration/migrator'
6
3
 
7
4
  module CaTissue
@@ -9,52 +6,63 @@ module CaTissue
9
6
  class Migrate < Command
10
7
  # The migration option specifications.
11
8
  #
12
- # The :unique option ensures that the migrated objects do not conflict with existing or future
9
+ # The +:unique+ option ensures that the migrated objects do not conflict with existing or future
13
10
  # objects. This is used for testing a migration dry run. It is recommended that the trial run
14
11
  # protocol is set to a test protocol as well.
15
12
  SPECS = [
16
- [:input, "input", "Source file to migrate"],
17
- [:target, "-t", "--target CLASS", "Migration target class"],
18
- [:mapping, "-m", "--mapping FILE[,FILE...]", Array, "The input field => caTissue attribute mapping file(s)"],
19
- [:filters, "--filters FILE[,FILE...]", Array, "The input value => caTissue value mapping file(s)"],
20
- [:defaults, "-d", "--defaults FILE[,FILE...]", Array, "The caTissue attribute default value file(s)"],
21
- [:shims, "-s", "--shims FILE[,FILE...]", Array, "Migration customization shim file(s) to load"],
22
- [:bad, "-b", "--bad FILE", "Write each invalid record to the given file and continue migration"],
23
- [:unique, "-u", "--unique", "Make the migrated objects unique for testing"],
24
- [:offset, "-o", "--offset N", Integer, "Number of input records to skip before starting the migration"]
13
+ [:input, 'INPUT', 'Source file to migrate'],
14
+ [:target, '-t', '--target CLASS', 'Migration target class'],
15
+ [:mapping, '-m', '--mapping FILE[,FILE...]', Array, 'The input field => caTissue attribute mapping file(s)'],
16
+ [:filters, '--filters FILE[,FILE...]', Array, 'The input value => caTissue value mapping file(s)'],
17
+ [:defaults, '-d', '--defaults FILE[,FILE...]', Array, 'The caTissue attribute default value file(s)'],
18
+ [:shims, '-s', '--shims FILE[,FILE...]', Array, 'Migration customization shim file(s) to load'],
19
+ [:controlled_values, '-k', '--controlled_values', 'Enable controlled value lookup'],
20
+ [:bad, '-b', '--bad FILE', 'Write each invalid record to the given file and continue migration'],
21
+ [:extract, '-x', '--extract FILE', 'Call the migration target extract method to write to the given extract'],
22
+ [:create, '-c', '--create', 'Always create the migration target'],
23
+ [:unique, '-u', '--unique', 'Make the migrated objects unique for testing'],
24
+ [:from, '--from N', Integer, 'Starting input record'],
25
+ [:to, '--to N', Integer, 'Ending input record'],
25
26
  ]
26
-
27
- # Creates a {Migrate} command with the given standard command line specifications
28
- # as well as the {SPECS} command line specifications.
27
+
28
+ # Creates a {Migrate} command with the {SPECS} command line specifications
29
+ # as well as the optional specifications parameter.
29
30
  #
30
- # @yield [opts] optional migrator factory
31
- # @yieldparam [{Symbol => Object}] the {CaTissue::Migrator#initialize} creation options
32
- # @see CaRuby::Command#run
33
- def initialize(&factory)
34
- super(SPECS) { |opts| migrate(opts, &factory) }
31
+ # @param (see CaRuby::CLI::Command#initialize)
32
+ # @yield (see #migrate)
33
+ # @yieldparam (see #migrate)
34
+ def initialize(specs=[], &block)
35
+ super(specs.concat(SPECS)) { |opts| migrate(opts, &block) }
35
36
  end
36
37
 
37
38
  private
38
39
 
39
- # Starts a Migrator with the command-line options.
40
+ # Starts a Migrator with the command-line options. Each input record is migrated to
41
+ # the caTissue database.
40
42
  #
41
- # @yield [target] operation on the migration target
42
- # @yieldparam [CaRuby::Resource] the migrated domain object
43
- # @see CaRuby::Command#run
44
- def migrate(opts)
45
- validate(opts)
46
- migrator = block_given? ? yield(opts) : CaTissue::Migrator.new(opts)
47
- migrator.migrate_to_database
43
+ # @param opts (see CaTissue::Migrator#initialize)
44
+ # @yield (see CaTissue::Migrator#migrate_to_database)
45
+ # @yieldparam (see CaTissue::Migrator#migrate_to_database)
46
+ def migrate(opts, &block)
47
+ opts[:target] = resolve(opts[:target])
48
+ # Migrate the input.
49
+ CaTissue::Migrator.new(opts).migrate_to_database(&block)
48
50
  end
49
51
 
50
- def validate(opts)
51
- tgt = opts[:target]
52
- if tgt.nil? then raise ArgumentError.new("Missing required migration target class option") end
52
+ # Resolves the given target class name in the caTissue context.
53
+ #
54
+ # @param [String] name the target class name
55
+ # @return [Class] the resolved class
56
+ # @raise [NameError] if the class could not be resolved
57
+ def resolve(name)
58
+ return if name.nil?
53
59
  begin
54
- opts[:target] = CaTissue.const_get(tgt)
55
- rescue Exception
56
- logger.fatal("Could not load CaTissue class #{tgt} - #{$!}.\n#{$@.qp}")
57
- raise MigrationError.new("Could not load migration target class #{tgt}")
60
+ # Strip the CaTissue module prefix, if necessary.
61
+ cnm = name.sub(/^CaTissue::/, '')
62
+ # Resolve the class in the CaTissue context.
63
+ CaTissue.module_for_name(cnm)
64
+ rescue Exception => e
65
+ Jinx.fail(NameError, "Could not load migration target class #{name}", e)
58
66
  end
59
67
  end
60
68
  end
@@ -1,5 +1,4 @@
1
- require 'catissue/cli/command'
2
- require 'catissue/database'
1
+ require File.dirname(__FILE__) + '/command'
3
2
 
4
3
  module CaTissue
5
4
  module CLI
@@ -29,7 +28,7 @@ module CaTissue
29
28
  rescue Exception => e
30
29
  logger.error("caTissue database access was unsuccessful - #{e}:\n#{e.backtrace.qp}")
31
30
  puts "caTissue database access was unsuccessful - #{e}."
32
- puts "See the log at #{DEF_LOG_FILE} for more information."
31
+ puts "See the log for more information."
33
32
  end
34
33
 
35
34
  if site then
@@ -1,7 +1,6 @@
1
- require 'caruby/util/inflector'
1
+ require 'jinx/helpers/inflector'
2
2
  require 'caruby/database/sql_executor'
3
3
  require 'caruby/database/persistence_service'
4
- require 'catissue/annotation/annotatable'
5
4
 
6
5
  module CaTissue
7
6
  module Annotation
@@ -19,16 +18,14 @@ module CaTissue
19
18
  @intgtr = integrator
20
19
  end
21
20
 
22
- # Augments the {CaRuby::PersistenceService} create method to handle caTissue annotation
21
+ # Augments the +CaRuby::PersistenceService+ create method to handle caTissue annotation
23
22
  # service peculiarities, e.g.:
24
- # * assigns the identifier, since assignment is not done automatically as is the case with the
25
- # default application service
23
+ # * assigns the identifier, since assignment is not done automatically as is the case with
24
+ # the default application service
26
25
  # * associate the annotation to the hook object
27
26
  # * Save all referenced annotation objects
28
27
  #
29
- # This method can only be called on primary annotation objects. A _primary_ annotation
30
- # is a top-level annotation which has a reference to the {Annotation#hook} which is
31
- # being annotated.
28
+ # This method is only called on {Metadata#primary?} annotation objects.
32
29
  #
33
30
  # @param [Annotation] annotation the annotation object to create
34
31
  # @return [Annotation] the annotation
@@ -43,14 +40,8 @@ module CaTissue
43
40
 
44
41
  # @param [Annotation] (see #create)
45
42
  def create_annotation(annotation)
46
- # get the hook
47
- hook = annotation.hook
48
- # If no hook, then this is not a primary annotation. In that case, find a referenced
49
- # primary annotation.
50
- # If no hook, then this is not a primary annotation. In that case, find a referenced
51
- # primary annotation.
52
- if hook then
53
- create_primary_annotation(annotation, hook)
43
+ if annotation.class.primary? then
44
+ create_primary_annotation(annotation, annotation.hook)
54
45
  else
55
46
  create_nonprimary_annotation(annotation)
56
47
  end
@@ -101,4 +92,4 @@ module CaTissue
101
92
  end
102
93
  end
103
94
  end
104
- end
95
+ end
@@ -1,12 +1,14 @@
1
1
  require 'singleton'
2
- require 'caruby/import/java'
2
+ require 'jinx/import/java'
3
3
  require 'caruby/database/sql_executor'
4
4
  require 'catissue/database/annotation/id_generator'
5
5
 
6
6
  module CaTissue
7
7
  module Annotation
8
- # EntityFacade is the caRuby substitue for the broken caTissue EntityManager. EntityManager is
9
- # the caTissue singleton Winnebago object for doing lots of things with dynamic extensions.
8
+ # EntityFacade is the caRuby substitute for the broken caTissue EntityManager.
9
+ # EntityManager is the caTissue singleton Winnebago object for doing lots of
10
+ # things with dynamic extensions. The EntityManager defects are listed in the
11
+ # various Rubydoc quirks.
10
12
  class EntityFacade
11
13
  include Singleton
12
14
 
@@ -38,7 +40,7 @@ module CaTissue
38
40
  @idgen.next_identifier(table)
39
41
  end
40
42
 
41
- # @quirk caTissue unlike the hook entity id lookup, the annotation entity id lookup strips the leading
43
+ # @quirk caTissue Unlike the hook entity id lookup, the annotation entity id lookup strips the leading
42
44
  # package prefix from the annotation class name. caTissue DE API requires this undocumented inconsistency.
43
45
  #
44
46
  # @quirk caTissue call into caTissue to get entity id doesn't work. caRuby uses direct SQL instead.
@@ -56,23 +58,23 @@ module CaTissue
56
58
  # @param [Integer] eid the entity id to check
57
59
  # @return [Boolean] whether the entity is primary
58
60
  def primary?(eid)
59
- result = @executor.execute { |dbh| dbh.select_one(IS_PRIMARY_SQL, eid) }
61
+ result = @executor.query(IS_PRIMARY_SQL, eid).first
60
62
  not result.nil?
61
63
  end
62
64
 
63
65
  # @param [Class] klass the {Annotatable} class
64
66
  # @return [Integer] the class entity id
65
67
  def hook_entity_id(klass)
66
- result = @executor.execute { |dbh| dbh.select_one(HOOK_ENTITY_ID_SQL, klass.java_class.name) }
68
+ result = @executor.query(HOOK_ENTITY_ID_SQL, klass.java_class.name).first
67
69
  if result.nil? then raise AnnotationError.new("Entity id not found for static hook class #{klass.qp}") end
68
70
  eid = result[0].to_i
69
71
  logger.debug { "Static hook class #{klass.qp} has entity id #{eid}." }
70
72
  eid
71
73
  end
72
74
 
73
- # @quirk caTissue call into caTissue to get entity id doesn't work for non-primary object.
74
- # Furthermore, the SQL used for the #{#annotation_entity_id} doesn't work for associated annotation
75
- # classes. Use alternative SQL instead.
75
+ # @quirk caTissue The call into caTissue to get entity id doesn't work for a non-primary object.
76
+ # Furthermore, the SQL used for the #{#annotation_entity_id} doesn't work for associated
77
+ # annotation classes. Use the {ASSN_ENTITY_ID_SQL} alternative SQL instead.
76
78
  #
77
79
  # @param [Integer] eid the referencing entity id
78
80
  # @param [String] name the association property name
@@ -91,16 +93,16 @@ module CaTissue
91
93
 
92
94
  # @quirk caTissue Annotation classes are incorrectly mapped to entity ids, which in turn are
93
95
  # incorrectly mapped to a table name. A candidate work-around is to bypass the caTissue DE
94
- # mechanism and hit the DE Hibernate config files directly. However, the DE Hibernate mappings
95
- # are incorrect and possibly no longer used. Therefore, the table must be obtained by SQL
96
- # work-arounds.
96
+ # mechanism and hit the DE Hibernate config files directly. However, the 1.1.2 DE Hibernate
97
+ # mappings are incorrect and possibly no longer used. Therefore, the table must be obtained
98
+ # by SQL work-arounds.
97
99
  #
98
100
  # @param [Annotation] obj the annotation object
99
101
  # @return [String] the entity table name
100
102
  # @param [Integer] the annotation entity identifier
101
103
  # @return [String] the entity table name
102
104
  def annotation_table_for_entity_id(eid)
103
- result = @executor.execute { |dbh| dbh.select_one(TABLE_NAME_SQL, eid) }
105
+ result = @executor.query(TABLE_NAME_SQL, eid).first
104
106
  if result.nil? then raise AnnotationError.new("Table not found for annotation entity id #{eid}") end
105
107
  tbl = result[0]
106
108
  logger.debug { "Annotation entity with id #{eid} has table #{tbl}." }
@@ -110,14 +112,14 @@ module CaTissue
110
112
  # @param (see #associated_entity_id)
111
113
  # @return [Integer, nil] the parent entity id, if any
112
114
  def parent_entity_id(eid)
113
- result = @executor.execute { |dbh| dbh.select_one(PARENT_ENTITY_ID_SQL, eid) }
115
+ result = @executor.query(PARENT_ENTITY_ID_SQL, eid).first
114
116
  result[0].to_i if result and result[0]
115
117
  end
116
118
 
117
119
  # Obtains the undocumented caTisue container id for the given primary entity id.
118
120
  #
119
- # @quirk caTissue EntityManager.getContainerIdForEntitycontainer uses incorrect table
120
- # (cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=421&sid=5252d951301e598eebf3e90036da43cb).
121
+ # @quirk caTissue 1.1.2 EntityManager.getContainerIdForEntity uses an
122
+ # incorrect table (cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=421&sid=5252d951301e598eebf3e90036da43cb).
121
123
  # The standard DE API call submits the query:
122
124
  # SELECT IDENTIFIER FROM dyextn_container WHERE ENTITY_ID = ?
123
125
  # This results in the error:
@@ -126,14 +128,15 @@ module CaTissue
126
128
  # SELECT IDENTIFIER FROM dyextn_container WHERE ABSTRACT_ENTITY_ID = ?
127
129
  # The work-around is to call this SQL directly.
128
130
  #
129
- # @quirk caTissue in 1.2, there are deprecated primary annotations with an entity id but no container id.
131
+ # @quirk caTissue 1.2 There are deprecated primary annotations with an entity id
132
+ # but no container id.
130
133
  #
131
134
  # @return [Integer] eid the primary entity id
132
135
  def container_id(eid)
133
- # The following call is broken (see method doc).
136
+ # The following call is broken in caTissue 1.1.2 (see method doc).
134
137
  # EntityManager.instance.get_container_id_for_entity(eid)
135
- # Work-around caTissue bug with direct query.
136
- result = @executor.execute { |dbh| dbh.select_one(CTR_ID_SQL, eid) }
138
+ # Work-around this caTissue bug with a direct query.
139
+ result = @executor.query(CTR_ID_SQL, eid).first
137
140
  if result.nil? then
138
141
  logger.debug("Dynamic extension container id not found for annotation with entity id #{eid}")
139
142
  return
@@ -163,7 +166,7 @@ module CaTissue
163
166
  # The entity group and name.
164
167
  grp, name = split_annotation_entity_class_name(klass)
165
168
  # Dive into some obscure SQL.
166
- result = @executor.execute { |dbh| dbh.select_one(ANN_ENTITY_ID_SQL, grp, name) }
169
+ result = @executor.query(ANN_ENTITY_ID_SQL, grp, name).first
167
170
  result[0].to_i if result
168
171
  end
169
172
 
@@ -208,23 +211,23 @@ module CaTissue
208
211
  end
209
212
 
210
213
  # @param (see #recursive_associated_entity_id)
211
- # @return @return [Integer, nil] the directly associated entity id, if any
214
+ # @return [Integer, nil] the directly associated entity id, if any
212
215
  def nonrecursive_associated_entity_id(eid, role)
213
216
  logger.debug { "Finding entity id #{eid} #{role} associated entity id..." }
214
- result = @executor.execute { |dbh| dbh.select_one(ASSN_ENTITY_ID_SQL, eid, role) }
215
- # The role role can be a mutation of the property name with spaces inserted in the
216
- # camel-case components, e.g. 'Additional Finding' instead of 'AdditionalFinding'.
217
+ result = @executor.query(ASSN_ENTITY_ID_SQL, eid, role).first
218
+ # The role can be a mutation of the property name with spaces inserted in the
219
+ # mixed-case components, e.g. 'Additional Finding' instead of 'AdditionalFinding'.
217
220
  # TODO - fix this kludge by finding out how the role relates to the property in the
218
221
  # database.
219
222
  if result.nil? and role =~ /.+[A-Z]/ then
220
223
  alt = role.gsub(/(.)([A-Z])/, '\1 \2')
221
224
  logger.debug { "Attempting to find entity id #{eid} #{role} associated entity id using variant #{alt}..." }
222
- result = @executor.execute { |dbh| dbh.select_one(ASSN_ENTITY_ID_SQL, eid, alt) }
225
+ result = @executor.query(ASSN_ENTITY_ID_SQL, eid, alt).first
223
226
  end
224
227
  if result.nil? and role =~ /[pP]athologic[^a]/ then
225
228
  alt = role.sub(/([pP])athologic/, '\1athological')
226
229
  logger.debug { "Attempting to find entity id #{eid} #{role} associated entity id using variant #{alt}..." }
227
- result = @executor.execute { |dbh| dbh.select_one(ASSN_ENTITY_ID_SQL, eid, alt) }
230
+ result = @executor.query(ASSN_ENTITY_ID_SQL, eid, alt).first
228
231
  end
229
232
  if result.nil? then logger.debug { "Entity id #{eid} is not directly associated with #{role}." } end
230
233
  result[0].to_i if result
@@ -250,9 +253,9 @@ EOS
250
253
  # The SQL to find an entity id for an annotation reference.
251
254
  ASSN_ENTITY_ID_SQL = <<EOS
252
255
  select assn.TARGET_ENTITY_ID
253
- from DYEXTN_ATTRIBUTE attr, DYEXTN_ABSTRACT_ENTITY ae, DYEXTN_ASSOCIATION assn, DYEXTN_ROLE role
254
- where assn.IDENTIFIER = attr.IDENTIFIER
255
- and attr.ENTIY_ID = ae.id
256
+ from DYEXTN_ATTRIBUTE pa, DYEXTN_ABSTRACT_ENTITY ae, DYEXTN_ASSOCIATION assn, DYEXTN_ROLE role
257
+ where assn.IDENTIFIER = pa.IDENTIFIER
258
+ and pa.ENTIY_ID = ae.id
256
259
  and assn.TARGET_ROLE_ID = role.IDENTIFIER
257
260
  and ae.id = ?
258
261
  and role.name = ?