Skip to content

Commit

Permalink
Find CodeSystems from packages by id, name, and URL (#1175)
Browse files Browse the repository at this point in the history
* Add tests for using name, id, or URL of CodeSystem in AssignmentRules

* Support using id, name, or URL when assigning a CodeSystem from FHIR or dependencies

- Use fishForMetadata to search in tank or fhir definitions for the CodeSystem
- Assign the system if it is found for local and FHIR definition CodeSystems
- Fix a bug in the TestFisher to only return the Package if we are fishing for a defined item
  • Loading branch information
jafeltra authored Nov 23, 2022
1 parent 496a294 commit 309875c
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 11 deletions.
5 changes: 2 additions & 3 deletions src/export/Package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ export class Package implements Fishable {
return metadata;
} else if (
// If nothing is returned, perhaps the Package itself is being referenced
item === this.config.packageId ||
item === this.config.name ||
item === this.config.id
item != null &&
(item === this.config.packageId || item === this.config.name || item === this.config.id)
) {
const metadata: Metadata = {
id: this.config.packageId || this.config.id,
Expand Down
14 changes: 6 additions & 8 deletions src/fhirtypes/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,17 +443,15 @@ export function replaceReferences<T extends AssignmentRule | CaretValueRule>(
const [system, ...versionParts] = value.system?.split('|') ?? [];
const version = versionParts.join('|');
const codeSystem = tank.fish(system, Type.CodeSystem);
const codeSystemMeta = fisher.fishForMetadata(codeSystem?.name, Type.CodeSystem);
if (
codeSystem &&
(codeSystem instanceof FshCodeSystem || codeSystem instanceof Instance) &&
codeSystemMeta
) {
const codeSystemMeta = fisher.fishForMetadata(system, Type.CodeSystem);
if (codeSystemMeta) {
clone = cloneDeep(rule);
const assignedCode = getRuleValue(clone) as FshCode;
assignedCode.system = `${codeSystemMeta.url}${version ? `|${version}` : ''}`;
// if a local system was used, check to make sure the code is actually in that system
listUndefinedLocalCodes(codeSystem, [assignedCode.code], tank, rule);
if (codeSystem && (codeSystem instanceof FshCodeSystem || codeSystem instanceof Instance)) {
// if a local system was used, check to make sure the code is actually in that system
listUndefinedLocalCodes(codeSystem, [assignedCode.code], tank, rule);
}
}
}
return clone ?? rule;
Expand Down
73 changes: 73 additions & 0 deletions test/export/InstanceExporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2848,6 +2848,79 @@ describe('InstanceExporter', () => {
]);
});

// Assigning codes from systems in the fisher.fhir (core fhir package or dependencies)
it('should assign a code from a CodeSystem in the fisher by id', () => {
// allergyintolerance-clinical is the id of a CodeSystem in the R4 definitions
const observation = new Instance('MyObservation');
observation.instanceOf = 'Observation';
const statusRule = new AssignmentRule('status');
statusRule.value = new FshCode('active');
const assignedCodeRule = new AssignmentRule('code');
assignedCodeRule.value = new FshCode('test-code', 'allergyintolerance-clinical'); // id
observation.rules.push(assignedCodeRule, statusRule);
doc.instances.set(observation.name, observation);

const exported = exportInstance(observation);
expect(exported.code).toEqual({
coding: [
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]
});
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

it('should assign a code from a CodeSystem in the fisher by name', () => {
// AllergyIntoleranceClinicalStatusCodes is the name of a CodeSystem in the R4 definitions
const observation = new Instance('MyObservation');
observation.instanceOf = 'Observation';
const statusRule = new AssignmentRule('status');
statusRule.value = new FshCode('active');
const assignedCodeRule = new AssignmentRule('code');
assignedCodeRule.value = new FshCode('test-code', 'AllergyIntoleranceClinicalStatusCodes'); // name
observation.rules.push(assignedCodeRule, statusRule);
doc.instances.set(observation.name, observation);

const exported = exportInstance(observation);
expect(exported.code).toEqual({
coding: [
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]
});
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

it('should assign a code from a CodeSystem in the fisher by url', () => {
// http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical is the url of a CodeSystem in the R4 definitions
const observation = new Instance('MyObservation');
observation.instanceOf = 'Observation';
const statusRule = new AssignmentRule('status');
statusRule.value = new FshCode('active');
const assignedCodeRule = new AssignmentRule('code');
assignedCodeRule.value = new FshCode(
'test-code',
'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
); // url
observation.rules.push(assignedCodeRule, statusRule);
doc.instances.set(observation.name, observation);

const exported = exportInstance(observation);
expect(exported.code).toEqual({
coding: [
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]
});
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

// Assigning Quantities with value 0 (e.g., Age)
it('should assign a Quantity with value 0 (and not drop the 0)', () => {
const observationInstance = new Instance('ZeroValueObservation');
Expand Down
63 changes: 63 additions & 0 deletions test/export/StructureDefinitionExporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4281,6 +4281,69 @@ describe('StructureDefinitionExporter R4', () => {
);
});

it('should apply a Code AssignmentRule and replace the id of code system (from the core version fhir or dependency) with its url', () => {
// allergyintolerance-clinical is the id of a CodeSystem in the R4 definitions
const profile = new Profile('LightObservation');
profile.parent = 'Observation';
const rule = new AssignmentRule('category');
rule.value = new FshCode('test-code', 'allergyintolerance-clinical'); // id
profile.rules.push(rule);

exporter.exportStructDef(profile);
const sd = pkg.profiles[0];
const assignedElement = sd.findElement('Observation.category');
expect(assignedElement.patternCodeableConcept.coding).toEqual([
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]);
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

it('should apply a Code AssignmentRule and replace the name of code system (from the core version fhir or dependency) with its url', () => {
// AllergyIntoleranceClinicalStatusCodes is the name of a CodeSystem in the R4 definitions
const profile = new Profile('LightObservation');
profile.parent = 'Observation';
const rule = new AssignmentRule('category');
rule.value = new FshCode('test-code', 'AllergyIntoleranceClinicalStatusCodes'); // name
profile.rules.push(rule);

exporter.exportStructDef(profile);
const sd = pkg.profiles[0];
const assignedElement = sd.findElement('Observation.category');
expect(assignedElement.patternCodeableConcept.coding).toEqual([
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]);
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

it('should apply a Code AssignmentRule and keep the url of code system (from the core version fhir or dependency) as the system url', () => {
// http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical is the url of a CodeSystem in the R4 definitions
const profile = new Profile('LightObservation');
profile.parent = 'Observation';
const rule = new AssignmentRule('category');
rule.value = new FshCode(
'test-code',
'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
); // url
profile.rules.push(rule);

exporter.exportStructDef(profile);
const sd = pkg.profiles[0];
const assignedElement = sd.findElement('Observation.category');
expect(assignedElement.patternCodeableConcept.coding).toEqual([
{
code: 'test-code',
system: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'
}
]);
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
});

it('should apply an AssignmentRule with a valid Canonical entity defined in FSH', () => {
const profile = new Profile('MyObservation');
profile.parent = 'Observation';
Expand Down

0 comments on commit 309875c

Please sign in to comment.