us_core_test_kit 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed2e43ac18efc613d5e8e4deaa2e27c90b3d14956676be3009cfcaf023316bfc
4
- data.tar.gz: 602336f9a94c5ba3c89d0a6295543e9fccace4fd1ed96f8e296aca2c83bb4a2c
3
+ metadata.gz: 423a133232c347722fccf2898b4ad15c164310066ee3490b21f597fbc71f9687
4
+ data.tar.gz: d6976a899786dd91a28e63671f4e94bb8062e743be466b72db5c1fc037cee661
5
5
  SHA512:
6
- metadata.gz: 6664094195116bde7e6483e0e6baf23f93e3515607502b74c94b18608e675925002a506ba29e31c8252b6ea583a499fb922f9b7352b604ce4569522cd8fbbfa8
7
- data.tar.gz: 9f52ccb0ac909060103b5e568f480f71ae40ba4d07affbcdd7bf175532e1b359be3152b87edd538d3bc8be7bdb2f8ae580629474e6c3f4293e1cccf09bc37a60
6
+ metadata.gz: fff0f5644ac84c70e2a6782d245437c62d82115e6b6c22772c2290b641ea60c3cfd293cf41a642419de436168f03f691b351d348b5bdd61818eceb9f6c01aba2
7
+ data.tar.gz: e47893ae3a7207fbc0e85bd958a1d8ffc94d516206971af365f1a962f338155c40d538be86c89732bb519101d2d31e724887c05bffff98346049d3fb56f1a584
@@ -1,5 +1,7 @@
1
1
  module USCoreTestKit
2
2
  module FHIRResourceNavigation
3
+ DAR_EXTENSION_URL = 'http://hl7.org/fhir/StructureDefinition/data-absent-reason'.freeze
4
+
3
5
  def resolve_path(elements, path)
4
6
  elements = Array.wrap(elements)
5
7
  return elements if path.blank?
@@ -14,12 +16,18 @@ module USCoreTestKit
14
16
  end.compact
15
17
  end
16
18
 
17
- def find_a_value_at(element, path)
19
+ def find_a_value_at(element, path, include_dar: false)
18
20
  return nil if element.nil?
19
21
 
20
22
  elements = Array.wrap(element)
21
23
 
22
24
  if path.empty?
25
+ unless include_dar
26
+ elements = elements.reject do |el|
27
+ el.respond_to?(:extension) && el.extension.any? { |ext| ext.url == DAR_EXTENSION_URL}
28
+ end
29
+ end
30
+
23
31
  return elements.find { |el| yield(el) } if block_given?
24
32
 
25
33
  return elements.first
@@ -43,9 +51,9 @@ module USCoreTestKit
43
51
  child = get_next_value(element, segment)
44
52
  element_found =
45
53
  if block_given?
46
- find_a_value_at(child, remaining_path) { |value_found| yield(value_found) }
54
+ find_a_value_at(child, remaining_path, include_dar: include_dar) { |value_found| yield(value_found) }
47
55
  else
48
- find_a_value_at(child, remaining_path)
56
+ find_a_value_at(child, remaining_path, include_dar: include_dar)
49
57
  end
50
58
 
51
59
  return element_found if element_found.present? || element_found == false
@@ -20,8 +20,7 @@ module USCoreTestKit
20
20
  * Device.serialNumber
21
21
  * Device.type
22
22
  * Device.udiCarrier
23
- * Device.udiCarrier.carrierAIDC
24
- * Device.udiCarrier.carrierHRF
23
+ * Device.udiCarrier.carrierAIDC or Device.udiCarrier.carrierHRF
25
24
  * Device.udiCarrier.deviceIdentifier
26
25
  )
27
26
 
@@ -17,8 +17,7 @@ module USCoreTestKit
17
17
  * DocumentReference.content
18
18
  * DocumentReference.content.attachment
19
19
  * DocumentReference.content.attachment.contentType
20
- * DocumentReference.content.attachment.data
21
- * DocumentReference.content.attachment.url
20
+ * DocumentReference.content.attachment.data or DocumentReference.content.attachment.url
22
21
  * DocumentReference.content.format
23
22
  * DocumentReference.context
24
23
  * DocumentReference.context.encounter
@@ -17,8 +17,7 @@ module USCoreTestKit
17
17
  * DocumentReference.content
18
18
  * DocumentReference.content.attachment
19
19
  * DocumentReference.content.attachment.contentType
20
- * DocumentReference.content.attachment.data
21
- * DocumentReference.content.attachment.url
20
+ * DocumentReference.content.attachment.data or DocumentReference.content.attachment.url
22
21
  * DocumentReference.content.format
23
22
  * DocumentReference.context
24
23
  * DocumentReference.context.encounter
@@ -19,15 +19,13 @@ module USCoreTestKit
19
19
  * Encounter.identifier.system
20
20
  * Encounter.identifier.value
21
21
  * Encounter.location
22
- * Encounter.location.location
22
+ * Encounter.location.location or Encounter.serviceProvider
23
23
  * Encounter.participant
24
24
  * Encounter.participant.individual
25
25
  * Encounter.participant.period
26
26
  * Encounter.participant.type
27
27
  * Encounter.period
28
- * Encounter.reasonCode
29
- * Encounter.reasonReference
30
- * Encounter.serviceProvider
28
+ * Encounter.reasonCode or Encounter.reasonReference
31
29
  * Encounter.status
32
30
  * Encounter.subject
33
31
  * Encounter.type
@@ -19,8 +19,7 @@ module USCoreTestKit
19
19
  * MedicationRequest.encounter
20
20
  * MedicationRequest.intent
21
21
  * MedicationRequest.medication[x]
22
- * MedicationRequest.reportedBoolean
23
- * MedicationRequest.reportedReference
22
+ * MedicationRequest.reportedBoolean or MedicationRequest.reportedReference
24
23
  * MedicationRequest.requester
25
24
  * MedicationRequest.status
26
25
  * MedicationRequest.subject
@@ -12119,10 +12119,13 @@
12119
12119
  :extensions:
12120
12120
  - :id: Patient.extension:race
12121
12121
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-race
12122
+ :uscdi_only: true
12122
12123
  - :id: Patient.extension:ethnicity
12123
12124
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity
12125
+ :uscdi_only: true
12124
12126
  - :id: Patient.extension:birthsex
12125
12127
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex
12128
+ :uscdi_only: true
12126
12129
  :slices: []
12127
12130
  :elements:
12128
12131
  - :path: identifier
@@ -12132,8 +12135,11 @@
12132
12135
  - :path: name.family
12133
12136
  - :path: name.given
12134
12137
  - :path: telecom.system
12138
+ :uscdi_only: true
12135
12139
  - :path: telecom.value
12140
+ :uscdi_only: true
12136
12141
  - :path: telecom.use
12142
+ :uscdi_only: true
12137
12143
  - :path: gender
12138
12144
  - :path: birthDate
12139
12145
  - :path: address
@@ -12143,10 +12149,23 @@
12143
12149
  - :path: address.postalCode
12144
12150
  - :path: address.period
12145
12151
  - :path: communication.language
12146
- - :path: telecom
12152
+ :uscdi_only: true
12147
12153
  - :path: name.suffix
12154
+ :uscdi_only: true
12148
12155
  - :path: name.use
12149
12156
  :fixed_value: old
12157
+ :uscdi_only: true
12158
+ - :path: name.period.end
12159
+ :uscdi_only: true
12160
+ - :path: telecom
12161
+ :uscdi_only: true
12162
+ - :path: communication
12163
+ :uscdi_only: true
12164
+ :choices:
12165
+ - :paths:
12166
+ - name.period.end
12167
+ - name.use
12168
+ :uscdi_only: true
12150
12169
  :mandatory_elements:
12151
12170
  - Patient.identifier
12152
12171
  - Patient.identifier.system
@@ -13976,7 +13995,6 @@
13976
13995
  - Reference
13977
13996
  :target_profiles:
13978
13997
  - http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner
13979
- - http://hl7.org/fhir/us/core/StructureDefinition/us-core-organization
13980
13998
  - :path: agent.onBehalfOf
13981
13999
  :types:
13982
14000
  - Reference
@@ -151,10 +151,13 @@
151
151
  :extensions:
152
152
  - :id: Patient.extension:race
153
153
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-race
154
+ :uscdi_only: true
154
155
  - :id: Patient.extension:ethnicity
155
156
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity
157
+ :uscdi_only: true
156
158
  - :id: Patient.extension:birthsex
157
159
  :url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex
160
+ :uscdi_only: true
158
161
  :slices: []
159
162
  :elements:
160
163
  - :path: identifier
@@ -164,8 +167,11 @@
164
167
  - :path: name.family
165
168
  - :path: name.given
166
169
  - :path: telecom.system
170
+ :uscdi_only: true
167
171
  - :path: telecom.value
172
+ :uscdi_only: true
168
173
  - :path: telecom.use
174
+ :uscdi_only: true
169
175
  - :path: gender
170
176
  - :path: birthDate
171
177
  - :path: address
@@ -175,10 +181,23 @@
175
181
  - :path: address.postalCode
176
182
  - :path: address.period
177
183
  - :path: communication.language
178
- - :path: telecom
184
+ :uscdi_only: true
179
185
  - :path: name.suffix
186
+ :uscdi_only: true
180
187
  - :path: name.use
181
188
  :fixed_value: old
189
+ :uscdi_only: true
190
+ - :path: name.period.end
191
+ :uscdi_only: true
192
+ - :path: telecom
193
+ :uscdi_only: true
194
+ - :path: communication
195
+ :uscdi_only: true
196
+ :choices:
197
+ - :paths:
198
+ - name.period.end
199
+ - name.use
200
+ :uscdi_only: true
182
201
  :mandatory_elements:
183
202
  - Patient.identifier
184
203
  - Patient.identifier.system
@@ -19,10 +19,6 @@ module USCoreTestKit
19
19
  * Patient.address.postalCode
20
20
  * Patient.address.state
21
21
  * Patient.birthDate
22
- * Patient.communication.language
23
- * Patient.extension:birthsex
24
- * Patient.extension:ethnicity
25
- * Patient.extension:race
26
22
  * Patient.gender
27
23
  * Patient.identifier
28
24
  * Patient.identifier.system
@@ -30,8 +26,16 @@ module USCoreTestKit
30
26
  * Patient.name
31
27
  * Patient.name.family
32
28
  * Patient.name.given
29
+
30
+ For ONC USCDI requirements, each Patient must support the following additional elements:
31
+
32
+ * Patient.communication
33
+ * Patient.communication.language
34
+ * Patient.extension:birthsex
35
+ * Patient.extension:ethnicity
36
+ * Patient.extension:race
37
+ * Patient.name.period.end or Patient.name.use
33
38
  * Patient.name.suffix
34
- * Patient.name.use
35
39
  * Patient.telecom
36
40
  * Patient.telecom.system
37
41
  * Patient.telecom.use
@@ -64,7 +64,6 @@
64
64
  - Reference
65
65
  :target_profiles:
66
66
  - http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner
67
- - http://hl7.org/fhir/us/core/StructureDefinition/us-core-organization
68
67
  - :path: agent.onBehalfOf
69
68
  :types:
70
69
  - Reference
@@ -277,7 +277,6 @@ module USCoreTestKit
277
277
  when '4.0.0'
278
278
  add_device_distinct_identifier
279
279
  add_patient_uscdi_elements
280
- add_provenance_agent_who
281
280
  end
282
281
  end
283
282
 
@@ -344,18 +343,23 @@ module USCoreTestKit
344
343
  def add_must_support_choices
345
344
  choices = []
346
345
 
347
- choices << {paths: ['content.attachment.data', 'content.attachment.url']} if profile.type == 'DocumentReference'
346
+ choices << { paths: ['content.attachment.data', 'content.attachment.url'] } if profile.type == 'DocumentReference'
348
347
 
349
348
  case profile.version
350
349
  when '3.1.1'
351
- choices << {paths: ['udiCarrier.carrierAIDC', 'udiCarrier.carrierHRF']} if profile.type == 'Device'
350
+ choices << { paths: ['udiCarrier.carrierAIDC', 'udiCarrier.carrierHRF'] } if profile.type == 'Device'
352
351
  when '4.0.0'
353
352
  case profile.type
354
353
  when 'Encounter'
355
- choices << {paths: ['reasonCode', 'reasonReference']}
356
- choices << {paths: ['location.location', 'serviceProvider']}
354
+ choices << { paths: ['reasonCode', 'reasonReference'] }
355
+ choices << { paths: ['location.location', 'serviceProvider'] }
357
356
  when 'MedicationRequest'
358
- choices << {paths: ['reportedBoolean', 'reportedReference']}
357
+ choices << { paths: ['reportedBoolean', 'reportedReference'] }
358
+ when 'Patient'
359
+ choices << {
360
+ paths: ['name.period.end', 'name.use'],
361
+ uscdi_only: true
362
+ }
359
363
  end
360
364
  end
361
365
 
@@ -377,35 +381,44 @@ module USCoreTestKit
377
381
  #US Core 4.0.0 Section 10.112.1.1 Additional USCDI v1 Requirement:
378
382
  @must_supports[:extensions] << {
379
383
  id: 'Patient.extension:race',
380
- url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race'
384
+ url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race',
385
+ uscdi_only: true
381
386
  }
382
387
  @must_supports[:extensions] << {
383
388
  id: 'Patient.extension:ethnicity',
384
- url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity'
389
+ url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity',
390
+ uscdi_only: true
385
391
  }
386
392
  @must_supports[:extensions] << {
387
393
  id: 'Patient.extension:birthsex',
388
- url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex'
394
+ url: 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex',
395
+ uscdi_only: true
389
396
  }
390
397
  @must_supports[:elements] << {
391
- path: 'telecom'
398
+ path: 'name.suffix',
399
+ uscdi_only: true
392
400
  }
393
401
  @must_supports[:elements] << {
394
- path: 'name.suffix'
402
+ path: 'name.use',
403
+ fixed_value: 'old',
404
+ uscdi_only: true
395
405
  }
396
406
  @must_supports[:elements] << {
397
- path: 'name.use',
398
- fixed_value: 'old'
407
+ path: 'name.period.end',
408
+ uscdi_only: true
399
409
  }
400
- end
401
- end
402
-
403
- def add_provenance_agent_who
404
- # FHIR-36344 US Core 4.0.0 mistakenly not lable us-core-organization as MS for Provenance.agent.who
405
- # This will be fixed in US Core 5.0.0
406
- if profile.type == 'Provenance'
407
- target_element = @must_supports[:elements].find { |element| element[:path] == 'agent.who'}
408
- target_element[:target_profiles] << 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-organization'
410
+ @must_supports[:elements] << {
411
+ path: 'telecom',
412
+ uscdi_only: true
413
+ }
414
+ @must_supports[:elements] << {
415
+ path: 'communication',
416
+ uscdi_only: true
417
+ }
418
+ @must_supports[:elements].each do |element|
419
+ path = element[:path]
420
+ element[:uscdi_only] = true if path.include?('telecom.') || path.include?('communication.')
421
+ end
409
422
  end
410
423
  end
411
424
  end
@@ -68,9 +68,32 @@ module USCoreTestKit
68
68
  end
69
69
 
70
70
  def must_support_list_string
71
- slice_names = group_metadata.must_supports[:slices].map { |slice| slice[:name] }
72
- element_names = group_metadata.must_supports[:elements].map { |slice| "#{resource_type}.#{slice[:path]}" }
73
- extension_names = group_metadata.must_supports[:extensions].map { |slice| slice[:id] }
71
+ build_must_support_list_string(false)
72
+ end
73
+
74
+ def uscdi_list_string
75
+ build_must_support_list_string(true)
76
+ end
77
+
78
+ def build_must_support_list_string(uscdi_only)
79
+ slice_names = group_metadata.must_supports[:slices]
80
+ .select { |slice| slice[:uscdi_only].presence == uscdi_only.presence }
81
+ .map { |slice| slice[:name] }
82
+
83
+ element_names = group_metadata.must_supports[:elements]
84
+ .select { |element| element[:uscdi_only].presence == uscdi_only.presence }
85
+ .map { |element| "#{resource_type}.#{element[:path]}" }
86
+
87
+ extension_names = group_metadata.must_supports[:extensions]
88
+ .select { |extension| extension[:uscdi_only].presence == uscdi_only.presence }
89
+ .map { |extension| extension[:id] }
90
+
91
+ group_metadata.must_supports[:choices]&.each do |choice|
92
+ next unless choice[:uscdi_only].presence == uscdi_only.presence
93
+ choice[:paths].each { |path| element_names.delete("#{resource_type}.#{path}") }
94
+ element_names << choice[:paths].map { |path| "#{resource_type}.#{path}" }.join(' or ')
95
+ end
96
+
74
97
  (slice_names + element_names + extension_names)
75
98
  .uniq
76
99
  .sort
@@ -36,8 +36,16 @@ module USCoreTestKit
36
36
  end
37
37
  end
38
38
 
39
+ def include_uscdi_only_test?
40
+ config.options[:include_uscdi_only_test] == true
41
+ end
42
+
39
43
  def must_support_extensions
40
- metadata.must_supports[:extensions]
44
+ if include_uscdi_only_test?
45
+ metadata.must_supports[:extensions]
46
+ else
47
+ metadata.must_supports[:extensions].reject{ |extension| extension[:uscdi_only] }
48
+ end
41
49
  end
42
50
 
43
51
  def missing_extensions(resources = [])
@@ -50,7 +58,11 @@ module USCoreTestKit
50
58
  end
51
59
 
52
60
  def must_support_elements
53
- metadata.must_supports[:elements]
61
+ if include_uscdi_only_test?
62
+ metadata.must_supports[:elements]
63
+ else
64
+ metadata.must_supports[:elements].reject{ |element| element[:uscdi_only] }
65
+ end
54
66
  end
55
67
 
56
68
  def missing_elements(resources = [])
@@ -85,7 +97,11 @@ module USCoreTestKit
85
97
  end
86
98
 
87
99
  def must_support_slices
88
- metadata.must_supports[:slices]
100
+ if include_uscdi_only_test?
101
+ metadata.must_supports[:slices]
102
+ else
103
+ metadata.must_supports[:slices].reject{ |slice| slice[:uscdi_only] }
104
+ end
89
105
  end
90
106
 
91
107
  def missing_slices(resources = [])
@@ -31,7 +31,7 @@ module USCoreTestKit
31
31
  if fixed_value_search?
32
32
  fixed_value_search_param_values.map { |value| fixed_value_search_params(value, patient_id) }
33
33
  else
34
- [search_params_with_values(patient_id)]
34
+ [search_params_with_values(search_param_names, patient_id)]
35
35
  end
36
36
  new_params.reject! do |params|
37
37
  params.any? { |_key, value| value.blank? }
@@ -135,6 +135,9 @@ module USCoreTestKit
135
135
  check_search_response
136
136
 
137
137
  post_search_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
138
+
139
+ filter_devices(post_search_resources) if resource_type == 'Device'
140
+
138
141
  get_resource_count = get_search_resources.length
139
142
  post_resource_count = post_search_resources.length
140
143
 
@@ -240,10 +243,11 @@ module USCoreTestKit
240
243
  new_search_params = params.merge('patient' => "Patient/#{params['patient']}")
241
244
  search_and_check_response(new_search_params)
242
245
 
243
- new_resource_count =
244
- fetch_all_bundled_resources
245
- .select { |resource| resource.resourceType == resource_type }
246
- .count
246
+ reference_with_type_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
247
+
248
+ filter_devices(reference_with_type_resources) if resource_type == 'Device'
249
+
250
+ new_resource_count = reference_with_type_resources.count
247
251
 
248
252
  assert new_resource_count == resource_count,
249
253
  "Expected search by `#{params['patient']}` to to return the same results as searching " \
@@ -256,9 +260,7 @@ module USCoreTestKit
256
260
  def perform_search_with_system(params, patient_id)
257
261
  return if search_variant_test_records[:token_variants]
258
262
 
259
- new_search_params = token_search_params.each_with_object({}) do |name, search_params|
260
- search_params[name] = search_param_value(name, patient_id, include_system: true)
261
- end
263
+ new_search_params = search_params_with_values(token_search_params, patient_id, include_system: true)
262
264
  return if new_search_params.any? { |_name, value| value.blank? }
263
265
 
264
266
  search_params = params.merge(new_search_params)
@@ -308,7 +310,7 @@ module USCoreTestKit
308
310
  definition = metadata.search_definitions[param_name]
309
311
  return [] if definition.blank?
310
312
 
311
- definition[:multiple_or] == 'SHALL' ? [definition[:values].join(',')] : [definition[:values]]
313
+ definition[:multiple_or] == 'SHALL' ? [definition[:values].join(',')] : Array.wrap(definition[:values])
312
314
  end
313
315
 
314
316
 
@@ -317,7 +319,7 @@ module USCoreTestKit
317
319
 
318
320
  all_search_params.each do |patient_id, params_list|
319
321
  next unless params_list.present?
320
-
322
+
321
323
  search_params = params_list.first
322
324
  existing_values = {}
323
325
  missing_values = {}
@@ -423,11 +425,29 @@ module USCoreTestKit
423
425
  end
424
426
  end
425
427
 
426
- def search_params_with_values(patient_id)
427
- search_param_names.each_with_object({}) do |name, params|
428
- value = patient_id_param?(name) ? patient_id : search_param_value(name, patient_id)
429
- params[name] = value
428
+ def search_params_with_values(search_param_names, patient_id, include_system: false)
429
+ resources = scratch_resources_for_patient(patient_id)
430
+
431
+ if resources.empty?
432
+ return search_param_names.each_with_object({}) do |name, params|
433
+ value = patient_id_param?(name) ? patient_id : nil
434
+ params[name] = value
435
+ end
430
436
  end
437
+
438
+ params_with_partial_value = resources.each_with_object({}) do |resource, outer_params|
439
+ results_from_one_resource = search_param_names.each_with_object({}) do |name, params|
440
+ value = patient_id_param?(name) ? patient_id : search_param_value(name, resource, include_system: include_system)
441
+ params[name] = value
442
+ end
443
+
444
+ outer_params.merge!(results_from_one_resource)
445
+
446
+ # stop if all parameter values are found
447
+ return outer_params if outer_params.all? { |_key, value| value.present? }
448
+ end
449
+
450
+ params_with_partial_value
431
451
  end
432
452
 
433
453
  def patient_id_list
@@ -446,10 +466,10 @@ module USCoreTestKit
446
466
 
447
467
  def search_param_paths(name)
448
468
  paths = metadata.search_definitions[name.to_sym][:paths]
449
- if paths.first =='class'
469
+ if paths.first =='class'
450
470
  paths[0] = 'local_class'
451
471
  end
452
-
472
+
453
473
  paths
454
474
  end
455
475
 
@@ -470,8 +490,13 @@ module USCoreTestKit
470
490
  end
471
491
 
472
492
  def no_resources_skip_message(resource_type = self.resource_type)
473
- "No #{resource_type} resources appear to be available. " \
474
- "Please use patients with more information"
493
+ msg = "No #{resource_type} resources appear to be available"
494
+
495
+ if (resource_type == 'Device' && implantable_device_codes.present?)
496
+ msg.concat(" with the following Device Type Code filter: #{implantable_device_codes}")
497
+ end
498
+
499
+ msg + ". Please use patients with more information"
475
500
  end
476
501
 
477
502
  def fetch_all_bundled_resources(
@@ -504,15 +529,6 @@ module USCoreTestKit
504
529
  page_count += 1
505
530
  end
506
531
 
507
- valid_resource_types = [resource_type, 'OperationOutcome'].concat(additional_resource_types)
508
- valid_resource_types << 'Medication' if resource_type == 'MedicationRequest'
509
-
510
- all_valid_resource_types =
511
- resources.all? { |entry| valid_resource_types.include? entry.resourceType }
512
-
513
- assert all_valid_resource_types,
514
- "All resources returned must be of the type: #{valid_resource_types.join(', ')}"
515
-
516
532
  resources
517
533
  end
518
534
 
@@ -520,11 +536,11 @@ module USCoreTestKit
520
536
  "Could not resolve next bundle: #{link}"
521
537
  end
522
538
 
523
- def search_param_value(name, patient_id, include_system: false)
539
+ def search_param_value(name, resource, include_system: false)
524
540
  paths = search_param_paths(name)
525
541
  search_value = nil
526
542
  paths.each do |path|
527
- element = find_a_value_at(scratch_resources_for_patient(patient_id), path)
543
+ element = find_a_value_at(resource, path) { |element| element_has_valid_value?(element, include_system) }
528
544
 
529
545
  search_value =
530
546
  case element
@@ -541,34 +557,37 @@ module USCoreTestKit
541
557
  if include_system
542
558
  coding =
543
559
  find_a_value_at(element, 'coding') { |coding| coding.code.present? && coding.system.present? }
544
- coding.present? ? "#{coding.system}|#{coding.code}" : nil
560
+ "#{coding.system}|#{coding.code}"
545
561
  else
546
562
  find_a_value_at(element, 'coding.code')
547
563
  end
548
564
  when FHIR::Identifier
549
- if include_system
550
- identifier = find_a_value_at(scratch_resources_for_patient(patient_id), path) do |identifier|
551
- identifier.value.present? && identifier.system.present?
552
- end
553
- identifier.present? ? "#{identifier.system}|#{identifier.value}" : nil
554
- else
555
- element.value
556
- end
565
+ include_system ? "#{element.system}|#{element.value}" : element.value
557
566
  when FHIR::Coding
558
- if include_system
559
- coding = find_a_value_at(scratch_resources_for_patient(patient_id), path) do |coding|
560
- coding.code.present? && coding.system.present?
561
- end
562
- coding.present? ? "#{coding.system}|#{coding.code}" : nil
563
- else
564
- element.code
565
- end
567
+ include_system ? "#{element.system}|#{element.code}" : element.code
566
568
  when FHIR::HumanName
567
569
  element.family || element.given&.first || element.text
568
570
  when FHIR::Address
569
571
  element.text || element.city || element.state || element.postalCode || element.country
570
572
  else
571
- element
573
+ if metadata.version != 'v3.1.1' &&
574
+ metadata.search_definitions[name.to_sym][:type] == 'date' &&
575
+ params_with_comparators&.include?(name)
576
+ # convert date search to greath-than comparator search with correct precision
577
+ # For all date search parameters:
578
+ # Patient.birthDate does not mandate comparators so cannot be converted
579
+ # Goal.target-date has day precision
580
+ # All others have second + time offset precision
581
+ if /^\d{4}$/.match?(element) || # YYYY
582
+ /^\d{4}-\d{2}$/.match?(element) || # YYYY-MM
583
+ (/^\d{4}-\d{2}-\d{2}$/.match?(element) && resource_type != "Goal") # YYYY-MM-DD AND Resource is NOT Goal
584
+ "gt#{(DateTime.xmlschema(element)-1).xmlschema}"
585
+ else
586
+ element
587
+ end
588
+ else
589
+ element
590
+ end
572
591
  end
573
592
 
574
593
  break if search_value.present?
@@ -578,6 +597,31 @@ module USCoreTestKit
578
597
  escaped_value
579
598
  end
580
599
 
600
+ def element_has_valid_value?(element, include_system)
601
+ case element
602
+ when FHIR::Reference
603
+ element.reference.present?
604
+ when FHIR::CodeableConcept
605
+ if include_system
606
+ coding =
607
+ find_a_value_at(element, 'coding') { |coding| coding.code.present? && coding.system.present? }
608
+ coding.present?
609
+ else
610
+ find_a_value_at(element, 'coding.code').present?
611
+ end
612
+ when FHIR::Identifier
613
+ include_system ? element.value.present? && element.system.present? : element.value.present?
614
+ when FHIR::Coding
615
+ include_system ? element.code.present? && element.system.present? : element.code.present?
616
+ when FHIR::HumanName
617
+ (element.family || element.given&.first || element.text).present?
618
+ when FHIR::Address
619
+ (element.text || element.city || element.state || element.postalCode || element.country).present?
620
+ else
621
+ true
622
+ end
623
+ end
624
+
581
625
  def save_resource_reference(resource_type, reference)
582
626
  scratch[:references] ||= {}
583
627
  scratch[:references][resource_type] ||= Set.new
@@ -647,9 +691,9 @@ module USCoreTestKit
647
691
  address&.country&.downcase&.start_with?(search_value_downcase)
648
692
  end
649
693
  when 'CodeableConcept'
650
- # FHIR token search (https://www.hl7.org/fhir/search.html#token): "When in doubt, servers SHOULD
651
- # treat tokens in a case-insensitive manner, on the grounds that including undesired data has
652
- # less safety implications than excluding desired behavior".
694
+ # FHIR token search (https://www.hl7.org/fhir/search.html#token): "When in doubt, servers SHOULD
695
+ # treat tokens in a case-insensitive manner, on the grounds that including undesired data has
696
+ # less safety implications than excluding desired behavior".
653
697
  codings = values_found.flat_map(&:coding)
654
698
  if search_value.include? '|'
655
699
  system = search_value.split('|').first
@@ -691,7 +735,7 @@ module USCoreTestKit
691
735
  values_found.any? { |value_found| search_values.include? value_found }
692
736
  end
693
737
  end
694
-
738
+
695
739
  break if match_found
696
740
  end
697
741
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module USCoreTestKit
2
- VERSION = '0.2.2'
4
+ VERSION = '0.2.3'
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: us_core_test_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen MacVicar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-09 00:00:00.000000000 Z
11
+ date: 2022-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inferno_core