CodeSystem constraint FHIR path expression seems to always be false

Using the base profile for CodeSystem, I came across one of the constraints with a FHIR path expression that to me sounds like it will always return false.

Take the following CodeSystem resource for example:

{
  "resourceType": "CodeSystem",
  "concept": [{
    "code": "example"
  }]
}

In the base CodeSystem profile, we have the following constraint with the FHIR path expression:

{
  "key": "csd-1",
  "severity": "error",
  "human": "Within a code system definition, all the codes SHALL be unique",
  "expression": "concept.code.combine($this.descendants().concept.code).isDistinct()",
  "xpath": "count(distinct-values(descendant::f:concept/f:code/@value))=count(descendant::f:concept)"
}

So this is using the combine(other : collection) : collection expression here. To begin, concept.code is executed first, which should return a collection of ["example"]. Next, $this.descendants().concept.code is executed, which should also return ["example"]. Next, the two results are combined, but duplicate values should not be removed. So the result of that should be ["example", "example"]. The isDistinct() function is performed last, which should return false since there are duplicates.

As I understand $this should be referring to the node in focus, which should just be the CodeSystem resource. This is because combine() doesn’t take in an input collection after some chained evaluation like other functions, rather it just works off of the focused collection.

Am I following this correctly? From what I can see, this FHIR path expression will always return false, this is because $this.descendants().concept.code will always also include concept.code. Am I missing something?

Shouldn’t the FHIR path expression instead be concept.descendants().code.isDistinct(). I feel like I am missing something about how $this or descendants() works…

1 Like

It’s not going to evaluate to true, but it’s not going to work either :frowning:

$this is going to evaluate to the code node. There are no descendants of code other than possibly id and extension, and neither of those will have children of .concept.code. So it’s not actually checking for duplicate codes as intended. What I think we should have here is:
concept.combine($this.descendants().select(concept)).code.isDistinct(). I.e. iterate through all of root-level concepts of the code system. For each concept, find all descendant elements that happen to also be concept and combine that set together with the root level concepts. Finally, for all of those concept nodes, find their child code nodes and make sure that the collection of all the codes is unique.

Can you please submit a change request for us to fix this?

Thanks for the quick reply. I agree with your solution and I think it works.

I went ahead and created a gforce account. Once approved, I’ll create the change request.

Actually, after some further review, I don’t think that solution will work. Here’s why I think so:

  • $this should refer to one item in the input collection. When doing concept.combine, all concepts will be passed into the combine function. So, if the code system had two concepts, the input collection will contain two items. When using $this, which item will it refer to? I am going off of the following paragraph from the FHIRPath specification:

http://hl7.org/fhirpath/index.html#functions

The wording of that paragraph suggests to me that $this should always operate under exactly one item. If there are multiple items, it becomes ambiguous. This is made more apparent to me where they provide an example of name.given.where, which iterates over each .given, one item at a time.

  • I don’t believe we need to use the combine function at all. I believe my previous proposal will work: concept.descendants().code.isDistinct().

EG: concept.descendants() will take all concepts, and then retrieve their descendant nodes, which should contain all concept.code, concept.concept.code, concept.concept...concept[n].code. From that collection, we retrieve the code portion: .code. This will now give us all primitive codes. From that collection we can do .isDistinct().

Taking an example:

{
  "resourceType": "CodeSystem",
  "concept": [{
    "code": "example1",
    "concept": [{
      "code": "example2"
    }, {
      "code": "example3"
    }]
  }]
}
  1. concept.descendants() output:
[
    {"code": "example1"},
    {"concept": [{"code":"example2"},{"code":"example3"}]},
    {"code": "example2"},
    {"code": "example3"}
]
  1. concept.descendants().code (Only retrieve the code portion of previous collection). Output:
[
    "example1", "example2", "example3"
]
  1. concepts.descendants().code.isDistinct() output:
[
    true
]

Any thoughts on that?

Actually, changes are now tracked in Jira (http://jira.hl7.org), so you’ll need to register there.

concept.descendants().code doesn’t filter the descendants to find those that are of type code. Instead it would find descendants of concept and then find child nodes of that called code - so in your example, it would grab example2 and example3 (from the second row) but would not include example1, example2, or example3 from rows 1, 3 or 4.

To filter the descendants, you have to use select()

The second issue is that your proposed expression would also match on CodeSystem.concept.property.code, which would be inappropriate - because there’d be lots of duplication of property codes.

Ah, I didn’t factor in concept.property.code.

The question I have is the use of $this in your example. I think concept.combine($this. is invalid because CodeSystem.concept can have more than one item, and $this should operate on only one item. This means that .combine($this should throw an error if more than one item is being passed into the combine function (which is possible since CodeSystem.concept is an array) Am I understanding that right?

Because of that, can we instead do something like this?

concept.code.combine(%resource.concept.descendants().select(concept).code).isDistinct()

EDIT: Actually, the above can be shortened down (without the select() function) I believe to: concept.code.combine(%resource.concept.descendants().concept.code).isDistinct()

.combine() operates on each item in the base collection (CodeSystem.concept in this case). $this is set to each item in the collection in turn - and the result is unioned together to produce the result collection - in no particular order.

.combine() operates on each item in the base collection

If this is true, then your solution works.

However, I can’t seem to find in the specification where it states that .combine() operates on each item. In the FHIR path specification, functions such as .select(), .all(), .exists(), etc. explicitly state that the function is operated for each item in the input collection. In contrast, the .combine() function is worded in a way that to me suggests it is not operated for each item in the input collection, rather it just takes all of the input collection, without operating in a “for each” style: http://hl7.org/fhirpath/#combineother-collection-collection

Feel free to raise a change request to clarify that behavior. (It certainly works in the reference FHIRPath implementations or they would have blown up when validating instances in the spec.)