diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8eda4263..266855f8 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['2.6', '2.7'] + ruby-version: ['3.0', '3.1', '3.2'] steps: - uses: actions/checkout@v2 diff --git a/.rubocop.yml b/.rubocop.yml index ca6fa782..bb3d3428 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,7 @@ inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 2.4 + TargetRubyVersion: 3.0 Exclude: - '*.gemspec' - 'Gemfile*' @@ -10,9 +10,6 @@ AllCops: - 'lib/tasks/*' - 'vendor/**/*' -Documentation: - Enabled: false - Metrics: Enabled: false @@ -22,8 +19,5 @@ Style: Layout: Enabled: false -Performance/Casecmp: - Enabled: false - Naming: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 030b5c77..36f2c2a7 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,19 +1,7 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2019-03-22 01:56:17 -0400 using RuboCop version 0.52.1. +# on 2024-10-14 14:56:48 UTC using RuboCop version 1.23.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. - -# Offense count: 4 -# Cop supports --auto-correct. -Performance/RegexpMatch: - Exclude: - - 'lib/fhir_client/model/client_reply.rb' - -# Offense count: 197 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. -# URISchemes: http, https -Metrics/LineLength: - Max: 210 diff --git a/Gemfile b/Gemfile index 7949e731..32bd2f0b 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,6 @@ source 'https://rubygems.org' gemspec group :test do - gem 'rubocop', '~> 0.52.1', require: false + gem 'rubocop', '~> 1.23.0', require: false gem 'awesome_print', require: 'ap' end diff --git a/README.md b/README.md index e8db0a92..50c7faed 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Ruby FHIR client. Supports: -* FHIR R4, STU3 and DSTU2 +* FHIR R5, R4B, R4, STU3 and DSTU2 * JSON and XML * All CRUD, including version read and history * Transactions and Batches @@ -59,7 +59,7 @@ patient.destroy ## Advanced Usage ### Changing FHIR Versions -The client defaults to `R4` but can be switched to `DSTU2` or `STU3`. It can also attempt to autodetect the FHIR version based on the `metadata` endpoint. +The client defaults to `R4` but can be switched to other versions. It can also attempt to autodetect the FHIR version based on the `metadata` endpoint. ```ruby # autodetect the FHIR version @@ -71,6 +71,10 @@ elsif version == :dstu2 puts 'FHIR Client using DSTU2' elsif version == :r4 puts 'FHIR Client using R4' +elsif version == :r4b + puts 'FHIR Client using R4B' +elsif + puts 'FHIR Client using R5' end # tell the client to use R4 @@ -79,7 +83,7 @@ client.use_r4 patient = FHIR::Patient.read('example') patient = client.read(FHIR::Patient, 'example').resource -# tell the client to use STU3 (default) +# tell the client to use STU3 client.use_stu3 # now use the client normally patient = FHIR::STU3::Patient.read('example') diff --git a/fhir_client.gemspec b/fhir_client.gemspec index e36fb211..cdc05d33 100644 --- a/fhir_client.gemspec +++ b/fhir_client.gemspec @@ -21,9 +21,10 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 3.0.0' spec.add_dependency 'activesupport', '>= 3' spec.add_dependency 'addressable', '>= 2.3' - spec.add_dependency 'fhir_models', '>= 4.2.1' + spec.add_dependency 'fhir_models', '>= 5.0.0' spec.add_dependency 'fhir_stu3_models', '>= 3.1.1' spec.add_dependency 'fhir_dstu2_models', '>= 1.1.1' spec.add_dependency 'nokogiri', '>= 1.10.4' diff --git a/lib/fhir_client.rb b/lib/fhir_client.rb index 338e116b..db59c8c4 100644 --- a/lib/fhir_client.rb +++ b/lib/fhir_client.rb @@ -1,4 +1,6 @@ require 'fhir_models' +require 'fhir_models/r4b' +require 'fhir_models/r5' require 'fhir_dstu2_models' require 'fhir_stu3_models' require 'active_support/all' diff --git a/lib/fhir_client/client.rb b/lib/fhir_client/client.rb index cb61786e..034c5320 100644 --- a/lib/fhir_client/client.rb +++ b/lib/fhir_client/client.rb @@ -77,6 +77,16 @@ def use_r4 @default_format = versioned_format_class end + def use_r4b + @fhir_version = :r4b + @default_format = versioned_format_class + end + + def use_r5 + @fhir_version = :r5 + @default_format = versioned_format_class + end + # # Instructs the client to specify the minimal Prefer Header where applicable def use_minimal_preference @@ -95,6 +105,10 @@ def detect_version cap = capability_statement if cap.is_a?(FHIR::CapabilityStatement) use_r4 + elsif cap.is_a?(FHIR::R4B::CapabilityStatement) + use_r4b + elsif cap.is_a?(FHIR::R5::CapabilityStatement) + use_r5 elsif cap.is_a?(FHIR::STU3::CapabilityStatement) use_stu3 elsif cap.is_a?(FHIR::DSTU2::Conformance) @@ -275,20 +289,36 @@ def try_conformance_formats(default_format) rescue @cached_capability_statement = nil end - if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4') - use_stu3 + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4.0') + use_r4b begin - @cached_capability_statement = parse_reply(FHIR::STU3::CapabilityStatement, frmt, reply) + @cached_capability_statement = parse_reply(FHIR::R4B::CapabilityStatement, frmt, reply) rescue @cached_capability_statement = nil end - unless @cached_capability_statement - use_dstu2 + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4') + use_r5 begin - @cached_capability_statement = parse_reply(FHIR::DSTU2::Conformance, frmt, reply) + @cached_capability_statement = parse_reply(FHIR::R5::CapabilityStatement, frmt, reply) rescue @cached_capability_statement = nil end + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('5') + use_stu3 + begin + @cached_capability_statement = parse_reply(FHIR::STU3::CapabilityStatement, frmt, reply) + rescue + @cached_capability_statement = nil + end + unless @cached_capability_statement + use_dstu2 + begin + @cached_capability_statement = parse_reply(FHIR::DSTU2::Conformance, frmt, reply) + rescue + @cached_capability_statement = nil + end + end + end end end if @cached_capability_statement @@ -317,23 +347,35 @@ def parse_reply(klass, format, response) return nil unless [200, 201].include? response.code res = begin - if(@fhir_version == :dstu2 || klass&.ancestors&.include?(FHIR::DSTU2::Model)) + if(@fhir_version == :dstu2 || klass < FHIR::DSTU2::Model) if(format.include?('xml')) FHIR::DSTU2::Xml.from_xml(response.body) else FHIR::DSTU2::Json.from_json(response.body) end - elsif(@fhir_version == :r4 || klass&.ancestors&.include?(FHIR::Model)) + elsif(@fhir_version == :stu3 || klass < FHIR::STU3::Model) if(format.include?('xml')) - FHIR::Xml.from_xml(response.body) + FHIR::STU3::Xml.from_xml(response.body) else - FHIR::Json.from_json(response.body) + FHIR::STU3::Json.from_json(response.body) + end + elsif(@fhir_version == :r4b || klass < FHIR::R4B::Model) + if(format.include?('xml')) + FHIR::R4B::Xml.from_xml(response.body) + else + FHIR::R4B::Json.from_json(response.body) + end + elsif(@fhir_version == :r5 || klass < FHIR::R5::Model) + if(format.include?('xml')) + FHIR::R5::Xml.from_xml(response.body) + else + FHIR::R5::Json.from_json(response.body) end else if(format.include?('xml')) - FHIR::STU3::Xml.from_xml(response.body) + FHIR::Xml.from_xml(response.body) else - FHIR::STU3::Json.from_json(response.body) + FHIR::Json.from_json(response.body) end end rescue => e @@ -349,7 +391,7 @@ def set_client_on_resource(resource) resource.client = self resource.each_element do |element, _, _| - if element.is_a?(Reference) || element.is_a?(STU3::Reference) || element.is_a?(DSTU2::Reference) || element.respond_to?(:resourceType) + if element.is_a?(Reference) || element.is_a?(FHIR::R4B::Reference) || element.is_a?(FHIR::R5::Reference) || element.is_a?(STU3::Reference) || element.is_a?(DSTU2::Reference) || element.respond_to?(:resourceType) element.client = self end end diff --git a/lib/fhir_client/ext/bundle.rb b/lib/fhir_client/ext/bundle.rb index cacd7f8b..0c43e212 100644 --- a/lib/fhir_client/ext/bundle.rb +++ b/lib/fhir_client/ext/bundle.rb @@ -67,4 +67,20 @@ class Bundle include FHIR::BundleExtras end end +end + +module FHIR + module R4B + class Bundle < FHIR::R4B::Model + include FHIR::BundleExtras + end + end +end + +module FHIR + module R5 + class Bundle < FHIR::R5::Model + include FHIR::BundleExtras + end + end end \ No newline at end of file diff --git a/lib/fhir_client/ext/model.rb b/lib/fhir_client/ext/model.rb index 009b18dd..7d61fc8a 100644 --- a/lib/fhir_client/ext/model.rb +++ b/lib/fhir_client/ext/model.rb @@ -144,3 +144,19 @@ class Model end end end + +module FHIR + module R4B + class Model < FHIR::Model + include FHIR::ModelExtras + end + end +end + +module FHIR + module R5 + class Model < FHIR::Model + include FHIR::ModelExtras + end + end +end diff --git a/lib/fhir_client/ext/reference.rb b/lib/fhir_client/ext/reference.rb index 47878abf..344ea736 100644 --- a/lib/fhir_client/ext/reference.rb +++ b/lib/fhir_client/ext/reference.rb @@ -82,7 +82,7 @@ class Reference include FHIR::ReferenceExtras def resource_class - "FHIR::#{resource_type}".constantize unless contained? + FHIR.const_get(resource_type) unless contained? end end end @@ -93,7 +93,7 @@ class Reference include FHIR::ReferenceExtras def resource_class - "FHIR::DSTU2::#{resource_type}".constantize unless contained? + FHIR::DSTU2.const_get(resource_type) unless contained? end end end @@ -101,12 +101,36 @@ def resource_class module FHIR module STU3 - class Reference + class Reference + include FHIR::ReferenceExtras + + def resource_class + FHIR::STU3.const_get(resource_type) unless contained? + end + end + end +end + +module FHIR + module R4B + class Reference < FHIR::R4B::Model include FHIR::ReferenceExtras def resource_class - "FHIR::STU3::#{resource_type}".constantize unless contained? + FHIR::R4B.const_get(resource_type) unless contained? end end end end + +module FHIR + module R5 + class Reference < FHIR::R5::Model + include FHIR::ReferenceExtras + + def resource_class + FHIR::R5.const_get(resource_type) unless contained? + end + end + end +end \ No newline at end of file diff --git a/lib/fhir_client/version_management.rb b/lib/fhir_client/version_management.rb index bb584083..7a8c22ea 100644 --- a/lib/fhir_client/version_management.rb +++ b/lib/fhir_client/version_management.rb @@ -7,6 +7,10 @@ def versioned_resource_class(klass = nil) FHIR::STU3 when :dstu2 FHIR::DSTU2 + when :r4b + FHIR::R4B + when :r5 + FHIR::R5 else FHIR end diff --git a/test/fixtures/r4b_capabilitystatement.json b/test/fixtures/r4b_capabilitystatement.json new file mode 100644 index 00000000..408bf3d9 --- /dev/null +++ b/test/fixtures/r4b_capabilitystatement.json @@ -0,0 +1,148 @@ +{ + "resourceType" : "CapabilityStatement", + "id" : "example", + "text" : { + "status" : "generated", + "div" : "
\n\t\t\t

The EHR Server supports the following transactions for the resource Person: read, vread, \n update, history, search(name,gender), create and updates.

\n\t\t\t

The EHR System supports the following message: admin-notify::Person.

\n\t\t\t

The EHR Application has a \n general document profile.\n

\n\t\t
" + }, + "url" : "urn:uuid:68d043b5-9ecf-4559-a57a-396e0d452311", + "version" : "20130510", + "name" : "ACME-EHR", + "title" : "ACME EHR capability statement", + "status" : "draft", + "experimental" : true, + "date" : "2012-01-04", + "publisher" : "ACME Corporation", + "contact" : [{ + "name" : "System Administrator", + "telecom" : [{ + "system" : "email", + "value" : "wile@acme.org" + }] + }], + "description" : "This is the FHIR capability statement for the main EHR at ACME for the private interface - it does not describe the public interface", + "useContext" : [{ + "code" : { + "system" : "http://terminology.hl7.org/CodeSystem/usage-context-type", + "code" : "focus" + }, + "valueCodeableConcept" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/variant-state", + "code" : "positive" + }] + } + }], + "jurisdiction" : [{ + "coding" : [{ + "system" : "urn:iso:std:iso:3166", + "code" : "US", + "display" : "United States of America (the)" + }] + }], + "purpose" : "Main EHR capability statement, published for contracting and operational support", + "copyright" : "Copyright © Acme Healthcare and GoodCorp EHR Systems", + "kind" : "instance", + "instantiates" : ["http://ihe.org/fhir/CapabilityStatement/pixm-client"], + "software" : { + "name" : "EHR", + "version" : "0.00.020.2134", + "releaseDate" : "2012-01-04" + }, + "implementation" : { + "description" : "main EHR at ACME", + "url" : "http://10.2.3.4/fhir" + }, + "fhirVersion" : "4.3.0", + "format" : ["xml", + "json"], + "patchFormat" : ["application/xml-patch+xml", + "application/json-patch+json"], + "implementationGuide" : ["http://hl7.org/fhir/us/lab"], + "rest" : [{ + "mode" : "server", + "documentation" : "Main FHIR endpoint for acem health", + "security" : { + "cors" : true, + "service" : [{ + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/restful-security-service", + "code" : "SMART-on-FHIR" + }] + }], + "description" : "See Smart on FHIR documentation" + }, + "resource" : [{ + "type" : "Patient", + "profile" : "http://registry.fhir.org/r4/StructureDefinition/7896271d-57f6-4231-89dc-dcc91eab2416", + "supportedProfile" : ["http://registry.fhir.org/r4/StructureDefinition/00ab9e7a-06c7-4f77-9234-4154ca1e3347"], + "documentation" : "This server does not let the clients create identities.", + "interaction" : [{ + "code" : "read" + }, + { + "code" : "vread", + "documentation" : "Only supported for patient records since 12-Dec 2012" + }, + { + "code" : "update" + }, + { + "code" : "history-instance" + }, + { + "code" : "create" + }, + { + "code" : "history-type" + }], + "versioning" : "versioned-update", + "readHistory" : true, + "updateCreate" : false, + "conditionalCreate" : true, + "conditionalRead" : "full-support", + "conditionalUpdate" : false, + "conditionalDelete" : "not-supported", + "searchInclude" : ["Organization"], + "searchRevInclude" : ["Person"], + "searchParam" : [{ + "name" : "identifier", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-identifier", + "type" : "token", + "documentation" : "Only supports search by institution MRN" + }, + { + "name" : "general-practitioner", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-general-practitioner", + "type" : "reference" + }] + }], + "interaction" : [{ + "code" : "transaction" + }, + { + "code" : "history-system" + }], + "compartment" : ["http://hl7.org/fhir/CompartmentDefinition/patient"] + }], + "messaging" : [{ + "endpoint" : [{ + "protocol" : { + "system" : "http://terminology.hl7.org/CodeSystem/message-transport", + "code" : "mllp" + }, + "address" : "mllp:10.1.1.10:9234" + }], + "reliableCache" : 30, + "documentation" : "ADT A08 equivalent for external system notifications", + "supportedMessage" : [{ + "mode" : "receiver", + "definition" : "http://hl7.org/fhir/MessageDefinition/example" + }] + }], + "document" : [{ + "mode" : "consumer", + "documentation" : "Basic rules for all documents in the EHR system", + "profile" : "http://fhir.hl7.org/base/Profilebc054d23-75e1-4dc6-aca5-838b6b1ac81d/_history/b5fdd9fc-b021-4ea1-911a-721a60663796" + }] +} \ No newline at end of file diff --git a/test/fixtures/r5_capabilitystatement.json b/test/fixtures/r5_capabilitystatement.json new file mode 100644 index 00000000..79a207cb --- /dev/null +++ b/test/fixtures/r5_capabilitystatement.json @@ -0,0 +1,151 @@ +{ + "resourceType" : "CapabilityStatement", + "id" : "example", + "text" : { + "status" : "generated", + "div" : "
\n\t\t\t\n

The EHR Server supports the following transactions for the resource Person: read, vread, \n update, history, search(name,gender), create and updates.

\n\t\t\t\n

The EHR System supports the following message: admin-notify::Person.

\n\t\t\t\n

The EHR Application has a \n \n general document profile.\n \n

\n\t\t\n
" + }, + "url" : "urn:uuid:68d043b5-9ecf-4559-a57a-396e0d452311", + "version" : "20130510", + "name" : "ACMEEHR", + "title" : "ACME EHR capability statement", + "status" : "draft", + "experimental" : true, + "date" : "2012-01-04", + "publisher" : "ACME Corporation", + "contact" : [{ + "name" : "System Administrator", + "telecom" : [{ + "system" : "email", + "value" : "wile@acme.org" + }] + }], + "description" : "This is the FHIR capability statement for the main EHR at ACME for the private interface - it does not describe the public interface", + "useContext" : [{ + "code" : { + "system" : "http://terminology.hl7.org/CodeSystem/usage-context-type", + "code" : "focus" + }, + "valueCodeableConcept" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/variant-state", + "code" : "positive" + }] + } + }], + "jurisdiction" : [{ + "coding" : [{ + "system" : "urn:iso:std:iso:3166", + "code" : "US", + "display" : "United States of America (the)" + }] + }], + "purpose" : "Main EHR capability statement, published for contracting and operational support", + "copyright" : "Copyright © Acme Healthcare and GoodCorp EHR Systems", + "kind" : "instance", + "instantiates" : ["http://ihe.org/fhir/CapabilityStatement/pixm-client"], + "software" : { + "name" : "EHR", + "version" : "0.00.020.2134", + "releaseDate" : "2012-01-04" + }, + "implementation" : { + "description" : "main EHR at ACME", + "url" : "http://10.2.3.4/fhir" + }, + "fhirVersion" : "5.0.0", + "format" : ["xml", + "json"], + "patchFormat" : ["application/xml-patch+xml", + "application/json-patch+json"], + "acceptLanguage" : ["en", + "es"], + "implementationGuide" : ["http://example.org/fhir/us/lab"], + "rest" : [{ + "mode" : "server", + "documentation" : "Main FHIR endpoint for acem health", + "security" : { + "cors" : true, + "service" : [{ + "coding" : [{ + "system" : "http://hl7.org/fhir/restful-security-service", + "code" : "SMART-on-FHIR" + }] + }], + "description" : "See Smart on FHIR documentation" + }, + "resource" : [{ + "type" : "Patient", + "profile" : "http://registry.fhir.org/r5/StructureDefinition/7896271d-57f6-4231-89dc-dcc91eab2416", + "supportedProfile" : ["http://registry.fhir.org/r5/StructureDefinition/00ab9e7a-06c7-4f77-9234-4154ca1e3347"], + "documentation" : "This server does not let the clients create identities.", + "interaction" : [{ + "code" : "read" + }, + { + "code" : "vread", + "documentation" : "Only supported for patient records since 12-Dec 2012" + }, + { + "code" : "update" + }, + { + "code" : "history-instance" + }, + { + "code" : "create" + }, + { + "code" : "history-type" + }], + "versioning" : "versioned-update", + "readHistory" : true, + "updateCreate" : false, + "conditionalCreate" : true, + "conditionalRead" : "full-support", + "conditionalUpdate" : false, + "conditionalPatch" : false, + "conditionalDelete" : "not-supported", + "searchInclude" : ["Patient:organization"], + "searchRevInclude" : ["Person:patient"], + "searchParam" : [{ + "name" : "identifier", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-identifier", + "type" : "token", + "documentation" : "Only supports search by institution MRN" + }, + { + "name" : "general-practitioner", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-general-practitioner", + "type" : "reference" + }] + }], + "interaction" : [{ + "code" : "transaction" + }, + { + "code" : "history-system" + }], + "compartment" : ["http://hl7.org/fhir/CompartmentDefinition/patient"] + }], + "messaging" : [{ + "endpoint" : [{ + "protocol" : { + "system" : "http://hl7.org/fhir/message-transport", + "code" : "mllp" + }, + "address" : "mllp:10.1.1.10:9234" + }], + "reliableCache" : 30, + "documentation" : "ADT A08 equivalent for external system notifications", + "supportedMessage" : [{ + "mode" : "receiver", + "definition" : "http://hl7.org/fhir/MessageDefinition/example" + }] + }], + "document" : [{ + "mode" : "consumer", + "documentation" : "Basic rules for all documents in the EHR system", + "profile" : "http://fhir.hl7.org/base/Profilebc054d23-75e1-4dc6-aca5-838b6b1ac81d/_history/b5fdd9fc-b021-4ea1-911a-721a60663796" + }] +} \ No newline at end of file diff --git a/test/unit/client_interface_sections/read_test.rb b/test/unit/client_interface_sections/read_test.rb index 14219503..87d8ea1f 100644 --- a/test/unit/client_interface_sections/read_test.rb +++ b/test/unit/client_interface_sections/read_test.rb @@ -15,7 +15,7 @@ def test_read patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.read(FHIR::Patient,'foo') assert reply.resource.is_a?(FHIR::Patient) @@ -29,7 +29,7 @@ def test_vread patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test\/.*_history\/2/).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.vread(FHIR::Patient,'foo', 2) assert reply.resource.is_a?(FHIR::Patient) @@ -46,7 +46,7 @@ def test_conditional_read_since patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).with(headers: {'If-Modified-Since' => 'Wed, 21 Oct 2015 07:28:00 GMT'}).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.conditional_read_since(FHIR::Patient,'foo', 'Wed, 21 Oct 2015 07:28:00 GMT') assert reply.resource.is_a?(FHIR::Patient) @@ -59,7 +59,7 @@ def test_conditional_read_version patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).with(headers: {'If-None-Match' => 'W/ABC'}).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.conditional_read_version(FHIR::Patient,'foo','ABC') assert reply.resource.is_a?(FHIR::Patient) @@ -77,7 +77,7 @@ def test_raw_read 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json options = {resource: FHIR::Patient, id: 'foo'} reply = temp.raw_read(options) diff --git a/test/unit/multiversion_test.rb b/test/unit/multiversion_test.rb index b96d02d9..bba165c6 100644 --- a/test/unit/multiversion_test.rb +++ b/test/unit/multiversion_test.rb @@ -1,5 +1,4 @@ require_relative '../test_helper' - class MultiversionTest < Test::Unit::TestCase def test_autodetect_stu3 @@ -47,6 +46,36 @@ def test_autodetect_r4 assert client.default_format.include? 'json' end + def test_autodetect_r4b + root = File.expand_path '..', File.dirname(File.absolute_path(__FILE__)) + capabilitystatement = File.read(File.join(root, 'fixtures', 'r4b_capabilitystatement.json')) + stub_request(:get, /autodetect/).to_return(body: capabilitystatement) + client = FHIR::Client.new('autodetect') + # Intentionally set the client incorrectly + client.default_xml + client.use_r4 + assert client.cached_capability_statement.nil? + assert client.detect_version == :r4b, "Expected Version to be r4b, but found #{client.detect_version.to_s}" + assert !client.cached_capability_statement.nil?, 'Expected Capability Statement to be cached' + assert client.cached_capability_statement.is_a?(FHIR::R4B::CapabilityStatement) + assert client.default_format.include? 'json' + end + + def test_autodetect_r5 + root = File.expand_path '..', File.dirname(File.absolute_path(__FILE__)) + capabilitystatement = File.read(File.join(root, 'fixtures', 'r5_capabilitystatement.json')) + stub_request(:get, /autodetect/).to_return(body: capabilitystatement) + client = FHIR::Client.new('autodetect') + # Intentionally set the client incorrectly + client.default_xml + client.use_r4 + assert client.cached_capability_statement.nil? + assert client.detect_version == :r5, "Expected Version to be r5, but found #{client.detect_version.to_s}" + assert !client.cached_capability_statement.nil?, 'Expected Capability Statement to be cached' + assert client.cached_capability_statement.is_a?(FHIR::R5::CapabilityStatement) + assert client.default_format.include? 'json' + end + def test_stu3_patient_manual stub_request(:get, /stu3/).to_return(body: FHIR::STU3::Patient.new.to_json) client = FHIR::Client.new('stu3') @@ -65,6 +94,23 @@ def test_dstu2_patient_manual assert client.read(FHIR::DSTU2::Patient, 'foo').resource.is_a?(FHIR::DSTU2::Patient) end + def test_r4b_patient_manual + stub_request(:get, /r4b/).to_return(body: FHIR::R4B::Patient.new({ 'id': 'foo' }).to_json) + client = FHIR::Client.new('r4b') + client.default_json + client.use_r4b + assert_equal :r4b, client.fhir_version + assert client.read(FHIR::R4B::Patient, 'foo').resource.is_a?(FHIR::R4B::Patient) + end + + def test_r5_patient_manual + stub_request(:get, /r5/).to_return(body: FHIR::R5::Patient.new({ 'id': 'foo' }).to_json) + client = FHIR::Client.new('r5') + client.default_json + client.use_r5 + assert_equal :r5, client.fhir_version + assert client.read(FHIR::R5::Patient, 'foo').resource.is_a?(FHIR::R5::Patient) + end def test_r4_patient_manual stub_request(:get, /r4/).to_return(body: FHIR::Patient.new({ 'id': 'foo' }).to_json) @@ -132,6 +178,26 @@ def test_r4_reply_fhir_version assert_equal :r4, client.reply.fhir_version end + def test_r4b_reply_fhir_version + stub_request(:get, /r4b/).to_return(body: FHIR::R4B::Patient.new({ 'id': 'foo' }).to_json) + client = FHIR::Client.new('r4b') + client.default_json + client.use_r4b + FHIR::R4B::Model.client = client + patient = FHIR::R4B::Patient.read('foo') + assert_equal :r4b, client.reply.fhir_version + end + + def test_r5_reply_fhir_version + stub_request(:get, /r5/).to_return(body: FHIR::R5::Patient.new({ 'id': 'foo' }).to_json) + client = FHIR::Client.new('r5') + client.default_json + client.use_r5 + FHIR::R5::Model.client = client + patient = FHIR::R5::Patient.read('foo') + assert_equal :r5, client.reply.fhir_version + end + def test_stu3_accept_mime_type_json stub_request(:get, /stu3/).to_return(body: FHIR::STU3::Patient.new({'id': 'foo'}).to_json) client = FHIR::Client.new('stu3') diff --git a/test/unit/set_client_on_resource_test.rb b/test/unit/set_client_on_resource_test.rb index cd55aee5..8371bda5 100644 --- a/test/unit/set_client_on_resource_test.rb +++ b/test/unit/set_client_on_resource_test.rb @@ -18,6 +18,32 @@ def test_r4 assert_equal(client, condition.subject.client) end + def test_r4b + condition = FHIR::R4B::Condition.new( + resourceType: 'Condition', + subject: { + reference: 'Patient/123' + } + ) + client.set_client_on_resource(condition) + + assert_equal(client, condition.client) + assert_equal(client, condition.subject.client) + end + + def test_r5 + condition = FHIR::R5::Condition.new( + resourceType: 'Condition', + subject: { + reference: 'Patient/123' + } + ) + client.set_client_on_resource(condition) + + assert_equal(client, condition.client) + assert_equal(client, condition.subject.client) + end + def test_stu3 condition = FHIR::STU3::Condition.new( resourceType: 'Condition',