inferno_core 0.6.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ module Inferno
2
+ module DSL
3
+ class ValueExtractor
4
+ attr_accessor :ig_resources, :resource, :profile_elements
5
+
6
+ def initialize(ig_resources, resource, profile_elements)
7
+ self.ig_resources = ig_resources
8
+ self.resource = resource
9
+ self.profile_elements = profile_elements
10
+ end
11
+
12
+ def values_from_fixed_codes(profile_element, type)
13
+ return [] unless type == 'CodeableConcept'
14
+
15
+ elements = profile_elements.select do |element|
16
+ element.path == "#{profile_element.path}.coding.code" && element.fixedCode.present?
17
+ end
18
+
19
+ elements.map(&:fixedCode)
20
+ end
21
+
22
+ def values_from_pattern_coding(profile_element, type)
23
+ return [] unless type == 'CodeableConcept'
24
+
25
+ elements = profile_elements.select do |element|
26
+ element.path == "#{profile_element.path}.coding" && element.patternCoding.present?
27
+ end
28
+
29
+ elements.map { |element| element.patternCoding.code }
30
+ end
31
+
32
+ def values_from_pattern_codeable_concept(profile_element, type)
33
+ return [] unless type == 'CodeableConcept'
34
+
35
+ elements = profile_elements.select do |element|
36
+ element.path == profile_element.path && element.patternCodeableConcept.present? && element.min.positive?
37
+ end
38
+
39
+ elements.map { |element| element.patternCodeableConcept.coding.first.code }
40
+ end
41
+
42
+ def value_set_binding(the_element)
43
+ the_element&.binding
44
+ end
45
+
46
+ def value_set(the_element)
47
+ ig_resources.value_set_by_url(value_set_binding(the_element)&.valueSet)
48
+ end
49
+
50
+ def bound_systems(the_element)
51
+ bound_systems_from_valueset(value_set(the_element))
52
+ end
53
+
54
+ def bound_systems_from_valueset(value_set)
55
+ value_set&.compose&.include&.map do |include_element|
56
+ bound_systems_from_valueset_include_element(include_element)
57
+ end&.flatten&.compact
58
+ end
59
+
60
+ def bound_systems_from_valueset_include_element(include_element)
61
+ if include_element.concept.present?
62
+ include_element
63
+ elsif include_element.system.present? && include_element.filter&.empty?
64
+ # Cannot process intensional value set with filters
65
+ ig_resources.code_system_by_url(include_element.system)
66
+ elsif include_element.valueSet.present?
67
+ include_element.valueSet.map do |vs|
68
+ a_value_set = ig_resources.value_set_by_url(vs)
69
+ bound_systems_from_valueset(a_value_set)
70
+ end
71
+ end
72
+ end
73
+
74
+ def codes_from_value_set_binding(the_element)
75
+ codes_from_system_code_pair(codings_from_value_set_binding(the_element))
76
+ end
77
+
78
+ def codes_from_system_code_pair(codings)
79
+ codings.present? ? codings.map { |coding| coding[:code] }.compact.uniq : []
80
+ end
81
+
82
+ def codings_from_value_set_binding(the_element)
83
+ return [] if the_element.nil?
84
+
85
+ bound_systems = bound_systems(the_element)
86
+
87
+ return codings_from_bound_systems(bound_systems) if bound_systems.present?
88
+
89
+ expansion_contains = value_set_expansion_contains(the_element)
90
+
91
+ return [] if expansion_contains.blank?
92
+
93
+ expansion_contains.map { |contains| { system: contains.system, code: contains.code } }.compact.uniq
94
+ end
95
+
96
+ def codings_from_bound_systems(bound_systems)
97
+ return [] unless bound_systems.present?
98
+
99
+ bound_systems.flat_map do |bound_system|
100
+ case bound_system
101
+ when FHIR::ValueSet::Compose::Include
102
+ bound_system.concept.map { |concept| { system: bound_system.system, code: concept.code } }
103
+ when FHIR::CodeSystem
104
+ bound_system.concept.map { |concept| { system: bound_system.url, code: concept.code } }
105
+ else
106
+ []
107
+ end
108
+ end.uniq
109
+ end
110
+
111
+ def value_set_expansion_contains(element)
112
+ value_set(element)&.expansion&.contains
113
+ end
114
+
115
+ def fhir_metadata(current_path)
116
+ FHIR.const_get(resource)::METADATA[current_path]
117
+ end
118
+
119
+ def values_from_resource_metadata(paths)
120
+ values = []
121
+
122
+ paths.each do |current_path|
123
+ current_metadata = fhir_metadata(current_path)
124
+
125
+ next unless current_metadata&.dig('valid_codes').present?
126
+
127
+ values += current_metadata['valid_codes'].flat_map do |system, codes|
128
+ codes.map { |code| { system:, code: } }
129
+ end
130
+ end
131
+
132
+ values
133
+ end
134
+ end
135
+ end
136
+ end
@@ -14,10 +14,7 @@ module Inferno
14
14
  class IG < Entity
15
15
  ATTRIBUTES = [
16
16
  :id,
17
- :profiles,
18
- :extensions,
19
- :value_sets,
20
- :search_params,
17
+ :resources_by_type,
21
18
  :examples
22
19
  ].freeze
23
20
 
@@ -25,12 +22,8 @@ module Inferno
25
22
 
26
23
  def initialize(**params)
27
24
  super(params, ATTRIBUTES)
28
-
29
- @profiles = []
30
- @extensions = []
31
- @value_sets = []
25
+ @resources_by_type ||= Hash.new { |hash, key| hash[key] = [] }
32
26
  @examples = []
33
- @search_params = []
34
27
  end
35
28
 
36
29
  def self.from_file(ig_path)
@@ -71,6 +64,9 @@ module Inferno
71
64
  next
72
65
  end
73
66
  end
67
+
68
+ ig.id = extract_package_id(ig.ig_resource)
69
+
74
70
  ig
75
71
  end
76
72
 
@@ -91,6 +87,9 @@ module Inferno
91
87
  next
92
88
  end
93
89
  end
90
+
91
+ ig.id = extract_package_id(ig.ig_resource)
92
+
94
93
  ig
95
94
  end
96
95
 
@@ -113,28 +112,51 @@ module Inferno
113
112
  end
114
113
 
115
114
  def handle_resource(resource, relative_path)
116
- case resource.resourceType
117
- when 'StructureDefinition'
118
- if resource.type == 'Extension'
119
- extensions.push resource
120
- else
121
- profiles.push resource
122
- end
123
- when 'ValueSet'
124
- value_sets.push resource
125
- when 'SearchParameter'
126
- search_params.push resource
127
- when 'ImplementationGuide'
128
- @id = extract_package_id(resource)
115
+ if relative_path.start_with? 'package/example'
116
+ examples << resource
129
117
  else
130
- examples.push(resource) if relative_path.start_with? 'package/example'
118
+ resources_by_type[resource.resourceType] << resource
131
119
  end
132
120
  end
133
121
 
134
- def extract_package_id(ig_resource)
122
+ def self.extract_package_id(ig_resource)
135
123
  "#{ig_resource.id}##{ig_resource.version || 'current'}"
136
124
  end
137
125
 
126
+ def profiles
127
+ resources_by_type['StructureDefinition'].filter { |sd| sd.type != 'Extension' }
128
+ end
129
+
130
+ def extensions
131
+ resources_by_type['StructureDefinition'].filter { |sd| sd.type == 'Extension' }
132
+ end
133
+
134
+ def capability_statement(mode = 'server')
135
+ resources_by_type['CapabilityStatement'].find do |capability_statement_resource|
136
+ capability_statement_resource.rest.any? { |r| r.mode == mode }
137
+ end
138
+ end
139
+
140
+ def ig_resource
141
+ resources_by_type['ImplementationGuide'].first
142
+ end
143
+
144
+ def profile_by_url(url)
145
+ profiles.find { |profile| profile.url == url }
146
+ end
147
+
148
+ def resource_for_profile(url)
149
+ profiles.find { |profile| profile.url == url }.type
150
+ end
151
+
152
+ def value_set_by_url(url)
153
+ resources_by_type['ValueSet'].find { |profile| profile.url == url }
154
+ end
155
+
156
+ def code_system_by_url(url)
157
+ resources_by_type['CodeSystem'].find { |system| system.url == url }
158
+ end
159
+
138
160
  # @private
139
161
  def add_self_to_repository
140
162
  repository.insert(self)