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

Igdd 1535 enable fhir query to izgw query transformation path #2

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d0794f0
Removing unintended uploaded jar files.
keithboone Jun 29, 2024
b0a9ef4
Final code for testing datatypes.
keithboone Jul 2, 2024
6e0b962
Cleaning up error reporting.
keithboone Jul 2, 2024
b622163
Adjust DateTime precision equivalence checks (varies under Linux).
keithboone Jul 2, 2024
5573e79
Adjust for no tz case in build environment at UTC
keithboone Jul 2, 2024
9f81a70
Adjusting timesAreEquivalent method for .999 and .9999 outputs.
keithboone Jul 3, 2024
ee8b918
Reorder precision adjustment
keithboone Jul 3, 2024
8fcee7e
Tweaking distance check for .999 and .9999 again.
keithboone Jul 3, 2024
a8df424
Diagnosing .999 checks in build environment.
keithboone Jul 3, 2024
0778d31
More dx
keithboone Jul 3, 2024
626e2ea
More DX
keithboone Jul 3, 2024
c022bc7
Adjusted logging level for DX.
keithboone Jul 3, 2024
ae522eb
Fixed some parsing errors on text, added tests, updated JavaDoc.
keithboone Jul 3, 2024
24ad580
Added Javadoc for public main classes.
keithboone Jul 4, 2024
2872fdb
More documentation and page build
keithboone Jul 4, 2024
baa2aa5
Added Github documentation publication to workflow.
keithboone Jul 4, 2024
f47ea48
Fix publish_dir
keithboone Jul 4, 2024
cc6c953
Tweak javadoc and report generation.
keithboone Jul 5, 2024
0fd684e
Updated POM to improve reporting.
keithboone Jul 5, 2024
4f2643e
One more tweak for dependency check.
keithboone Jul 5, 2024
541e4c8
Remove team from generated reports.
keithboone Jul 5, 2024
ebea55a
Remove team from report.
keithboone Jul 5, 2024
7629567
One more try for dependency-check-report.
keithboone Jul 5, 2024
7f513d0
Fix ordering.
keithboone Jul 5, 2024
18b7b20
Adjust test class names, fix dependency check reporting.
keithboone Jul 5, 2024
b7e530a
Up through PID and a good bit of testing on one message.
keithboone Jul 7, 2024
9bf65cf
Added remaining essential segments. It builds. Need to test.
keithboone Jul 16, 2024
ca9922d
Testing cleanup
keithboone Jul 16, 2024
30147c7
All unit tests passing.
keithboone Jul 16, 2024
b25d703
Merge branch 'main' into IGDD-1535_Enable_FHIR_Query_to_IZGW_Query_Tr…
keithboone Jul 16, 2024
346a1dd
Create SegmentParser.md
keithboone Jul 16, 2024
1f6b03e
Updated JavaDoc
keithboone Jul 17, 2024
0e6afd8
Committing code for BSOD recovery
keithboone Jul 19, 2024
df4842b
Automated conversion testing from @ComesFrom and @Produces annotations.
keithboone Jul 23, 2024
476bbbb
Documentation updates.
keithboone Jul 23, 2024
b526845
Fixing testTheData test.
keithboone Jul 23, 2024
e8aa0e8
Added class to generate QPD from FHIR Query parameters
keithboone Jul 24, 2024
3e125aa
Reference link cleanup
keithboone Jul 29, 2024
d71da5b
Updates for FHIR Conversion
keithboone Aug 6, 2024
8381e1b
AddressParser: share state name and abbreviation data.
keithboone Aug 14, 2024
8f814dd
Cleanup warnings.
keithboone Aug 14, 2024
3096b84
Fix family name search, adjusted phone search for tefca-viewer extra
keithboone Aug 18, 2024
e77fc03
Fine tuning for Demo
keithboone Aug 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .classpath
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
Expand Down
15 changes: 11 additions & 4 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
# default to force a revision check unless releasing
echo DO_REVISION_CHECK=true >> $GITHUB_ENV
# Skip dependency check
echo SKIP_DEPENDENCY_CHECK=true >> $GITHUB_ENV
echo SKIP_DEPENDENCY_CHECK=false >> $GITHUB_ENV

# If pulling to main branch (cutting a release), set branch tag appropriately
- name: Sets env vars for pull to main
Expand All @@ -122,7 +122,7 @@ jobs:
# Skip revision check on merge
echo DO_REVISION_CHECK=false >> $GITHUB_ENV
# Skip dependency check
echo SKIP_DEPENDENCY_CHECK=true >> $GITHUB_ENV
echo SKIP_DEPENDENCY_CHECK=false >> $GITHUB_ENV

# If pushing to main branch (cutting a release), set branch tag appropriately
- name: Sets env vars for pull to main
Expand Down Expand Up @@ -181,11 +181,18 @@ jobs:
ELASTIC_API_KEY: ${{ secrets.ELASTIC_API_KEY }}

run: |
env && mvn -B clean package install deploy -Dbuildno=${{github.run_number}} \
env && mvn -B clean package install deploy site -Dbuildno=${{github.run_number}} \
-DdoRevisionCheck=${{env.DO_REVISION_CHECK}} \
-DskipDependencyCheck=${{env.SKIP_DEPENDENCY_CHECK}} \
-Dimage.tag=$IMAGE_BRANCH_TAG


- name: Publish Site
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./target/site
destination_dir: current

- name: Upload build environment as artifact for failed build
uses: actions/upload-artifact@v4
if: ${{ failure() }}
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
**/target
**/doc
**/*.log
**/target/classes
**/.mvn
**/logs
**/temp
**/pom.xml.versionsBackup
**/pom.xml.versionsBackup
/~/
161 changes: 160 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,163 @@
# v2tofhir
This is the v2tofhir Converter core code for the IZ Gateway Transformation Service
This is the HL7 Version 2 to FHIR R4 Converter library for the IZ Gateway Transformation Service. The library
is intended to be a stand-alone set of HL7 Version 2 messaging conversion tools that can be used in multiple
contexts. It has been designed to support conversion of messages written according the the
(CDC HL7 Version 2 Immunization Implementation Guide)[https://repository.immregistries.org/files/resources/5bef530428317/hl7_2_5_1_release_1_5__2018_update.pdf] and may be suitable for other uses. This library depends on both the HAPI V2 and the HAPI FHIR libraries.

## JavaDoc
See [The JavaDoc for the Current Build](https://vigilant-adventure-g62mzg1.pages.github.io/current/apidocs/gov/cdc/izgw/v2tofhir/package-summary.html)

## Principles of the V2 Converter
The conversion methods of the V2 converter are intended to be forgiving, and follow (Postel's law)[https://en.wikipedia.org/wiki/Robustness_principle], doing
the best that they can to convert a V2 datatype or string to the appropriate FHIR type.

As a result, the conversion methods (e.g., DatatypeConverter.to*, DatatypeParser.convert, and DatatypeParser.fromString) do not throw
exceptions during the conversion process. Instead, these conversion methods return null if the datatype was null or empty (Type.isEmpty()
returns true or an exception), or if the datatype could not be converted because values are invalid. This follows the convention that
conversion should do as much as possible without causing a failure in applications using this library, as it is deemed more appropriate
to return as much information as is possible rather than nothing at all.

## How To Guide

### Converting a Single HL7 V2 Message
The main use case for this library is to convert a sinngle HL7 V2 Message to a Bundle of FHIR Resources.

```java
import gov.cdc.izgw.v2tofhir.MessageParser;
import org.hl7.fhir.r4.model.Bundle;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Structure;

...

void convertMessageExample(Message message) {
MessageParser parser = new MessageParser();
Bundle b parser.createBundle(message);
// Do something with the bundle resources
}
```

### Converting HL7 V2 Message Structures (Segments or Groups) to FHIR Resources
An individual segment, structure or group or sequence of these objects can also be converted to a FHIR Bundle.
In HAPI V2, a Segment is a specialization of a Structure and a Group is a named collection of segments or groups within a message.

The MessageParser class can be used to parse an iterable sequence of these objects in the provided order. These
conversions are performed as best as possible because some segments in the sequence (e.g., MSH) may be missing and
fail to create essential resources (e.g., MessageHeader).

Individual segments can contribute information to existing Resources created during a conversion. For example, the
ORC, RXA, RXR and OBX segments of the ORDER group in a VXU_V04 message all contribute information to the Immunization
resource.

```java
void convertStructureExample(Structure structure) {
MessageParser parser = new MessageParser();
Bundle b parser.createBundle(Collections.singletonList(structure));
// Do something with the bundle resources
}
```

### Converting an HL7 V2 Datatype to a FHIR Datatype
The HL7 Version 2 datatypes can be converted to FHIR Datatypes by the DatatypeConverter class or specific
DatatypeParser implementations. To convert an HL7 V2 Datatype to a FHIR Datatype, call the
to{FHIR Classname}(Type t) static method in DatatypeConverter. See the example below:

```java
convertTypesExample(DTM dtm, CWE cwe, XPN xpn) {
/* dtm can be converted to FHIR Types derived from BaseDateTimeType */
InstanceType instant = DatatypeConverter.toInstantType(dtm);
/* The calls below produces the same results as the call above */
instant = DatatypeConverter.convert(InstantType.class, dtm);
instant = DatatypeConverter.convert("InstantType", dtm);

DateTimeType dateTime = DatatypeConverter.toDateTimeType(dtm);
DateType date = DatatypeConverter.toDateType(dtm);

/* Codes can be converted to Coding, CodeableConcept, CodeType or Identifier types */
CodeableConcept cc = DatatypeConverter.toCodeableConcept(cwe);
Coding coding = DatatypeConverter.toCoding(cwe);
CodeType code = DatatypeConverter.toCodeType(cwe);

HumanName hn = DatatypeConverter.toHumanName(hn);
/* HumanName also has a standalone parser */
hn = new HumanNameParser().convert(hn);
}

```

### Converting a FHIR Resource or Datatype to a string representation
The TextUtils class enables conversion of HL7 V2 types and FHIR Datatypes to a text string relying on the same supporting methods
so that the representations are similar if not identical.

Call TextUtils.toString(ca.uhn.hl7v2.model.Type) to convert an HL7 Version 2 datatype to a string. Call
TextUtils.toString(org.hl7.fhir.r4.model.Type) to convert a FHIR datatype to a string. When the FHIR type
was created by a DatatypeConverter method, the toString() results on the FHIR type should be identical
to the toString() method on the source.

These methods are primarily used to support validation of FHIR conversions.

### Converting Text Strings to FHIR Datatypes
Stand-alone datatype parsers (classes implementing DatatypeParser such as AddressParser, ContactPointParser, and HumanNameParser)
support conversion of text strings the specified FHIR datatype. These parsers use very lightweight natural language processing to
parse the string into the relevant data type.

```java
HumanName hn = new HumanNameParser().fromString("Mr. Keith W. Boone");
Address addr = new AddressParser().fromString(
"1600 Clifton Road, NE\n" +
"Atlanta, GA 30333"
);
ContactPointParser parser = new ContactPointParser();
/* All of below return a Phone number */
ContactPoint cp = parser.fromString("tel:800-555-1212");
cp = parser.fromString("+1.800.555.1212");
cp = parser.fromString("(800) 555-1212");

/* All of below return an e-mail address */
cp = parser.fromString("mailto:[email protected]");
cp = parser.fromString("[email protected]");
cp = parser.fromString("IZ Gateway <[email protected]>");

/** Returns a network address */
cp = parser.fromString("https://support.izgateway.org");

```

## Developer Guide
### Writing a new Datatype Parser

### Writing a new Structure Parser

### Writing a new Segment Parser
See the [Segment Parser Walkthrough](SegmentParser.md)

### Creating a New Resource
There are two ways to create a new resource within a Segment or Structure parser. The first
is to use the resource factory method: <R extends IBaseResource> R createResource(Class<R> clazz) to
create it. This will create the resource, assign it an identifier, and add it to the bundle in the
order of creation, and if enabled, also create a Provenance resource documenting how and where it was
create from.

```
Patient p = createResource(Patient.class);
```

The next method is to create it in any other way, and then just add it to the bundle. This too will
generate an identifier for the resource, add it to the bundle in the order in which it was recieved,
and if enabled, create a Provenance resource for it.

```
Patient p = new Patient();
addResource(p);
```
### Accessing Existing Resources
Methods exist to access the first, last, and any identified resource of a given type and identifier,
and find one or create one if it doesn't exist.

The Resource getResource(String id) method gets the resource with the specified identifier.
The <R extends IBaseResource> R getResource(Class<R> clazz, String id) method gets the resource of the specified type with the specified identifier.
The <R extends IBaseResource> R getFirstResoruce(Class<R> clazz) gets the first generated resource of the specified type in the bundle.
The <R extends IBaseResource> R getLastResoruce(Class<R> clazz) gets the most recently generated resource of the specified type in the bundle.

The <R extends IBaseResource> R findResource(Class<R> clazz, String id) method first calls getResource(clazz, id), and returns the result if a resource was
found otherwise it calls createResource(clazz, id) to create a new one.
Loading