Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FI-2906 R4B and R5 support #169

Merged
merged 12 commits into from
Oct 18, 2024
2 changes: 1 addition & 1 deletion .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 1 addition & 7 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml

AllCops:
TargetRubyVersion: 2.4
TargetRubyVersion: 3.0
Exclude:
- '*.gemspec'
- 'Gemfile*'
Expand All @@ -10,9 +10,6 @@ AllCops:
- 'lib/tasks/*'
- 'vendor/**/*'

Documentation:
Enabled: false

Metrics:
Enabled: false

Expand All @@ -22,8 +19,5 @@ Style:
Layout:
Enabled: false

Performance/Casecmp:
Enabled: false

Naming:
Enabled: false
14 changes: 1 addition & 13 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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')
Expand Down
3 changes: 2 additions & 1 deletion fhir_client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 2 additions & 0 deletions lib/fhir_client.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require 'fhir_models'
require 'fhir_models/r4b'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only require these when we're going to actually use them, otherwise this undoes the work we did to allow versions to be loaded separately.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, Diego, I thought I removed this comment before I finished my review because I decided it was out of scope. Could you undo this part of the changes?

require 'fhir_models/r5'
require 'fhir_dstu2_models'
require 'fhir_stu3_models'
require 'active_support/all'
Expand Down
68 changes: 55 additions & 13 deletions lib/fhir_client/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions lib/fhir_client/ext/bundle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
16 changes: 16 additions & 0 deletions lib/fhir_client/ext/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
32 changes: 28 additions & 4 deletions lib/fhir_client/ext/reference.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -93,20 +93,44 @@ 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
end

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
4 changes: 4 additions & 0 deletions lib/fhir_client/version_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading