Skip to content

Commit

Permalink
Add optional argument for making clone of predefined resources (#1500)
Browse files Browse the repository at this point in the history
The FHIRDefinitions class provides a public method to return all
predefined resources. Hypothetically, the caller of this method could
alter the predefined resources, which is why it could be useful to
return a clone of these resources. However, in all places this method is
called by SUSHI, the resources are used for a search, not for any
modifications. By not cloning the resources for the search, significant
time savings are possible. Just in case someone else is using SUSHI as a
dependency and calling this method and expecting to receive a clone, the
default behavior is to return a clone.

When searching for slices, the slice of an element is always a sibling
of that element. Therefore, it is preferable to search the smaller list
containing only the element's parent's children, when possible. This
takes advantage of the underlying ElementDefinition tree. Because the
root element's parent is undefined, use the full element list when
working with the root element. This shouldn't be possible in most cases,
as revealed by the test coverage, but the implementation is defensive
just in case something unusual has happened to the root element.
  • Loading branch information
mint-thompson authored Aug 26, 2024
1 parent 00415f1 commit e91f68e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 14 deletions.
10 changes: 7 additions & 3 deletions src/fhirdefs/FHIRDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ export class FHIRDefinitions extends BaseFHIRDefinitions implements Fishable {
return flatten(Array.from(this.supplementalFHIRDefinitions.keys()));
}

allPredefinedResources(): any[] {
return Array.from(this.predefinedResources.values()).map(v => cloneDeep(v));
allPredefinedResources(makeClone = true): any[] {
if (makeClone) {
return Array.from(this.predefinedResources.values()).map(v => cloneDeep(v));
} else {
return Array.from(this.predefinedResources.values());
}
}

add(definition: any): void {
Expand Down Expand Up @@ -81,7 +85,7 @@ export class FHIRDefinitions extends BaseFHIRDefinitions implements Fishable {
const resource = this.fishForFHIR(item, ...types);
if (
resource &&
this.allPredefinedResources().find(
this.allPredefinedResources(false).find(
predefResource =>
predefResource.id === resource.id &&
predefResource.resourceType === resource.resourceType &&
Expand Down
26 changes: 16 additions & 10 deletions src/fhirtypes/ElementDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,11 +774,12 @@ export class ElementDefinition {

getSlices() {
if (this.sliceName) {
return this.structDef.elements.filter(
// this.parent() should never be undefined if this element has a sliceName, but code defensively just in case
return (this.parent()?.children(true) ?? this.structDef.elements).filter(
e => e.id !== this.id && e.path === this.path && e.id.startsWith(`${this.id}/`)
);
} else {
return this.structDef.elements.filter(
return (this.parent()?.children(true) ?? this.structDef.elements).filter(
e => e.id !== this.id && e.path === this.path && e.id.startsWith(`${this.id}:`)
);
}
Expand Down Expand Up @@ -898,12 +899,14 @@ export class ElementDefinition {
const slicedElement = this.slicedElement();
if (slicedElement) {
const parentSlice = this.findParentSlice();
const sliceSiblings = this.structDef.elements.filter(
el =>
this !== el &&
slicedElement === el.slicedElement() &&
parentSlice === el.findParentSlice()
);
const sliceSiblings = this.parent()
.children(true)
.filter(
el =>
this !== el &&
slicedElement === el.slicedElement() &&
parentSlice === el.findParentSlice()
);
const newParentMin = min + sliceSiblings.reduce((sum, el) => sum + el.min, 0);
// if this is a reslice, the parent element will also be a slice of the sliced element.
// if this is not a reslice, the parent element is the sliced element.
Expand Down Expand Up @@ -985,8 +988,9 @@ export class ElementDefinition {
return parentNameParts.slice(0, i + 1).join('/');
})
.reverse();
const elementsToSearch = this.parent()?.children(true) ?? this.structDef.elements;
for (const parentName of potentialParentNames) {
const potentialParent = this.structDef.elements.find(el => {
const potentialParent = elementsToSearch.find(el => {
return el.sliceName === parentName && el.slicedElement() === slicedElement;
});
if (potentialParent) {
Expand Down Expand Up @@ -2586,7 +2590,9 @@ export class ElementDefinition {
*/
slicedElement(): ElementDefinition | undefined {
if (this.sliceName) {
return this.structDef.elements.find(e => e.id === this.id.slice(0, this.id.lastIndexOf(':')));
return (this.parent()?.children(true) ?? this.structDef.elements).find(
e => e.id === this.id.slice(0, this.id.lastIndexOf(':'))
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/Processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ export function writeFHIRResources(
logger.info('Exporting FHIR resources as JSON...');
let count = 0;
const skippedResources: string[] = [];
const predefinedResources = defs.allPredefinedResources();
const predefinedResources = defs.allPredefinedResources(false);
const writeResources = (
resources: {
getFileName: () => string;
Expand Down

0 comments on commit e91f68e

Please sign in to comment.