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

Integrate FHIR Package Loader v2 #1543

Merged
merged 15 commits into from
Dec 20, 2024
Merged

Integrate FHIR Package Loader v2 #1543

merged 15 commits into from
Dec 20, 2024

Conversation

cmoesel
Copy link
Member

@cmoesel cmoesel commented Dec 6, 2024

Description: This PR integrates the brand new FHIR Package Loader (v2). The general approach was:

  • Update FHIRDefinitions to extend BasePackageLoader
  • Update fishing functions in FHIRDefinitions to use the findResource and findResourceInfo functions in BasePackageLoader -- ensuring that FHIRDefinitions still conforms to the expected Fisher interface.
  • Remove most other functions from FHIRDefinitions in favor of the functions inherited from BasePackageLoader
  • Update all affected code as necessary (most significant changes in package loading and IG Exporter)
  • Update tests to load most fixtures using FPL virtual packages

This also updates the regression framework to support pre-caching of dependencies so the first run of SUSHI does not have the extra work of downloading all dependencies (which could skew results). It also reports out more information regarding performance.

Testing Instructions: Some ideas:

  • Run it against some of your favorite projects
  • Delete or rename your FHIR cache and try it on a project or two
  • Try package-related features like sushi update-dependencies
  • Try the FSH-to-FHIR API
  • Run a regression.
    • Note that the regression is expected to result in changes for a few repos (mainly some differences in warning/error counts). Confirm that the changes appear to be correct and/or harmless.

First take at integrating the new FPL. It works, but could use some refactoring, cleanup, and optimization.
Additional changes to get all of the tests passing again. Still needs refactoring, cleanup, and optimization.
Clean up the FHIRDefinitions objects to only contain what's actually needed.
- Only clone FPL results where and when necessary
- Use FPL's new SafeMode.FREEZE feature to avoid unintentional modification of cached resources
- Integrate optimized FPL with new optimize() function
- Update some outdated dependencies
@cmoesel cmoesel marked this pull request as ready for review December 6, 2024 17:55
Copy link
Collaborator

@jafeltra jafeltra left a comment

Choose a reason for hiding this comment

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

I just left a few very small questions/comments.

I tried out using this branch, running a small regression, using the update-dependencies command, and the FSH to FHIR API, and everything worked as expected!

package.json Outdated Show resolved Hide resolved
src/app.ts Outdated Show resolved Hide resolved
src/app.ts Outdated Show resolved Hide resolved
src/fhirdefs/FHIRDefinitions.ts Outdated Show resolved Hide resolved
src/ig/IGExporter.ts Show resolved Hide resolved
Copy link
Collaborator

@mint-thompson mint-thompson left a comment

Choose a reason for hiding this comment

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

This worked perfectly when I ran with it locally. I have a few small comments and suggestions.

src/app.ts Outdated Show resolved Hide resolved
@@ -271,15 +273,16 @@ export class IGExporter {
}

if (dependsOn.version === 'latest') {
// TODO: This assumes only a single version of a package is in scope
Copy link
Collaborator

Choose a reason for hiding this comment

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

The current implementation is fine, since it's the same as before, but I'm curious: what would be the best way to handle latest when multiple versions are in scope? Would it just be whichever version is the latest based on a semver comparison? Or would we need to check the registry to see what has the tag?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we have a few options. Using semver would probably be a reasonable approach, but we might also look into using FPL to find the latest again or tagging latest versions in the FPL DB when we put them in there (and exposing that in the PackageInfo results.

);
if (configParameters && projectDir) {
const pathResources = configParameters
?.filter(parameter => parameter.value && parameter.code === 'path-resource')
Copy link
Collaborator

Choose a reason for hiding this comment

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

The if statement guarantees that configParameters is truthy, so I don't think you need to null-coalesce here.

Suggested change
?.filter(parameter => parameter.value && parameter.code === 'path-resource')
.filter(parameter => parameter.value && parameter.code === 'path-resource')

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed in 5b4874e.

);
beforeAll(async () => {
r5Defs = await getTestFHIRDefinitions(false, testDefsPath('r5-definitions'));
r5Fisher = new TestFisher().withFHIR(r5Defs);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this line needed? r5Fisher gets assigned to a new TestFisher during beforeEach, and nothing uses it before then.

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed in 5b4874e.

);
beforeAll(async () => {
r5Defs = await getTestFHIRDefinitions(false, testDefsPath('r5-definitions'));
r5Fisher = new TestFisher().withFHIR(r5Defs);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similarly to ElementDefinition.assignFshReference.test.ts, I don't think this line should be needed. This also appears to be in a lot of the ElementDefinition.assign{something} tests. Maybe I've missed something about side effects?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, I think this is just the result of me having to refactor these tests and doing some of the refactoring a line at a time without looking at the overall test suite to notice that some things are no longer necessary. Good find.

Copy link
Member Author

Choose a reason for hiding this comment

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

This also appears to be in a lot of the ElementDefinition.assign{something} tests. Maybe I've missed something about side effects?

Actually, now that I've looked through them, I don't see it anywhere else. Just ElementDefinition.assignFshReference.test.ts and ElementDefinition.assignValue.test.ts. Are you sure you saw it in other tests? And if so, where?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I must have been looking at the wrong set of search results when I wrote this comment if I thought there were many other places. I only see unnecessary instantiation of TestFisher in a beforeAll block in those two files.

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed in 5b4874e.

);
defs.add(def);
it('should allow a choice to be constrained to a profile of Reference', async () => {
defs.loadLocalPaths(testDefsPath('StructureDefinition-reference-with-type.json'));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this line have an await to guarantee that the local definition finishes loading before trying to constrain the element's type?

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed in 5b4874e -- and I found one more case of loadLocalPaths that needed an await.

const NUM_R5_AUTO_DEPENDENCIES = 3;

const TERM_R4_PKG_RESPONSE = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am a big fan of how much simpler these test definitions get to be now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Me too!

The main difference in FPL 2.0.0-beta.2 is that you no longer pass in a sql.js Database to the SQLJSPackageDB constructor. Instead, you construct SQLJSPackageDB and then call its async initialize function.

This required us to update FHIRDefinitions to add an initialize function that then invokes the SQLJSPackageDB initiailze function.
mint-thompson
mint-thompson previously approved these changes Dec 17, 2024
Copy link
Collaborator

@mint-thompson mint-thompson left a comment

Choose a reason for hiding this comment

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

This looks good! I have one minor comment, but I'm fine with this being merged in as-is.

Comment on lines 205 to 225
export async function newFHIRDefinitions(
isSupplementalFHIRDefinitions = false,
supplementalFHIRDefinitionsFactory?: () => Promise<FHIRDefinitions>,
// override is mainly intended to be used in unit tests
override?: {
packageDB?: PackageDB;
packageCache?: PackageCache;
registryClient?: RegistryClient;
currentBuildClient?: CurrentBuildClient;
options?: BasePackageLoaderOptions;
}
) {
const fhirDefinitions = new FHIRDefinitions(
isSupplementalFHIRDefinitions,
supplementalFHIRDefinitionsFactory,
override
);
await fhirDefinitions.initialize();
return fhirDefinitions;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

This implementation is good, but I'm wondering if I like this better as a static method on FHIRDefinitions instead of a standalone function. Also, the function name seems risky for awkward typos, since this and the constructor take the same arguments.

@cmoesel
Copy link
Member Author

cmoesel commented Dec 17, 2024

@jafeltra @mint-thompson - I pushed up some commits that change newFHIRDefinitions to createFHIRDefinitions and integrate FPL 2.0.0-beta.3.

jafeltra
jafeltra previously approved these changes Dec 20, 2024
Copy link
Collaborator

@jafeltra jafeltra left a comment

Choose a reason for hiding this comment

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

Yay this looks good to me! All the fixes look good since my last review!

mint-thompson
mint-thompson previously approved these changes Dec 20, 2024
Copy link
Collaborator

@mint-thompson mint-thompson left a comment

Choose a reason for hiding this comment

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

hooray!

@cmoesel
Copy link
Member Author

cmoesel commented Dec 20, 2024

Excellent. This signals that the new FPL is also ready for official release. So here is the plan:

  1. Bump the FPL version to 2.0.0 (non-beta) and release on NPM.
  2. Integrate the official FPL 2.0.0 release into this PR.
  3. Since FPL 2.0.0 is the same as FPL 2.0.0-beta.3, no further review of this PR is required after that, so I will merge this one.
  4. Release this as a minor SUSHI release.

@cmoesel cmoesel dismissed stale reviews from mint-thompson and jafeltra via f9a7d8d December 20, 2024 17:30
@cmoesel
Copy link
Member Author

cmoesel commented Dec 20, 2024

@jafeltra and @mint-thompson - I dismissed your reviews when I pushed up the new dependency on FPL 2.0.0. As noted above, it does not affect any actual logic since FPL 2.0.0 is exactly the same as FPL 2.0.0-beta.3. Please re-approve.

@cmoesel cmoesel merged commit 6541681 into master Dec 20, 2024
14 checks passed
@cmoesel cmoesel deleted the new-fpl branch December 20, 2024 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants