Stream: conformance
Topic: Narrow Quantity to Duration and Age
Chris Moesel (May 18 2020 at 20:33):
If I want to say that Observation.value[x]
can only be a Duration
or an Age
, how do I do that? The value[x]
choice does not contain Duration
or Age
specifically, but it does contain Quantity
-- and Duration
/Age
are specializations of Quantity
.
In the past, I thought that this worked:
{
"id": "Observation.value[x]",
"path": "Observation.value[x]",
"type": [ { "code": "Duration" }, { "code": "Age" } ]
}
but now the Publisher barks at that:
illegal constrained type Duration from Quantity, CodeableConcept, string, boolean, integer, Range, Ratio, SampledData, time, dateTime, Period in http://hl7.org/fhir/StructureDefinition/Observation
Is what I've done above legal or is this something you need to drop into FHIRPath to express?
Grahame Grieve (May 18 2020 at 23:08):
it's not legal. Choice types are final, in effect; you'll have to use FHIRPath
Lloyd McKenzie (May 19 2020 at 01:29):
You should be able to specify a targetProfile for the type
Grahame Grieve (May 19 2020 at 05:26):
You mean profile not targetProfile but Age and Duration are not profiles
Chris Moesel (May 19 2020 at 12:53):
Right. At first I thought profile too, but they are specializations, not constraints, so we can't use profile. So... FHIRPath it is.
Lloyd McKenzie (May 19 2020 at 15:19):
Why are they specializations - they don't add any new elements...
Lloyd McKenzie (May 19 2020 at 15:19):
I'm pretty sure I've referenced them with profile and it's worked...
Chris Moesel (May 19 2020 at 15:33):
Why are they specializations
We just had this same exact question/conversation during our team meeting. We couldn't figure out why they are specializations either. Best we could come up w/ is that in cases where they are used as choices in core spec, it allows valueAge
and valueDuration
to be used instead of valueQuantity
-- which is probably a bit more explicit from a user perspective. But still... I'd be interested to hear the story behind it. It looks like they were constraints in DSTU2.
Lloyd McKenzie (May 19 2020 at 15:36):
@Grahame Grieve
Grahame Grieve (May 19 2020 at 19:10):
they were constraints, but that meant that when you used them, you didn't really use them. People got confused by this - for instance, a value that was a choice of Age and Duration was actually a choice of Quantity. So we changed them to specializations instead of constraints. We discussed that this meant that you couldn't do what Chris wants to do, but we felt that it wouldn't happen very often (and we were right - it was such a long time till someone tried to do it that Lloyd didn't remember the discussion)
Chris Moesel (May 19 2020 at 19:54):
And I'll admit that this didn't come up in a real world use case for us either. It came up in a fairly contrived unit test in SUSHI.
Chris Moesel (Jun 03 2020 at 18:27):
Followup question. We've established that the following is an illegal constraint because Duration
and Age
are not in the original type list (even though their parent, Quantity
, is in the type list):
{
"id": "Observation.value[x]",
"path": "Observation.value[x]",
"type": [ { "code": "Duration" }, { "code": "Age" } ]
}
It appears that if I try to do a similar thing, but with Bundle.entry.resource
instead, the IG Publisher is happy with it. For example, even though Bundle.entry.resource
only has Resource
in its type list, I can apparently constrain it to sub-types like this:
{
"id": "Bundle.entry.resource",
"path": "Bundle.entry.resource",
"type": [ { "code": "Patient" }, { "code": "Condition" }]
}
Chris Moesel (Jun 03 2020 at 18:29):
- Is that second example (w/ Bundle.entry.resource) indeed valid?
- If so, what makes the first invalid? Is it because it is a choice (e.g., the
[x]
makes the type list final)? I think this is what Graham implied, but I want to confirm before I code up SUSHI this way.
Lloyd McKenzie (Jun 03 2020 at 18:43):
@Grahame Grieve
Chris Moesel (Jun 03 2020 at 18:55):
Upon further investigation, the following ALSO does not work:
{
"id": "DeviceDefinition.quantity",
"path": "DeviceDefinition.quantity",
"type": [ { "code": "Duration" }, { "code": "Age" } ]
}
Grahame Grieve (Jun 03 2020 at 18:57):
because Observation.value has a set of concrete types, but Bundle.entry.resource has a single abstract type
Chris Moesel (Jun 03 2020 at 19:00):
Ooooohhh... is that the key? We can do it on something that is type Resource
because Resource
is abstract, but we can't do it on something like Quantity
because it is concrete? Because it can't just be due to the choice since DeviceDefinition.quantity
also does not work.
Grahame Grieve (Jun 03 2020 at 19:01):
Unless the type is abstract, the type is final
Chris Moesel (Jun 03 2020 at 19:02):
And by final
, you mean it cannot be replaced by specializations in the type list. If you want to constrain it to a specialization you have to fall back to FHIRPath invariants.
Chris Moesel (Jun 03 2020 at 19:03):
I think I understand now. Thank you, @Grahame Grieve!
Nick Freiter (Jun 12 2020 at 16:05):
@Grahame Grieve , we were under the impression that if we wanted to use FHIRPath to express on a profile that a Quantity element should be a Duration, we would place the following in the constraint
array on the Quantity type element in question:
{
"key": "dur-1",
"severity": "error",
"human": "Type is a duration",
"expression": "is(FHIR.Duration)",
}
However, this leads to an error in validation of any instance of that profile, and the error seems to be caused by the fact that the element is of type Quantity, but the FHIRPath constraint indicates it should be of type Duration. We thought this would be allowed since Duration is a child type of Quantity. We have also tried using the conformsTo
operator instead of is
, and that also leads to validation errors. Was the above not what you meant when you said we would have to use FHIRPath to constrain a Quantity to a Duration?
Grahame Grieve (Jun 12 2020 at 19:35):
it wasn't what I meant.
"expression": "is(FHIR.Duration)"
No, because that's just saying again that the type is a Duration, but it can't be since the binding is final.
Grahame Grieve (Jun 12 2020 at 19:35):
conformsTo - maybe that should work if you provide a canonical URL? but that would really be a bug on my part since it can't conform to the definition, since the definition says it's a type
Grahame Grieve (Jun 12 2020 at 19:38):
{
"key": "dur-1",
"severity": "error",
"human": "Type is a duration",
"expression": "$this.memberOf('http://hl7.org/fhir/ValueSet/all-time-units)",
}
Chris Moesel (Jun 12 2020 at 21:45):
So are you saying there is no uniform way for a profile author to succinctly say that an element of TypeA should be a specific specialization of that type? Is that intentional because a specialization can introduce new elements -- and it's really only rather unfortunate here because these specific specializations (Duration and Age) don't introduce new units (e.g., they act much more like constraints)?
Grahame Grieve (Jun 12 2020 at 21:49):
if a specialization is allowed then you can say that it must be done - exactly how you did it. But since it's not allowed, you can't satisfy that constraint
Chris Moesel (Jun 12 2020 at 21:54):
OK. I think we just got confused because Duration and Age act more like constraints, so it feels like they should be allowed, even if they're not. We'll update SUSHI to yell when an author tries to constrain a type to a specialization (if that specialization hasn't already been explicitly allowed via a choice).
Grahame Grieve (Jun 12 2020 at 21:56):
it's unfortunate, I agree, because they do feel a lot like constraints. they used to be. But people were confused by that since they couldn't listed as types in resource definitions/profiles, and didn't appear in choices.
Last updated: Apr 12 2022 at 19:14 UTC