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

Add CodeableReference keyword #1292

Merged
merged 7 commits into from
Jun 22, 2023
Merged

Add CodeableReference keyword #1292

merged 7 commits into from
Jun 22, 2023

Conversation

jafeltra
Copy link
Collaborator

This PR adds a CodeableReference keyword, which can be used in Type Rules to constrain a type to a CodeableReference or a specific set of CodeableReference resource/profiles and Add Element Rules to add a CodeableReference element.

As of right now, the CodeableReference keyword cannot be used in AssignmentRules. To assign a portion of a CodeableReference element, you can assign the concept and/or reference portion directly, as you do now in the current version of SUSHI. If it turns out we do want to add AssignmentRule use for the CodeableReference PR, I'll either close this PR or mark it as draft while making the updates.

@jafeltra jafeltra force-pushed the codeable-reference-keyword branch from 9a84c47 to 314a875 Compare June 15, 2023 15:40
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 really good, and should definitely help with using CodeableReference types. I have a few small suggestions.

Comment on lines 965 to 969
if (
targetTypes.some(t => t.code === 'CodeableReference') &&
!targetTypes.some(t => t.code === 'Reference') &&
rule.types.every(t => t.isReference)
) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this condition may need to be slightly adjusted. It should only be necessary for one of the rule's types to be Reference for this warning to be useful. Here is an example of what I mean:

Extension: MyExt
* value[x] only boolean or CodeableReference
* value[x] only boolean or Reference(Patient)

The first OnlyRule removes the Reference type, so the second OnlyRule constrains the target profile for CodeableReference. But, in this case, no warning is logged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, that's a good point, and a case I hadn't thought about. If I just change the condition here, the warning message actually constructs the wrong example because it tries to create CodeableReference(boolean or Patient), which is wrong. So I think I'll also just remove the example, especially since the line number is included as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I updated the condition and the warning message and included a test in 20614c4.

@@ -1171,7 +1199,7 @@ export class ElementDefinition {
// one of the targetProfiles. If the targetProfile property is null, that means any
// reference is allowed.
// When 'Reference' keyword is used, prefer to match on the 'Reference' type over the
// 'CodeableReference' type if they both exist on the element.
// 'CodeableReference' type if they both exist on the element, but issue a warning.
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 referring to the warning in constrainType, or is there supposed to be a new warning here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

opps, yes I moved the warning and forgot about the comment!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed in 20614c4

Copy link
Collaborator

Choose a reason for hiding this comment

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

It could be useful to add some tests that constrain an element to a combination of Reference/CodeableReference and non-reference types.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added in 20614c4

@@ -1319,6 +1319,58 @@ describe('FSHImporter', () => {
);
});

it('should parse an only rule with a CodeableReference to one type', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are these new tests identical to the new tests in FSHImporter.Profile.test.ts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So.. I think.. maybe? I thought they seemed to be covering the same cases, but I was going off of the existing tests, and there seem to be a good deal of overlap in those sets of tests. So I sort of just figured there was a reason we had them in each place. But maybe, if you agree they seem to cover exactly the same cases, this is the time to stop duplicating tests and I can remove either set.

Copy link
Member

Choose a reason for hiding this comment

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

If you can confirm that these are exactly the same, I'm fine with removing them. We may have overlapping tests due to previous refactoring... Or in a few cases, I think we have a token test cases in broad test files and then many detailed ones in more specific test files. Maybe that is what's going on here? Either way, duplicate tests aren't really helpful so I'm fine w/ them going away.

That said, if there are lots of duplicate tests in this file in general, then it may be worth making a separate task to clean the whole thing up.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I double checked, and as far as I can tell, they are exactly the same. Neither set of tests sets up anything different in describe and/or beforeAll/beforeEach blocks.

There do seem to be large amounts of duplicates between these two files. The FSHImporter.SDRules.tests.ts file does mention at the top that it is designed to cover the overlap between the four different StructureDefinition entities (profiles, extensions, resources, and logicals). I looked at the OnlyRule section, where the tests I added were, as well as a few other sections. There is a large amount of overlap between the tests, but unfortunately there are a few tests that were newly added in both files. For example, the CaretValueRule section has 4 tests shared between the two files, 1 new test added in the FSHImporter.Profile file, and 1 new test added in the FSHImporter.SDRules file.

So that is... unfortunate. It seems like the files might have been refactored when Logicals and Resources were added, so I wonder if something got messed up in the rebasing/merging back then. Who knows.

All that said, I think what makes sense is to add the three new tests I included here into the FSHImporter.SDRules.test.ts file and remove them from the FSHImporter.Profile.test.ts file since they apply to any StructureDefinition and that will reduce clutter for now. And then it probably is a good idea to clean up these files so there are fewer shared tests between them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I checked the InsertRule block and there's a whole bunch of tests in the FSHImporter.Profile.test.ts that aren't in the FSHImporter.SDRules.test.ts (~12 tests). So I actually don't know for sure which file we should be trying to maintain, but I think the FSHImporter.SDRules.test.ts makes more sense as a centralized place to hold the overlapping tests. So I'll still plan to move my tests to be in FSHImporter.SDRules.test.ts, but I can be convinced otherwise if either of you disagree on the file to hold them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed the duplicate tests in 7d6c098, but I can swap the location once you have a chance to process the novels I wrote above.

Copy link
Member

Choose a reason for hiding this comment

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

I don't know. On one hand, I understand the approach of having tests for logic that applies to any SD being in FSHImporter.SDRules.test.ts. On the other hand, when you write the test, you do have to choose a specific kind of SD, right? But when we're talking about importing rules, I guess it shouldn't matter if it is a profile, logical, etc... So... ???

I think one of the reasons we split into FSHImporter.Profile.test.ts and others was to keep FSHImporter.SDRules.test.ts from becoming massive. But at the same time, if we put a rule import test only in FSHImporter.Profile.test.ts, then it's not easy to know where to look for it and people might thing that type of rule is not tested at all.

All this to say, I think you can justify either way. But I guess maybe if I had to lean, I'd lean toward FSHImporter.SDRules.test.ts? Maybe we should refactor into a separate file for every rule type instead. That actually might make more sense, but is way outside the scope of this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

On the other hand, when you write the test, you do have to choose a specific kind of SD, right?

Yes, you do. It seems like the majority of the tests in FSHImporter.SDRules.test.ts are testing Profile, with a handful for Resource when testing Resource/Logical Model specific rules.

I was looking at the file history trying to figure out which file came first, and it seemed like SDRules came second, which is why I thought maybe it was trying to ease the number of tests in the Profile file, but that was really just an inference.

But when we're talking about importing rules, I guess it shouldn't matter if it is a profile, logical, etc... So... ???

Also, when looking at the Importer code, we do specifically have a visitSdRule function that is called when importing all four types of StructureDefintions. So maybe to align with the code, the tests in FSHImporter.SDRules.test.ts should align with the functionality in visitSdRule and any extra functionality, like the rules specific to Logical Models and Resources, are included in separate files for those entities. It feels like maybe that was what we tried to do and things got messy. I'm not sure. And I guess I don't need to be sure for right now.

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.

Thank you for the updates! I have a suggestion about the warning message, but everything else looks good.

rule.types.some(t => t.isReference)
) {
logger.warn(
'The CodeableReference() syntax should be used to constrain references of a CodeableReference',
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this message might read a little better if it said keyword instead of syntax:

The CodeableReference() keyword should be used to constrain references of a CodeableReference

Copy link
Collaborator Author

@jafeltra jafeltra Jun 20, 2023

Choose a reason for hiding this comment

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

I like it. Added in 9c780bd.

@jafeltra jafeltra force-pushed the codeable-reference-keyword branch from 6ef48c8 to 9c780bd Compare June 20, 2023 21:10
@cmoesel
Copy link
Member

cmoesel commented Jun 21, 2023

FYI - I've discussed with Mark Kramer and he agrees with the approach here: CodeableConcept() is suitable for constraining types but should not be used for assignments.

mint-thompson
mint-thompson previously approved these changes Jun 21, 2023
Copy link
Member

@cmoesel cmoesel 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 and works well. I've mainly just made some small suggestions for the tests.

addresses.constrainType(onlyRule, fisher);
}).toThrow(/"Reference\(Patient\).*Reference\(.*Condition\)/);
describe('Reference() keyword', () => {
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a subset', () => {
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest rewording the tests that use Reference to constrain a CodeableConcept so that the test summary indicates that a warning should be logged. E.g.:

Suggested change
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a subset', () => {
it('should warn when a CodeableReference to multiple resource types is constrained to a Reference to a subset', () => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 9f88612, along with the few other tests that needed this update.

);
});

it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a single profile', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a single profile', () => {
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to multiple profiles', () => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 9f88612

expect(loggerSpy.getAllMessages('warn')).toHaveLength(0);
});

it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a single profile using CodeableReference keyword', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to a single profile using CodeableReference keyword', () => {
it('should allow a CodeableReference to multiple resource types to be constrained to a reference to multiple profiles using CodeableReference keyword', () => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 9f88612

const input = leftAlign(`
Profile: ObservationProfile
Parent: Observation
* performer only CodeableReference( Organization or CareTeam)
Copy link
Member

Choose a reason for hiding this comment

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

Just to be sure we're allowing white space in all the places, I'd suggest adding some before the last ) too:

Suggested change
* performer only CodeableReference( Organization or CareTeam)
* performer only CodeableReference( Organization or CareTeam )

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good call!

Copy link
Collaborator Author

@jafeltra jafeltra Jun 21, 2023

Choose a reason for hiding this comment

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

Updated in 9f88612, but then promptly removed in favor of the tests in FSHImporter.SDRules.test.ts. But don't worry, they have the space as well!

@@ -1319,6 +1319,58 @@ describe('FSHImporter', () => {
);
});

it('should parse an only rule with a CodeableReference to one type', () => {
Copy link
Member

Choose a reason for hiding this comment

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

If you can confirm that these are exactly the same, I'm fine with removing them. We may have overlapping tests due to previous refactoring... Or in a few cases, I think we have a token test cases in broad test files and then many detailed ones in more specific test files. Maybe that is what's going on here? Either way, duplicate tests aren't really helpful so I'm fine w/ them going away.

That said, if there are lots of duplicate tests in this file in general, then it may be worth making a separate task to clean the whole thing up.

Copy link
Member

@cmoesel cmoesel left a comment

Choose a reason for hiding this comment

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

Two thumbs up. Would recommend to a friend.

@jafeltra jafeltra merged commit d58c5e7 into master Jun 22, 2023
@jafeltra jafeltra deleted the codeable-reference-keyword branch June 22, 2023 18:57
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