FHIR Chat · FHIRPath · implementers

Stream: implementers

Topic: FHIRPath


view this post on Zulip Admin (Nov 20 2015 at 09:44):

JS implementation coming along.

view this post on Zulip Josh Mandel (Nov 20 2015 at 10:12):

Whoa, hey Grahame!

view this post on Zulip nicola (RIO/SS) (Nov 20 2015 at 11:23):

Demo was updated - http://niquola.github.io/fhirpath-demo/#/

view this post on Zulip nicola (RIO/SS) (Nov 20 2015 at 11:29):

Here is syntax of jsquery from postgresql guys - https://github.com/postgrespro/jsquery

view this post on Zulip Josh Mandel (Nov 20 2015 at 11:29):

Oh yeah, I forgot about that. The symbols are pretty cryptic at first look ;-)

view this post on Zulip Josh Mandel (Nov 20 2015 at 11:32):

(deleted)

view this post on Zulip Grahame Grieve (Nov 20 2015 at 11:45):

hi

view this post on Zulip Josh Mandel (Nov 20 2015 at 11:45):

@Grahame Grieve I don't understand when you managed to sign up and join. I was in the room with you the whole time.

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:37):

I still don't understand `.distinct(path,path). Can you help with an example, @Grahame Grieve

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:40):

ok, so there's a rule: if you say that an element has more than one type, then the different types must have a different code, or if you have more than one type with the same code, they have to have different profiles

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:41):

e,g. you couldn't say element value[x] choice of boolean | boolean

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:41):

but you might say element value[x] : choice of Reference(Patient) | Reference(Person)

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:42):

hence, invariant on ElementDefinition:

type.distinct(code,profile)

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:44):

So that's the use case. Now help me understand how it applies, as a rule, to data. Each of the two path arguments to distinct() returns a collection. How do I decide, based on those two collections, whether distinct() returns [true] or [false] ?

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:45):

Also, @nicola and I would love to demo our JS FHIRPath implementation in the demo session, if we can?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:46):

Sounds like a good to me, but Ewout controls things

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:46):

my rule for distinct: if all the collections are equal, they are not distinct

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:47):

collections are equal if they are the same length, and if all the items in order equal each other

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:47):

OK. So why can't distinct() be replaced with != calls?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:47):

clearly, there's an order problem there

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:47):

(Also, @nicola says we're already on the list. Shows you what I know.)

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:47):

huh? how would that work?

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:47):

Order problefm?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:48):

for that use cases above, order doesn't matter - they can't differ only in order

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:48):

So... sort then do a comparison, is the basic idea? We'll need to specify that.

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:48):

we don't have sort. I don't know how to sort some of those things

view this post on Zulip nicola (RIO/SS) (Nov 20 2015 at 12:48):

distinct is overlapping 'SQL distinct', so someone would think that distinct is a filter

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:49):

well, I'm open to name questions

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:49):

I'd say say for =, to do something like:

ElementDefinition.type.where(code = profile).empty()

view this post on Zulip nicola (RIO/SS) (Nov 20 2015 at 12:49):

intersect?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:49):

that's a total different rule

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:49):

OK, then I'm still not getting it.

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:50):

Intersect and union are nice terms that people understand

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:50):

you rule says that for the types, none of them can exist where the type.code = type.profile

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:51):

my rule is different to that - all the types must be different from each other, in that they must have different types

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:51):

I could try something like this:

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:52):

Hmm. I guess I need a passing/failing example to understand what you mean.

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:52):

pass:
Element xxx.value[x]
type : boolean
type : integer

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:52):

fail:

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:52):

Element xxx.value[x]
type: boolean
type: boolean

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:52):

pass:

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:53):

Where does the word "profile" appear in those? (The second argument to distinct(type, profile) in your example path)?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:53):

Element xxx.value[x]
type : Reference, profile = Patient
type: Reference, profile = Person

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:53):

fil:

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:53):

fail:

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:53):

Element xxx.value[x]
type : Reference, profile = Patient
type: Reference, profile = Patient

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:54):

Um. I'm just not getting what this operation does.

view this post on Zulip nicola (RIO/SS) (Nov 20 2015 at 12:54):

.type() function?

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:55):

No, @Grahame Grieve is talking about a simple json property of ElementDefinition whose name just happens to be type.

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:55):

it says that none of the items in the collection can have the same values for set of nominated expressions as any other item in the collection

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:56):

What does it means to "have.... values for [a]... set of... expressions"?

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:56):

here's my implementation: (in pascal):

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:56):

Great ;-)

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:56):

var
table : array of array of TFHIRBaseList;
i, j : integer;
base : TFHIRBase;
distinct : boolean;
begin
distinct := Context.Count <= 1;
try
SetLength(table, context.Count);
for i := 0 to context.Count - 1 do
begin
SetLength(table[i], exp.Parameters.Count);
base := context[i];
for j := 0 to exp.Parameters.Count - 1 do
table[i][j] := evaluate(base, exp.Parameters[j]);
end;
for i := 0 to context.Count - 1 do
for j := i+1 to context.Count - 1 do
if areDistinct(table[i], table[j]) then
begin
distinct := true;
break;
end;
finally
for i := 0 to context.Count - 1 do
for j := 0 to exp.Parameters.Count - 1 do
table[i][j].Free;
end;
result := TFHIRBaseList.Create;
result.Add(TFhirBoolean.Create(distinct));

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:56):

lose the indent... ouch

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:56):

Add ``` before/after your code block for code fomatting

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:57):

...
function TFHIRPathEvaluator.funcDistinct(resource : TFHIRResource; originalContext, context: TFHIRBaseList; exp: TFHIRPathExpression): TFHIRBaseList;
var
table : array of array of TFHIRBaseList;
i, j : integer;
base : TFHIRBase;
distinct : boolean;
begin
distinct := Context.Count <= 1;
try
SetLength(table, context.Count);
for i := 0 to context.Count - 1 do
begin
SetLength(table[i], exp.Parameters.Count);
base := context[i];
for j := 0 to exp.Parameters.Count - 1 do
table[i][j] := evaluate(base, exp.Parameters[j]);
end;
for i := 0 to context.Count - 1 do
for j := i+1 to context.Count - 1 do
if areDistinct(table[i], table[j]) then
begin
distinct := true;
break;
end;
finally
for i := 0 to context.Count - 1 do
for j := 0 to exp.Parameters.Count - 1 do
table[i][j].Free;
end;
result := TFHIRBaseList.Create;
result.Add(TFhirBoolean.Create(distinct));
end;
...

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:57):

And do ```pascal at the beginning for syntax highlighting

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:57):

function TFHIRPathEvaluator.funcDistinct(resource : TFHIRResource; originalContext, context: TFHIRBaseList; exp: TFHIRPathExpression): TFHIRBaseList;
var table : array of array of TFHIRBaseList;
i, j : integer;
base : TFHIRBase;

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:58):

do what?

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:58):

    ```pascal
   some
   code
   here
   ```

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:58):

function TFHIRPathEvaluator.funcDistinct(resource : TFHIRResource; originalContext, context: TFHIRBaseList; exp: TFHIRPathExpression): TFHIRBaseList;
var
  table : array of array of TFHIRBaseList;
  i, j : integer;
  base : TFHIRBase;
  distinct : boolean;
begin
  distinct := Context.Count <= 1;
  try
    SetLength(table, context.Count);
    for i := 0 to context.Count - 1 do
    begin
      SetLength(table[i], exp.Parameters.Count);
      base := context[i];
      for j := 0 to exp.Parameters.Count - 1 do
        table[i][j] := evaluate(base, exp.Parameters[j]);
    end;
    for i := 0 to context.Count - 1 do
      for j := i+1 to context.Count - 1 do
        if areDistinct(table[i], table[j]) then
        begin
          distinct := true;
          break;
        end;
  finally
    for i := 0 to context.Count - 1 do
      for j := 0 to exp.Parameters.Count - 1 do
        table[i][j].Free;
  end;
  result := TFHIRBaseList.Create;
  result.Add(TFhirBoolean.Create(distinct));
end;

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:58):

Backticks

view this post on Zulip Josh Mandel (Nov 20 2015 at 12:58):

You can edit your last message :-)

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:59):

great. and also this:

view this post on Zulip Grahame Grieve (Nov 20 2015 at 12:59):

function TFHIRPathEvaluator.areDistinct(a1, a2 : array of TFHIRBaseList) : boolean;
var
  i : integer;
  res : TFHIRBaseList;
begin
  result := false;
  for i := 0 to length(a1) - 1 do
  begin
    res := opEquals(a1[i], a2[i]);
    try
      if not convertToBoolean(res) then
      begin
        result := true;
        exit;
      end;
    finally
      res.Free;
    end;
  end;
end;

view this post on Zulip Grahame Grieve (Nov 20 2015 at 13:00):

does this help?

view this post on Zulip Josh Mandel (Nov 20 2015 at 13:03):

That helps a ton, in that the code is totally unambiguous :-) (Even if I don't really read Pascal.)

view this post on Zulip Josh Mandel (Nov 20 2015 at 13:04):

Also, you gotta admit the fact that pygments handles syntax highlighting for pascal is pretty cool.

view this post on Zulip Grahame Grieve (Nov 20 2015 at 13:04):

yeah, I figured that piece of pascal wasn't too pascal specific

view this post on Zulip Grahame Grieve (Nov 20 2015 at 13:04):

yes, the syntax highlighting is sensational

view this post on Zulip Josh Mandel (Nov 20 2015 at 13:07):

(And a feature not supported by Slack ;-))

view this post on Zulip Josh Mandel (Nov 20 2015 at 13:08):

BTW, @nicola's demo that we'll show is at https://niquola.github.io/fhirpath-demo

view this post on Zulip James Agnew (Nov 20 2015 at 13:22):

view this post on Zulip James Agnew (Nov 20 2015 at 13:22):

oops

view this post on Zulip Email Gateway (Nov 20 2015 at 15:01):

Just testing e-mail integration with updated cron job.

view this post on Zulip Josh Mandel (Nov 20 2015 at 23:41):

Published an npm package fhirpath.js — and a set of test cases

view this post on Zulip Josh Mandel (Nov 21 2015 at 00:22):

  • Added support for $context.
  • And support for custom lookup constants

view this post on Zulip Grahame Grieve (Nov 21 2015 at 13:27):

need to be specific in the spec that you can't use the characters #13, #10 and #9 in a string literal

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:02):

Josh, are you going to implement FHIR path in XML as well as JSON?

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:02):

Wasn't planning to; I'd say just convert the XML to JSON first if you want to use fhirpath.js.

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:02):

if you are, there's a gotcha in XML like there is in JSON - the way resources are included at DomainResource.contained and Bundle.entry

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:03):

then you don't need to worry about ti

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:03):

what's the gotcha there? (I do want to understand it, at least :-))

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:04):

well, we have

  <contained>
   <[resource]>
   </resource]>   
 </contained>

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:04):

The inner element is XML only, and not included in the path statement

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:19):

Sorry, you're saying that in the following:

<Patient>
  <contained>
    <Practitioner>
      <name><text>John</text></name>
    </Practitioner>
  </contained>
</Patient>

to get "John", I'd evaluate Patient.contained.name instead of Patient.contained.Practitioner.name ?

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:20):

yes, that's right.

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:20):

the path needs to be the same for json and xml

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:22):

Agreed on that point, but I'd kind of think that this query is supposed to work with or without the word Practitioner.

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:22):

hah. You might have missed our earlier discussion on that

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:23):

We currently allow Type.path only at the entry point, where it stands as a type filter. We allow that because we do this on 90+% of the paths that we have

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:23):

Sounds like I did. Skype, or here? Was there a short conclusion?

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:23):

Yeah, OK. But it's not really *doing* anything, is what you're saying.

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:23):

I argued that we should allow this internally in the path as well, so you could have Observation.value[x].CodeableConcept.coding

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:24):

but James (mainly) argued back say that was counter-intuitive and also that we already have Observation.valueCodeableConcept

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:24):

Ha, argh. That's even worse than I imagined; at least the resource types manifest explicitly in JSON (unlike data element ntypes)

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:24):

and even then this path is not the same as that other path

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:25):

so I ended up agreeing with James, and we only allow Type. at the entry point

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:25):

and so Patient.contained.Practitioner.name is not valid

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:26):

Well, there was a potential middle ground (that Type is allowed at any resource entry point, rather than just the top-level resource entry point).

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:26):

we didn't discuss that

view this post on Zulip Josh Mandel (Nov 24 2015 at 03:26):

I have no strong feeling except that Observation.value[x].CodeableConcept is an abomination :-)

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:27):

James may have an opinion on the middle ground

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:27):

or others....

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:27):

@James Agnew - just seeing how tagging works

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:28):

even given the middle ground, it would still be a special case gotcha

view this post on Zulip Grahame Grieve (Nov 24 2015 at 03:29):

but it's good that you only mild feelings about Observation.value[x].CodeableConcept ;-)

view this post on Zulip Grahame Grieve (Nov 25 2015 at 23:49):

so Josh, my implementation of distinct was wrong. here's the debugged version:

view this post on Zulip Grahame Grieve (Nov 25 2015 at 23:49):

view this post on Zulip Grahame Grieve (Nov 25 2015 at 23:50):

function TFHIRPathEvaluator.areDistinct(a1, a2 : array of TFHIRBaseList) : boolean;
var
  i : integer;
  res : TFHIRBaseList;
begin
  result := false;
  for i := 0 to length(a1) - 1 do
  begin
    res := opEquals(a1[i], a2[i]);
    try
      if not convertToBoolean(res) then
      begin
        result := true;
        exit;
      end;
    finally
      res.Free;
    end;
  end;
end;

function TFHIRPathEvaluator.funcDistinct(ctxt : TFHIRPathExecutionContext; context: TFHIRBaseList; exp: TFHIRExpressionNode): TFHIRBaseList;
var
  table : array of array of TFHIRBaseList;
  i, j : integer;
  base : TFHIRBase;
  distinct : boolean;
begin
  distinct := Context.Count <= 1;
  try
    SetLength(table, context.Count);
    for i := 0 to context.Count - 1 do
    begin
      SetLength(table[i], exp.Parameters.Count);
      base := context[i];
      for j := 0 to exp.Parameters.Count - 1 do
        table[i][j] := evaluate(ctxt, base, exp.Parameters[j]);
    end;
    distinct := true;
    for i := 0 to context.Count - 1 do
      for j := i+1 to context.Count - 1 do
        if not areDistinct(table[i], table[j]) then
        begin
          distinct := false;
          break;
        end;
  finally
    for i := 0 to context.Count - 1 do
      for j := 0 to exp.Parameters.Count - 1 do
        table[i][j].Free;
  end;
  result := TFHIRBaseList.Create(TFhirBoolean.Create(distinct));
end;

view this post on Zulip Josh Mandel (Nov 26 2015 at 05:45):

Can you clarify what the error was, and whether niquola.github.io/fhirpath-demo/#/ is susceptible?

view this post on Zulip Grahame Grieve (Nov 26 2015 at 06:39):

The error was that I returned true if any of them were differentiable, not all of them

view this post on Zulip Grahame Grieve (Nov 26 2015 at 06:39):

looks like your implementation is right to me

view this post on Zulip Josh Mandel (Nov 26 2015 at 12:12):

Gotcha - thanks!

view this post on Zulip Grahame Grieve (Nov 28 2015 at 04:53):

Is it worth translating FHIR path expressions to Javascript equivalents?

view this post on Zulip Josh Mandel (Nov 28 2015 at 13:41):

Can you give an example of what you mean? I mean, for a vaguely complicated one? Is the idea that you want to return something human-readable, or something eval-able? If the latter, why not just return the whole library in a self-evaluating function, with the input already bound?

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:14):

i think I mean the second - just generate a javascript function that returns the output if the query

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:15):

OK -- and the function could be huge? What would you do with said function (i.e. why would you use it instead of just calling the fhirpath evaluator)?

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:15):

well, it could be several sub-functions, and a small library too.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:16):

A pattern for this in JS would be just:

function withExpression(expr){
  return function(target){
    return fhirpath.evaluate(expr, target);
  }
}

(Note: this may reverse the order of args from what my actual library expects.)

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:16):

and your second question is the on I am asking myself - is it better?

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:16):

So you can pre-bind the expression and get a function you can run against any target.

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:17):

well, not against any target, I think. I would have to generate for specific target - e.g. a function might look different run against a patient instead of a practitioner

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:17):

By "target" I meant a specific resource (i.e. not "Patient", but a specific patient resource)

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:17):

sure. that would be the idea.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:17):

Currently the evaluator takes a path and a target as inputs.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:18):

I think you're saying you want a function that just takes a target, and has the path baked-in.

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:18):

but if you have a javascript evaulator, is pre-generating code instead better for some kind of conditions?

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:18):

The snippet above shows you how to do this.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:18):

I mean, really optimized code maybe. But it sounds like you're trying to solve a performance problem.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:19):

There are lots of thing we could do to just make the evlauator faster.

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:19):

(Like starting from a bunch of hard test cases and profiling it, for a start.)

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:19):

if really optimised code is the only reason that would be better, it wouldn't be worth doing

view this post on Zulip Grahame Grieve (Nov 28 2015 at 14:20):

I had planned to do it prior to you writing the evaluator, but now I'm thinking it would be a waste of time

view this post on Zulip Josh Mandel (Nov 28 2015 at 14:29):

Fair enough -- sounds like, effectively, a different style for writing an evaluator.

view this post on Zulip Grahame Grieve (Nov 28 2015 at 21:31):

do we need to be explicit that '=' is not pointer based but property based?

view this post on Zulip Grahame Grieve (Nov 28 2015 at 21:47):

but are these different:

<code id="1">
<system value="http://loinc.org"/>
<code value="23"/>
</code>

<code id="2">
<system value="http://loinc.org"/>
<code value="23"/>
</code>

view this post on Zulip Grahame Grieve (Nov 28 2015 at 21:47):

?

view this post on Zulip Josh Mandel (Nov 28 2015 at 22:05):

I'd like to say they're the same. Otherwise the language is going to get heavy/hard-to-use for dealing with special cases.

view this post on Zulip Grahame Grieve (Nov 29 2015 at 00:14):

I'd like them to be the same, but on what grounds do you exempt things from the equality test? I guess, tad things that are format specific, and not described in the logical model. I'll update the documentation accordingly

view this post on Zulip Grahame Grieve (Nov 29 2015 at 00:17):

Except that id is described explicitly

view this post on Zulip Grahame Grieve (Nov 29 2015 at 00:39):

And what about resources? Are 2 resources with the same content and different ids equal? I think not

view this post on Zulip Grahame Grieve (Nov 29 2015 at 11:04):

I'm just finishing off my Fhir path implementation - been working on it all week. I've been fixing my implementation, the Fhir path statements, the invariants, and the example resources

view this post on Zulip Grahame Grieve (Nov 29 2015 at 11:06):

What would be really really nice would be to able to indicate in the Fhir path expression a particular test to inject into the error message

view this post on Zulip Grahame Grieve (Nov 29 2015 at 11:06):

It's kind of hard to describe, and it wouldn't always be possible, but sometimes it would save such a lot of debugging - and I can debug. Lots of people wouldn't be

view this post on Zulip Grahame Grieve (Nov 29 2015 at 11:07):

Maybe a .log()? Or appending ^ to an operation?

view this post on Zulip Grahame Grieve (Nov 29 2015 at 11:08):

I'm down to 135 errors...

view this post on Zulip Ewout Kramer (Nov 30 2015 at 15:25):

Is it worth translating FHIR path expressions to Javascript equivalents?

I am doing this in the .NET implementation. But there, I'd need to find a plausible name for the "." operation --> moving to a child. So, "Patient.name.where().count()" would now turn into context.Children("name").Where(p=>p.some condition).Count()

view this post on Zulip Ewout Kramer (Nov 30 2015 at 15:26):

So you can pre-bind the expression and get a function you can run against any target.

And the .NET parses a FhirPath expression and turns it into a function that you can use to run that expression against an instance. So, in fact you'd get a pre-compiled evaluator based on that expression. Under the hood, it dynamically creates a function that does the calls as I showed above.

view this post on Zulip Grahame Grieve (Dec 01 2015 at 03:03):

well, is that based on raw JSON, or on yhe .net object model?

view this post on Zulip Ewout Kramer (Dec 01 2015 at 08:21):

It's built on top of an abstract model representing "FHIR data", which is mostly nested dictionaries, except that elements may repeat

view this post on Zulip Grahame Grieve (Dec 01 2015 at 12:25):

so you can run javascript against that? is this using the dotnet javascript infrastructure? why not just generate C#?

view this post on Zulip Ewout Kramer (Dec 03 2015 at 19:22):

Sorry, missed this reply! No, it's all .NET based, so there's a .NET parser for FhirPath which produces a dynamically created function that is the parser, which you can repeatedly call without having to parse again. But it runs against an abstract model of nested dictionaries, not against json or xml per se.

view this post on Zulip Ewout Kramer (Dec 22 2015 at 10:46):

If I do Patient.name.substring(2,4) (instead of Patient.name.text.substring()), what will your FhirPath evaluators do?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 10:49):

And, presuming my names look like integers, will Patient.name.text.asInteger() produce an array or integers? What if one of my names is not parseable as an integer?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 10:54):

"This means that Patient.telecom.system = 'phone' will return an empty collection if there is more than one telecom with a use". Since the "==" operator returns a boolean, I assume it is supposed to say "it returns False if there is more than one telecom with a use" ?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 10:58):

Or do the operations return a collection? E.g. the "==" returns a collection with { True } as the single element? In which case this is valid:
(Patient.name.use == 'official').count() ?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 10:59):

Patient.name.substring(2,4) would be an empty collection

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:00):

"* this and the other 3 order related operations can only be used for strings, codes, integers, and decimals" I don't think "code" is a type in FhirPath....It also means the comparison operations cannot be used on dates?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:01):

we could remove code from that list - I wrote that before I sorted out the base types

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:01):

I avoided oprations on dates, since they're so tricky. A yagni thing...

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:02):

asInteger for me only returns an integer on a single string. else it will be an empty collection

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:03):

yes Patient.telecom.system = 'phone' should be false not empty collection

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:03):

I have operations returning a collection with a single value. it's usually a boolean

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:03):

case op of
poEquals: result := TAdvStringSet.Create('boolean');
poEquivalent: result := TAdvStringSet.Create('boolean');
poNotEquals: result := TAdvStringSet.Create('boolean');
poNotEquivalent: result := TAdvStringSet.Create('boolean');
poLessThen: result := TAdvStringSet.Create('boolean');
poGreater: result := TAdvStringSet.Create('boolean');
poLessOrEqual: result := TAdvStringSet.Create('boolean');
poGreaterOrEqual: result := TAdvStringSet.Create('boolean');
poIn: result := TAdvStringSet.Create('boolean');
poPlus: result := TAdvStringSet.Create('string');
poMinus: result := TAdvStringSet.Create('string');
poConcatenate: result := TAdvStringSet.Create('boolean');
poOr: result := TAdvStringSet.Create('boolean');
poAnd: result := TAdvStringSet.Create('boolean');
poXor: result := TAdvStringSet.Create('boolean');
poImplies: result := TAdvStringSet.Create('boolean');
poUnion: result := TAdvStringSet.Create(left, right);
else
raise Exception.Create('not done yet');
end;

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:06):

technically this is valid : (Patient.name.use == 'official').count() ? - return value will be always be one

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:07):

What I find confusing is that we use the term "collection" in the FhirPath spec. Json has a collection, but Xml does not. And we have not described a "logical" FHIR model so far. So, since every operation returns "a collection of Elements of various types", saying that the behaviour for "==" depends on the fact that something is a "collection" ("comparison is order dependent") does not sound right. I think the text should say: "If == operates on collections with more than one element, order is significant" ?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:07):

I am assuming "a collection" means "a list of elements matching the expression so far"

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:08):

xml has a logical collection

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:08):

and your assumption is correct

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:08):

Sure, but Patient.name returns "a collection of name elements", not a single name which is a collection!

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:09):

and your assumption is correct
Great.

So, maybe I should go through the spec for FhirPath and make sure that everywhere we say "collection" we mean the resultset, and not "a repeating element" ?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:13):

well, umm, ok. I guess I don't find any confusion here, so it seems like a backwards step to me

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:14):

because I don't know what this means: "a collection of name elements", not a single name which is a collection!

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:15):

I also have the feeling the spec makes a subtle distinction between selecting something that originates in an Element, and something that does not. E.g. If I'd execute myPatient.Evaluate("Patient.name"), I would get back a collection of Elements, which trace back to the original elements in the POCO "myPatient". But if I do, e.g. substring() on a collection, I'd get a set of strings that have no origin in the original data, so cannot be used to select elements from the POCO. Is FhirPath supposed to make this possible?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:21):

"All elements in a collection will always have a FHIR type"

Are we saying FhirPath is always evaluated against a typed model? Is that really necessary? This means we need the full StructureDefinition parser machinery to evaluate FhirPath? Or always evaluate it against an in-memory POCO that has type information? I think we should not do that!

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:21):

I don't understand either of these either

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:22):

the execution operates against an object model, and the outcomes are always objects

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:22):

some queries will return you objects that are also in the original object graph, and some will return new objects. I care about this when presenting outcomes, for instance, but it makes no difference to the evaluation engine

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:23):

Why would that be? You mean high-performance evaluators need to read all instance data into an object model first?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:23):

again, I don't know what you mean

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:24):

you do need some type information to execute properly, yes

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:24):

I am not building the .NET FhirPath evaluator against the .NET POCO model, since why would you read data into a POCO if you just want to validate it against FhirPath rules?

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:24):

And also, doing reflection on a POCO is slow.

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:24):

I think you're doing it wrong. I'll tell you why

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:25):

your users will mostly use FHIRPath against POCO models.

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:25):

it's only validation where you think ohterwise, and that's a special case that's not the general case

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:25):

here's how my engines work:

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:25):

- they don't know anything about FHIR types. They operate on collections of FHIR base

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:25):

Base object

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:26):

which comes fom the POCO

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:26):

POJO for me

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:26):

I have a method for asking the base object for the value of a property

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:27):

there's two instantiations of that - one that uses the built in POJO property accessor, and one that users the validation framework

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:27):

if reflection is slow, generate something faster.

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:27):

that's not magic, and that's what I do for pascal and java - has heaps of uses, being able to iterate the properties

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:28):

there's also a method for asking a base type what the type of a property is, but you only need that if you want to check type safety

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:29):

I don't think we should let the design of FhirPath be influenced on how WE or you generate stuff. Unless we REALLY REALLY need typed information in FhirPath we should avoid it. Where do we need type info in FhirPath?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:29):

the design of it is not influenced by how you generate stuff.

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:30):

here's where I use the type information

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:31):

Well, yes, you are assuming you have type information around in a efficent way. Which I *might* include in my implementation if necessary, but it comes at a cost.

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:31):

we say that if the context is Observation, you can do either code.xx or Observation.code.xx

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:32):

I need type information here to allow me to safely ignore the Observation. bit

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:32):

I need type information when checking type safety, but you don't need to do that

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:33):

I need to be able to list all the children or descendents of an object. I use property iterators to do that. that may or may not be type information, depending on your context

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:33):

or I get a property by name. however that happens; that's an interface for me

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:38):

So, if that's the list, having a type around is optional. Which is fine, it matches my usecase. In fact, I now parse xml/json data to a tree-representation. I can "parse" POCO's to the same tree-representation. Then, I can "annotate" this tree with type information from a StructureDefinition (when it was parsed from a POCO, I don't need to do this -> the information is present in the POCO model). So, my tree (on which the FhirPath executes) *may* have type information to give better validation or warnings. In any case, I don't think that so far we should require having types in FhirPath.

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:40):

I got into this when reading about "datetime", which is sometimes mentioned as a type and sometimes it is not. The constant <2015> in a FhirPath expression can currently be both an integer and a datetime I guess, which is what triggered this. Certainly after reading: "The evaluation engine will automatically elevate constants to the right FHIR type."..... I am saying we should not put this in the spec.

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:41):

(Xpath1 worked perfectly without typed information, and we won't try to go where xpath2 went...)

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:41):

I don't see how we can not put it in the spec, and xpath certainly does have types at the primitive level

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:42):

where's the spec again?

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:43):

there's no date type

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:43):

I don't see how those base types are ambiguous or problematic

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:46):

there's one other place I need type information - I need to know whether the object is a primitive or not, and which of the base data types it maps to

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:46):

that's fine on the JSON implementation, but needs type information on xml...

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:47):

There are only 5 basic types in FHIRPath: boolean, string, integer, decimal, and datetime

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:47):

xpath certainly does have types at the primitive level

Sure, and we can keep that, since I can derive that (just like xpath) from the notation of the constants in an expression

view this post on Zulip Ewout Kramer (Dec 22 2015 at 11:48):

And "datetime" can just be a year so, you can have confusion between a datetime just being the year and an int..

view this post on Zulip Grahame Grieve (Dec 22 2015 at 11:49):

hm I read the wrong list. ok, there is ambiguity with regard to a year only. Its' going to be an integer. tough

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:00):

Maybe we should have an explicit syntax for datetime, e.g. #2015#

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:01):

Anyway, I am updating the document to reflect some of our discussion....(not the requirements on typeinfo, though ;-)

view this post on Zulip Grahame Grieve (Dec 22 2015 at 12:04):

well, we don't even say whether date time is a string or not

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:04):

if the right collection is a URI, and it refers to a value set, value set membership testing will be performed

I think we'd better define an explicit operation for this, instead of overloading the IN operation...

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:04):

No, we don't say that. We do say all primitives have a string representation.

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:05):

E.g. the length() operation is dependent on this

view this post on Zulip Grahame Grieve (Dec 22 2015 at 12:05):

yes it's in those that I need to know whether there's a primitive to evaluate on

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:09):

I have updated some of the text of the FhirPath spec to be more elaborate about where we return collections and what asInteger and substring() do when they are executed on a collection with multiple values.

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:11):

I wonder whether Josh/Nikolai have type information...I think they are parsing the json, so they recognize the basic json types, no more...

view this post on Zulip Grahame Grieve (Dec 22 2015 at 12:11):

right, They probably haven't run into the date issue. which I haven't either, actually

view this post on Zulip Grahame Grieve (Dec 22 2015 at 12:12):

and they would need special logic for the Observation. thing

view this post on Zulip Ewout Kramer (Dec 22 2015 at 12:14):

Ah! The fun of actually implementing what we've written....as usual that's when things come up...

view this post on Zulip Grahame Grieve (Dec 22 2015 at 12:16):

well, I'll spend some time tomorrow looking into the date question

view this post on Zulip Ewout Kramer (Dec 23 2015 at 11:55):

What's the desired behaviour for Patient.name.use.something? An empty set, or an error that "use" does not have children to select?

view this post on Zulip Grahame Grieve (Dec 23 2015 at 12:10):

empty set

view this post on Zulip Grahame Grieve (Dec 23 2015 at 12:11):

I will make a compile error

view this post on Zulip Ewout Kramer (Jan 04 2016 at 14:21):

What's the behaviour of your fhirpath evaluator when you try to "+" collections with > 1 element or incompatible types?

view this post on Zulip Josh Mandel (Jan 05 2016 at 15:59):

... empty collection?

view this post on Zulip Grahame Grieve (Jan 05 2016 at 19:53):

yes, empty collection

view this post on Zulip Ewout Kramer (Jan 06 2016 at 07:44):

Our grammar only has a notation for "decimal", but our type system distinguishes intergers and decimals. So does the evaluation of .valueQuantity.value = 4 (comparing decimal and integer?) differ from .valueQuantity.value = 4.0? Are both regarded as comparisons between decimals? And for .multipleBirthInteger = 4 and 4.0? Are you using the type of the (Typed) element to cast the constant to the right type?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 07:49):

What's the difference between "aadf" + "qewr" and "aadf" & "qewr" ?

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:01):

there's no difference, but it might ne redudant. I added + and & before we really had control over primitives

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:01):

so maybe it isn't needed now?

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:01):

decimal and integer - I don't think the difference matters anywhere?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:02):

Well, we explicitly mention the two as separate types in FhirPath, so if it doesn't matter, should we remove "integer" as a separate type and just have "decimal" ?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:03):

Or does that introduce problems with the comparison operators?

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:03):

it might.

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:03):

integers are decimals with fixed precision

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:03):

I'm busy today and tomorrow. I'll review this on the plane - is that ok?

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:04):

tomorrow is a big day - oldest daughter's 18th birthday

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:04):

Of course. No hurry.

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:04):

So, I take it you are on a plane back home ;-)

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:04):

a few formalities to go through

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:04):

dirvers license!

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:05):

no, I'm home, been home for a few weeks

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:05):

leave in 36 hrs

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:05):

That's ok. I have a few more suggestions to talk through now I have almost fully implemented fhirpath on .net...

view this post on Zulip Grahame Grieve (Jan 06 2016 at 09:06):

ok

view this post on Zulip Ewout Kramer (Jan 06 2016 at 09:43):

Our grammar currently also allows 4 > 5 <= 6. I think that's an oversight...

view this post on Zulip Grahame Grieve (Jan 06 2016 at 10:58):

how does it allow that?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 11:34):

expression = term (righthand)*
righthand = op term | "." function

term op term op term op term, where op also includes = etc.

view this post on Zulip Grahame Grieve (Jan 06 2016 at 18:44):

yes I suppose it does. Is it a problem that you can string together some non-sensical operations? we'll complicate the grammar immensiely if we try to make it explicit which operations are allowed in sequence or not

view this post on Zulip Ewout Kramer (Jan 06 2016 at 19:29):

ACtually, no. It's just that the expression turns into a boolean, like 5 > 6 = true != false (left associative)

view this post on Zulip Grahame Grieve (Jan 06 2016 at 19:29):

yes there's lots of valid uses

view this post on Zulip Ewout Kramer (Jan 06 2016 at 20:58):

What about Patient.identifier.where(use = 'official') = Patient.identifier.skip(1) ?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 20:59):

Can you 'restart' the context to Patient like this? Or you'd need $parent?

view this post on Zulip Ewout Kramer (Jan 06 2016 at 21:01):

Well, it works in my parser and looks logical.

view this post on Zulip Grahame Grieve (Jan 06 2016 at 21:53):

that's ok. "Patient." is a null thing that is allowed to appear at the start of an expression at the root context

view this post on Zulip Grahame Grieve (Jan 06 2016 at 21:53):

all expressionsi in an operation have the same context.

view this post on Zulip Grahame Grieve (Jan 06 2016 at 21:53):

so that's not restarting the context

view this post on Zulip Grahame Grieve (Jan 06 2016 at 22:10):

sorry, all expressions in a set linked by operators

view this post on Zulip Ewout Kramer (Jan 07 2016 at 09:43):

No, you're right, thwo whole expression runs in the same context. My code was smarter than my brain at that time.

view this post on Zulip Ewout Kramer (Jan 07 2016 at 13:45):

I think we should rename the $parent axis to $parents, since -using the | operator for example- you could combine nodes from different part of a tree, so you can have multiple different parents...

view this post on Zulip Ewout Kramer (Jan 07 2016 at 13:47):

It's also true, that when you have combined trees with | ** can result in duplicate nodes...

view this post on Zulip Ewout Kramer (Jan 07 2016 at 15:21):

Yeah. The | operator can also cause you to have a focus with both "values (primitive elements)" and "elements", which makes the interpretation of asInteger() a bit ambiguous. Contains a "single value" is different from contains a single element...

view this post on Zulip Ewout Kramer (Jan 14 2016 at 21:16):

[13-1-2016 20:29:31] * Ewout Kramer added Bryn Rhodes, Grahame Grieve *
[13-1-2016 20:29:44] Ewout Kramer: Hi Bryn. Reading through the thread, but not quite finished it. I am thinking of changing the way we handle choice elements ([x])...

What if this:
Observation.value[x] was turned into a normal Observation.value

and

Observation.valueBoolean turned into

Observation.value.of(boolean)

So we get a "type" filter, which would probably be useful in other circumstances as well
[13-1-2016 20:30:11] Grahame Grieve: busy, but I will think about that
[13-1-2016 20:30:25] Grahame Grieve: but I don't like losing the .valueBoolean for all sorts of reasons
[13-1-2016 20:30:55] Grahame Grieve: don't mind losing the [x] quite so much but I think it increases complexity for some implementations
[13-1-2016 20:32:39] Ewout Kramer: The valueBoolean is a very FHIR specific way of type filtering, that feels natural only if you have seen FHIR instances, so if we use FhirPath (or ????Path) outside FHIR, this will look alien to people.
[13-1-2016 20:42:28] Grahame Grieve: yes. I agree to that. but it sounds like we can have our cake and eat it too then
[13-1-2016 20:43:00] Grahame Grieve: because if you are applying FHIRPath in the context where you have a type attribute instead of a pre-coordinated name, then .valueBoolean would be weird
[13-1-2016 20:43:20 | Edited 20:43:25] Grahame Grieve: so we could say that the base is .value.type(boolean) and in FHIR, you can do .valueBoolean
[13-1-2016 21:19:38] Ewout Kramer: "However, this seems to be ambiguous in the grammar with the multiplication operator"

It's not really ambiguous because the multiplication requires a second operand, so either the bla* expression is followed by nothing (=path expression) or it's follow by another path (bla*bla => multiplication) or followed by an invocation (=> path expression). So my parser does indeed support Resource.element**4
[13-1-2016 21:20:29 | Edited 21:21:00] Ewout Kramer: But yes, my parser framework has unlimited lookahead ;)
[13-1-2016 21:21:18] Ewout Kramer: It requires some lookahead to disambiguate, agreed
[13-1-2016 21:34:31] Ewout Kramer: "A.B + A.C If either of B or C are actually lists, then under CQL, this would be a compile-time error, but under FHIRPath, it would be allowed"

We could disallow this is FhirPath, and define the + - / * etc operators to work on single values / lists with one element. The compiler can statically check that.

To allow adding in circumstances where the user is sure there can be only a single value (because the criteria expressed limit the possibilities to only one value), he/she could indicate that explicitly:

A.B.single() + A.C.single()

This would conceptually "cast" an array of one value to a "single" value and then allow addition. The single() function would throw at runtime when there's > 1 one value in A.B. If the user does not care, he/she could do A.B.first() + A.C.first().

This has the advantage of enabling static type checking (i.e. adding elements with cardinality 0..1 would still look natural as A+B), keeps the normal path navigation simple A.B.C (no addition of [] necessary), and is very explicit in rare(?) circumstances where a collection would need to be added.
[13-1-2016 21:34:34] Grahame Grieve: I don't much like the look ahead part
[13-1-2016 21:35:04] Ewout Kramer: I agree. It requires a strong parser framework
[13-1-2016 21:36:15 | Edited 21:36:32] Ewout Kramer: Maybe we should use Bla.[name] STAR. This would also enable more complex repeats like Questionnaire.[group.question] STAR
[13-1-2016 21:36:55] Ewout Kramer: Where STAR=*. Skype is turning my asterix into bold....
[13-1-2016 21:47:44] Ewout Kramer: I've checked the current fhirpath expressions for the use of "+", they are used on constructs that can statically be determined to be single values, so no change would be necessary to the current statements.
[13-1-2016 22:01:57 | Edited 22:02:24] Ewout Kramer: "FHIRPath defines contexts using a "$"
you might find that you don't need some of them, but a couple are kind of handy in an expression - particular $context
Yeah, they are definitely useful, I’m just saying they are parameters,
I picked $context because that's the one that's not a parameter - it arises inline."

In my implementation $context and $resource are indeed treated exactly the same as constant values, in this case passed as parameters into the execution engine.

$parent and $focus are not constant, but we could change $parent to a function application .parents().

$focus is the "variable" in the sense of a lambda expression, e.g. where(x => x>1) in C#, or \x ->x>1 in Haskell for example. Rather than introducing a syntax like this, we could keep treating $focus as the exception (the only non-constant looking like a constant), or replace it by '_', as used in Scala:

(1|2|3|4|5).where( _ > 3)
[13-1-2016 22:05:54] Ewout Kramer: Then, I don't think there is a difference between $xxxx or %xxxxx anymore and they can be merged to mean "constant value". (although stuff like %vs-xxxxx act more like a function with a single param)
[13-1-2016 22:09:12 | Edited 22:09:22] Ewout Kramer: "A..
The second invocation of * would have no type information, it would have to be a run-time invocation.

(...)

That is what I was thinking, define a "dynamic" type that would push it to run-time, similar to the way XPath or C# support dynamic types. "

I like that idea, in fact, my compiler currently does not do static typechecking and treats everything exactly like a "dynamic".

So, paths like '*' and '**', and also Observation.value would evaluate to a dynamic. Disadvantage is that it is not immediately clear in an expression like Observation.value.unit that halfway, we have switched to a dynamic type.
[13-1-2016 22:12:53 | Edited 22:12:57] Ewout Kramer: I did not find any examples where missing 3VL for booleans is a problem?
[13-1-2016 22:14:49 | Edited 22:15:02] Ewout Kramer: But I think we should not do null propagation, except for '+' on strings, where null would be the empty string. Again, I did not find occurrences for '+' in the current fhirpath invariants that use the effect of null propagation.
[13-1-2016 22:16:11] Ewout Kramer: I think that was all. Phew!
[13-1-2016 22:19:38] Grahame Grieve: "The single() function would throw at runtime" - as currently specified, there is no exceptions, just null outcomes.
[13-1-2016 22:20:24] Ewout Kramer: Yes, and I don't like that at all. It requires null propagation from that moment on and results in unexpected behaviour
[13-1-2016 22:20:34] Grahame Grieve: [woensdag 13 januari 2016 21:36] Ewout Kramer:

<<< A.B.single() + A.C.single()why tax the user like this? if the user knows this is ok, why make them say it's ok?
[13-1-2016 22:20:56] Grahame Grieve: Bla.[name]* - isn't this a problem for use of []?
[13-1-2016 22:21:00] Ewout Kramer: Because it harldy ever happens (0 occurences in the current invariants), and when it does, it's very explicit for the reader.
[13-1-2016 22:21:25 | Edited 22:21:30] Ewout Kramer: We have removed "[]" if we don't use [x] anymore for value.
[13-1-2016 22:21:37] Ewout Kramer: Oh, in CQL. Yes, that could be.
[13-1-2016 22:21:59] Grahame Grieve: don't like .parents() because suddenly you need a grammatical way to start with a '.'
[13-1-2016 22:22:27] Grahame Grieve: Rather than introducing a syntax like this, we could keep treating $focus as the exceptionI didn't understand that bit
[13-1-2016 22:23:54] Grahame Grieve: Generally, there was a lot there I wasn't confident I understood.
[13-1-2016 22:24:21] Grahame Grieve: in particular, the notion of null return vs exceptions is important. Right now, you can do this:

rule.path.something.empty()
[13-1-2016 22:24:48] Grahame Grieve: and know that this will be true, that there will be no errors.
[13-1-2016 22:24:59] Grahame Grieve: allowing exceptions..... makes that really really hard
[13-1-2016 22:35:53] Ewout Kramer: don't like .parents() because suddenly you need a grammatical way to start with a '.'Yuck. No we dont want that
[13-1-2016 22:42:20] Ewout Kramer: Yes, I agree the null return vs. exception is one of the biggest issues to tackle.
[13-1-2016 22:50:22] Ewout Kramer: So, let's see. I don't mind single() returning an empty collection, and I don't mind propagating it over child navigation (yada.single().family), but I think 4 + [] = [] is almost always unintended, as is [3,4] + 4 = []
[13-1-2016 22:53:04] Ewout Kramer: Actually, I get confused by most of the operations, including functions, that will return empty when their input is unexpected, like toInteger():

Patient.identifier.id.toInteger() will now return a single integer when there is exactly 1 id, but will return empty when there are 0 or more than 1. I cannot imagine this is desired behaviour.
[13-1-2016 22:53:10] Grahame Grieve: so, maybe. but thing.property.where(otherproperty+4).otherthing
[13-1-2016 22:53:12] Grahame Grieve: that's not clear
[13-1-2016 22:54:25 | Edited 22:54:39] Ewout Kramer: Luckily, when we would introdue select(), we could do what we want:

Patient.identifier.select(id.toInteger()) would return a collection of ids as integers.
[13-1-2016 22:55:04] Grahame Grieve: what if they aren't integers?
[13-1-2016 22:55:57] Bryn Rhodes: I actually really like the empty collection is equivalent to "null", I think that's very clean.
[13-1-2016 22:56:07] Ewout Kramer: Yes
[13-1-2016 22:56:10] Bryn Rhodes: I think if they aren't integers, that's an error, because it's a mistake.
[13-1-2016 22:56:14] Ewout Kramer: But what to do with null +4 ?
[13-1-2016 22:56:26] Bryn Rhodes: null + 4 returns null, just like it does in SQL.
[13-1-2016 22:56:38] Grahame Grieve: I think that you either have exceptions, or query null handling.
[13-1-2016 22:56:49] Bryn Rhodes: Null propagation is good because it allows you to write expressions without regard to whether or not the information isn't there.

view this post on Zulip Ewout Kramer (Jan 14 2016 at 21:18):

[13-1-2016 22:56:51] Ewout Kramer: Grahame: correct
[13-1-2016 22:57:15] Bryn Rhodes: But turning exception conditions into nulls is very bad.
[13-1-2016 22:57:18] Bryn Rhodes: IMHO.
[13-1-2016 22:57:18] Grahame Grieve: you can do type checking at compile time, as I do, and warn the user that the effects might be not what they think
[13-1-2016 22:57:19] Grahame Grieve: so I think it's ok because of that
[13-1-2016 22:57:37] Grahame Grieve: it's one or the other. mixing them is very bad
[13-1-2016 22:57:43] Bryn Rhodes: Why?
[13-1-2016 22:58:12] Bryn Rhodes: The point, I think is that the fact that information is missing isn't an error, it's "i don't know".
[13-1-2016 22:58:19] Bryn Rhodes: But 1 + "Steve" is an error.
[13-1-2016 22:58:27] Grahame Grieve: If you mix the conditions, you'll have to define which is which, and then users will have to guess which is
[13-1-2016 22:58:43] Grahame Grieve: so how does a user handle the case where it might be an error or not?
[13-1-2016 22:59:12] Grahame Grieve: if they're constants, it's always going to be an error. but a real world case, one or both are going to things extracted from objects by query
[13-1-2016 23:00:07] Grahame Grieve: if you say it's always null, the user has predictability, and can make queries without being taxed to make all sorts of type checks and error condition checks - this in a language that is not geared to procedural case statements
[13-1-2016 23:01:22] Bryn Rhodes: So, my problem with that is that "null" is a valid result, it means something, and if you make an error "null" then you don't know whether it's null because it really was null, or it's null because you had some error in your expression.
[13-1-2016 23:01:47] Bryn Rhodes: It ends up hiding important information from the user.
[13-1-2016 23:02:42 | Edited 23:02:44] Bryn Rhodes: Especially in a really complicated expression, that becomes a really big issue.
[13-1-2016 23:03:02] Ewout Kramer: So, Bryn, 4 + [] = [], but 4 + [3,4,5] = error, right?
[13-1-2016 23:03:26] Grahame Grieve: you need to stop using constants. They mislead you about what's going on
[13-1-2016 23:03:32] Bryn Rhodes: Well, I would actually prefer to see that as a "compile-time" error, because you can't add a singular and a list.
[13-1-2016 23:04:24] Bryn Rhodes: But if we accept that there can be implicit conversions to lists, then yes, that would be a run-time error, because there is more than one.
[13-1-2016 23:07:57] Ewout Kramer: So, I suggested making this a compile time error indeed, and add single() for the circumstances where you really want to add to collections together, because you know they are single values (or nulls - if we keep the null propagation). And then if single() encounters > 1 element....a runtime error?
[13-1-2016 23:08:39] Bryn Rhodes: Yes, I like that. In fact CQL has a "singleton from" operator with exactly those semantics.
[13-1-2016 23:08:46] Ewout Kramer: ok
[13-1-2016 23:09:56] Ewout Kramer: So, I see 2 votes for propagating nulls over math. operators and comparisons, so null > 4 = null (=false)
[13-1-2016 23:11:28] Grahame Grieve: so you make users specify singleton even when they know it's null, so that the compiler doesn't tell them that they're wrong, even when they aren't
[13-1-2016 23:12:31] Ewout Kramer: I don't understand that
[13-1-2016 23:13:06] Ewout Kramer: You make them specify singleton if you are doing operations that can statically be determined to be collections. What does that have to do with null?
[13-1-2016 23:14:59] Grahame Grieve: you said you make them specify singletons so that a collection is proven to be single.
[13-1-2016 23:15:00] Bryn Rhodes: I actually really like that because it means you don't have to provide list-valued overloads for all singular operators to enable type analysis.
[13-1-2016 23:15:31] Grahame Grieve: you didn't say anything about statically determined
[13-1-2016 23:15:31] Grahame Grieve: Bryn, like which?
[13-1-2016 23:15:49] Bryn Rhodes: Like .single()
[13-1-2016 23:16:09] Ewout Kramer: I think I had conceded that single() would only throw when there's > 1 element, and return empty on an empty collection
[13-1-2016 23:16:28 | Edited 23:16:34] Bryn Rhodes: Yeah, I was just providing another reason that I like it.
[13-1-2016 23:17:10] Ewout Kramer: That makes sense if we stick to null propagation, as you and Bryn both like to do.
[13-1-2016 23:18:50] Grahame Grieve: but you're going to make a user specify .single() everywhere, because if they do something like

something[thisIsPossiblyOneOrMoreIntegersButIKnowItsOnlyOne + 4].other
[13-1-2016 23:18:56 | Edited 23:18:57] Grahame Grieve: then you'll make that an error anyway
[13-1-2016 23:20:12] Ewout Kramer: I was looking at the operators, certainly not path navigation.
[13-1-2016 23:20:46] Ewout Kramer: What we do with functions that expect a single input (like toInteger) that receive > 1 element, we have not yet discussed.
[13-1-2016 23:22:14] Ewout Kramer: So, I really think single() is going to be exceptional.
[13-1-2016 23:22:21] Ewout Kramer: It should
[13-1-2016 23:22:26] Ewout Kramer: Otherwise, I'd agree with you
[13-1-2016 23:22:45] Grahame Grieve: I was just concluding that I have no idea how what you're describing works
[13-1-2016 23:23:25] Grahame Grieve: under some set of circumstances, it blows up, and .empty() returns false instead of true, and I can no longer understand in my head how a user could know which was which
[13-1-2016 23:24:12 | Edited 23:24:17] Ewout Kramer: So, currently, what would x+y do if either x or y > 1 element?
[13-1-2016 23:24:46] Bryn Rhodes: Hmmm.....
[13-1-2016 23:25:40] Bryn Rhodes: If you allow for dynamics, then the compiler can't know in all cases when single() is required, which means it would be allowed to be inconsistently applied in the language, which would kind of defeat it's usefulness... I think.
[13-1-2016 23:26:37] Ewout Kramer: Ah, but that's true of dynamic in general, and is separate from single()
[13-1-2016 23:26:47] Bryn Rhodes: Agreed.
[13-1-2016 23:26:50] Grahame Grieve: that's why I think that .single() and exceptions is a bad idea
[13-1-2016 23:27:11] Bryn Rhodes: I think swallowing exceptions is an even worse idea.
[13-1-2016 23:28:20] Bryn Rhodes: How would I ever know if something went wrong?
[13-1-2016 23:29:21] Bryn Rhodes: FHIR Path as currently defined doesn't swallow exceptions, right?
[13-1-2016 23:29:32] Ewout Kramer: Right.
[13-1-2016 23:29:52] Ewout Kramer: Adding something to a collection > 1 elmenent returns in an empty collection.
[13-1-2016 23:31:18] Grahame Grieve: so I agree that this is not a comfortable case for me. But I think that any other approach is less comfortable
[13-1-2016 23:31:29] Ewout Kramer: Well, maybe we should propagate both the null and the exception. So, at the end of evaluation, you can either live with the thing being null, or inspect an exception property of the evaluation engine.
[13-1-2016 23:31:46] Ewout Kramer: But how would the caller decide which behaviour he want?
[13-1-2016 23:31:49] Grahame Grieve: but .empty.....
[13-1-2016 23:32:09] Grahame Grieve: this is how OCL works... no exceptions.... just null
[13-1-2016 23:32:14] Bryn Rhodes: What about just .single() semantics but not having to invoke it?
[13-1-2016 23:32:25] Grahame Grieve: not having to invoke it?
[13-1-2016 23:32:41] Ewout Kramer: well, you'd still have to chose between resulting in null or throwing an exception
[13-1-2016 23:32:51] Bryn Rhodes: Yeah, so if you invoked a singular operation on operands with more than one item, it would throw an exception.
[13-1-2016 23:33:09] Bryn Rhodes: If either operand is empty, return empty.
[13-1-2016 23:33:18] Bryn Rhodes: Otherwise, perform the singular operation.
[13-1-2016 23:33:37] Ewout Kramer: well, you'd still have to chose between resulting in null or throwing an exceptionThat remains the devilish dilemma
[13-1-2016 23:33:45] Bryn Rhodes: Yeah, and that's one of the main reasons we didn't use OCL.
[13-1-2016 23:33:48 | Edited 23:33:49] Bryn Rhodes: That's just not safe.
[13-1-2016 23:34:17] Bryn Rhodes: What's the problem with .empty()?
[13-1-2016 23:34:21] Bryn Rhodes: I don't understand.
[13-1-2016 23:35:01] Grahame Grieve: well, at present, objects.filter(criteria).empty returns true if there's no object in the objects that meets criteria
[13-1-2016 23:35:27] Grahame Grieve: but you guys re arguing that for some combinations of criteria, it should return false even if there are no objects that meet the criteria
[13-1-2016 23:36:18 | Edited 23:36:32] Ewout Kramer: no, we are arguing that if the criteria dont make sense, they should not be considered a "false" outcome
[13-1-2016 23:37:19] Ewout Kramer: Alternatively, we define how + works on collections, e.g. result in a collection where 4 is added to all input values
[13-1-2016 23:37:32] Grahame Grieve: so the result of that is the user has to tell the compiler that they do make sense, even when the user knows that they make sense because the language works that way
[13-1-2016 23:38:23 | Edited 23:38:37] Ewout Kramer: If I understand correctly what you are saying, you are saying: "it's ok to produce nonsense results because we have specified that we produce nonsense results"
[13-1-2016 23:39:09] Ewout Kramer: Let's find some actual examples.
[13-1-2016 23:39:38] Ewout Kramer: Becuase I am sure that in practice, our proposal does not change your current way of working.
[13-1-2016 23:40:08] Bryn Rhodes: +1
[13-1-2016 23:41:04] Grahame Grieve: The case that I see is that the resource defines something as a collection.
[13-1-2016 23:41:06] Grahame Grieve: Patient name.
[13-1-2016 23:41:15] Grahame Grieve: Patient.name.first + 'that'
[13-1-2016 23:41:46] Grahame Grieve: a user would have lots of grounds to know that although the specification says it's a collection, they only ever have a single name
[13-1-2016 23:42:19] Ewout Kramer: So, how would you use this in an invariant?
[13-1-2016 23:43:02] Grahame Gr

view this post on Zulip Ewout Kramer (Jan 14 2016 at 21:19):

[13-1-2016 23:43:02] Grahame Grieve: contained.all("#"+id in **.reference)
[13-1-2016 23:44:02 | Edited 23:44:08] Ewout Kramer: id is 0..1, and the compiler would not complain. But you mean, if id were defined as 0..*?
[13-1-2016 23:44:09 | Edited 23:44:09] Grahame Grieve: yes
[13-1-2016 23:46:28] Bryn Rhodes: That would still work, so long as the id did have at most one id at runtime.
[13-1-2016 23:46:51] Bryn Rhodes: As an aside, how does the compiler know that the "id" is applied to the current iteration target, and the ** is applied to the top level resource?
[13-1-2016 23:47:24] Ewout Kramer: ** would, in my evaluator, be applied to the current iteration target
[13-1-2016 23:47:58 | Edited 23:48:00] Bryn Rhodes: Am I misunderstanding what that invariant is supposed to be enforcing then?
[13-1-2016 23:48:25] Ewout Kramer: I think the invariant should read $context.**reference
[13-1-2016 23:49:00] Grahame Grieve: yes it's wrong. good pick
[13-1-2016 23:49:13] Bryn Rhodes: Okay, and then it would work, so long as there was at most one identifier?
[13-1-2016 23:49:31] Bryn Rhodes: id, sorry
[13-1-2016 23:49:35] Ewout Kramer: Currently, it would become false if > 1 id
[13-1-2016 23:50:07] Ewout Kramer: And you could say that's a correct outcome, but really, I wonder if the writer of the invariant was aware of that consequence.
[13-1-2016 23:50:25] Ewout Kramer: (in this case, since it is Grahame, he was....but generally speaking)
[13-1-2016 23:50:29] Bryn Rhodes: Yeah, and it could just as easily have resulted in the wrong outcome if there was negation involved.
[13-1-2016 23:50:33] Ewout Kramer: y
[13-1-2016 23:51:59] Bryn Rhodes: An error in an invariant though, is still a "false" because it means the same thing, so I don't see how that changes the behavior, it just gives the user more information about what went wrong.
[13-1-2016 23:52:09] Grahame Grieve: yes, this one, it would be ok for it to be handled either way, because the invariant would be false either way
[13-1-2016 23:52:23] Grahame Grieve: that was the 1st + I found. I'll find a more difficult case now
[13-1-2016 23:53:23] Ewout Kramer: And, I think if there COULD have been > 1 you'd really have wanted:

contained.select('#' + id) in **.reference
[13-1-2016 23:54:29] Ewout Kramer: which is a more safe, and more true statment, because then all id's would have to appear in a reference
[13-1-2016 23:54:59 | Edited 23:55:10] Ewout Kramer: (I call it select, but many langues call it map())
[13-1-2016 23:55:41] Bryn Rhodes: I like select.
[13-1-2016 23:56:08] Bryn Rhodes: CQL actually uses return, but there was considerable debate about that.
[13-1-2016 23:57:03] Grahame Grieve: maybe I'm just stupid, but I don't understand how that is different
[13-1-2016 23:58:31] Ewout Kramer: contained.all('#' + id...) has the problem that the "+" would return empty, so when there is > 1 id, the statement becomes false.
[13-1-2016 23:59:06] Ewout Kramer: While the version with select() would return true (it seemed to me that IF there are > 1 id, you'd wanted those other id's to also be referenced)
[13-1-2016 23:59:14] Ewout Kramer: That's a user's choice of course.
[13-1-2016 23:59:27] Grahame Grieve: ok I get it
[13-1-2016 23:59:31] Grahame Grieve: snapshot.element.tail().all(path.startsWith($context.snapshot.element.first().path+"."))
[00:00:06] Grahame Grieve: I suppose you're going to argue with this one that first() makes it single. so this is not going to be a problem
[00:00:08] Ewout Kramer: here, the first() fixes the problem
[00:00:10] Ewout Kramer: yep
[00:00:15] Ewout Kramer: you know me by now.
[00:02:47] Grahame Grieve: (Range): low.empty() or high.empty() or (low <= high)
[00:02:57] Ewout Kramer: But the main question is: that contained.all() statement, should that have thrown when the user is 100 % there cannot be > 1 id?
[00:03:16] Ewout Kramer: can low and high repeat?
[00:03:27] Ewout Kramer: or is this a subclause on something that is repeating?
[00:04:13] Grahame Grieve: they can't repeat now
[00:04:37] Bryn Rhodes: If the user is 100% certain that there cannot be > 1 id and there isn't actually > 1 id at runtime, then there would be no error.
[00:05:23] Grahame Grieve: here's a much more interesting case:
[00:05:25] Grahame Grieve: component.where(code = $context.code).empty()
[00:05:51] Grahame Grieve: on Observation
[00:06:08] Ewout Kramer: Ah, but I like how we have defined = on collections....
[00:06:31] Ewout Kramer: no problem here for me.
[00:06:51] Bryn Rhodes: Me either, = is overloaded for collections, makes sense.
[00:07:53] Grahame Grieve: I think it's going to be hard to find something out of the existing resource based things
[00:08:15] Ewout Kramer: in the high and low case, it would depend on whether they would need to be compared in pairs, or all lows must be < highest high, or lower than the lowest high.
[00:08:31] Grahame Grieve: for more interesting examples, I'm going to have to talk about profiles
[00:08:31] Grahame Grieve: because is your compiler profile aware?
[00:09:25] Grahame Grieve: it can't be. actually. that's the problem
[00:09:46] Grahame Grieve: I'm writing an evaluation on patient that knows that the cardinality of a collection ix fixed to 1.
[00:10:02] Grahame Grieve: but your evaluation engine doesn't know that, so the user has to tell it
[00:11:13] Ewout Kramer: Yes. So, if you use that statement to validate the profile, of course you would have to check for occurences > 1. This is the situation where we know the statement is executed in an environment where the isntances is already validated against the profile and we are 100% sure it will not repeat.
[00:11:32] Grahame Grieve: yes, but the engine is not clued into this
[00:11:36] Ewout Kramer: Rght.
[00:12:58 | Edited 00:14:47] Ewout Kramer: So, there's someone who has written a profile and has told the author of the statement that there's one occurrence only. Author is a consumer of the output of a system where the profile has been run to validate incoming instances.
[00:16:02] Grahame Grieve: yes
[00:16:28 | Edited 00:16:36] Ewout Kramer: So, it depends whether the FP compiler is run against the base resources or against the gatekeeper profile...
[00:16:58] Ewout Kramer: oh, we didn't do static checking anymore.
[00:18:19] Ewout Kramer: So, now the configuration changes. The author is not updated of this fact (might be quite some time later). Would we prefer run-time errors, or unpredictable behaviour of the downstream FP expressions?
[00:18:31] Ewout Kramer: Or still - static checking?
[00:18:53] Ewout Kramer: Or static checking? (but that would require single())
[00:20:01] Ewout Kramer: Let's see if a night of sleep brings more insights. Gentlemen, thank you for an entertaining discussion ;-)
[00:20:34] Grahame Grieve: yes sleep time
[07:14:18] Ewout Kramer: Thought about it some more.

[00:18] Ewout Kramer:

<<< So, now the configuration changes. The author is not updated of this fact (might be quite some time later). Would we prefer run-time errors, or unpredictable behaviour of the downstream FP expressions?
My answer is: runtime error (at least). Your assumptions have changed because of an upstream change. This means that your FP queries based on those assumptions are now potentially doing the wrong thing, so they need to throw and you need to take a look at your queries to update them to the new situation (upstream profile causes different cardinality)

If you want to be future proof & you can use single() or first(), and that's an explicit choice stating that you have covered the case where the cardinality turns out to be > 1
[07:15:21] Ewout Kramer: And I think I would add a parameter to my evaluator to use "strict" evaluation. If you enable that, the compiler will track cardinalities and point you out where you'd need to do single() or first() (or however you want to handle it)
[07:15:31 | Edited 07:16:43] Ewout Kramer: CQL might decide to require "strict" mode, while FHIR does not.
[07:18:53] Ewout Kramer: Note: the discussion about single() also holds for functions taking a parameter (like substring) that needs to be single-valued. returning empty on a substring() just because the parameter turns out to be a collection has the same risks.
[07:20:24 | Removed 07:21:34] Ewout Kramer: This message has been removed.
[07:51:11] Grahame Grieve: I think we need to understand the impacts on the various ways you use a query
- indexing for search parameter
- invariant
- mapping
- decision support library
[07:51:20] Grahame Grieve: how do these fail in the various cases?
[08:02:13] Ewout Kramer: That makes sense
[08:02:31] Ewout Kramer: To validate my statement ;-)
[08:11:05] Ewout Kramer: bryn, we're sitting front right in the breakfast room
[13:50:23] Grahame Grieve: so we didn't close this out did we?
[14:12:09] Grahame Grieve: let me know if this gets interesting
[14:15:20] Ewout Kramer: ok
[14:42:56] Bryn Rhodes: So, as far as next steps here, I was thinking I could start by actually taking a branch of the CQL tooling and implement the changes that have been proposed to enable the CQL grammar to express FHIRPath.
[14:43:01] Bryn Rhodes: Does that sound like a good next step?
[14:55:32 | Edited 14:55:51] Ewout Kramer: I think I know "I" agreed on ;) But as a summary:

  • Stick to null propagation (but we still need to define if nulls propagate through parameters, i.e. if you pass null to substring() what happens?). We agreed 4 + null = null, but what about string + null?
  • Will now throw an exception if operators / functions are called on collections with > 1 element when 1 element (or null) is expected.
  • Throwing exceptions at runtime can be avoided by
    a) being absolutely sure (because you're downstream from a profile validator) that cardinality will be 1 or
    b) defensively use mechanisms like first(),
    c) Have static validation capabilities in the compiler (which can be switched on/off or are effectively warnings) to point out where

view this post on Zulip Ewout Kramer (Jan 14 2016 at 21:19):

[14:55:32 | Edited 14:55:51] Ewout Kramer: I think I know "I" agreed on ;) But as a summary:

  • Stick to null propagation (but we still need to define if nulls propagate through parameters, i.e. if you pass null to substring() what happens?). We agreed 4 + null = null, but what about string + null?
  • Will now throw an exception if operators / functions are called on collections with > 1 element when 1 element (or null) is expected.
  • Throwing exceptions at runtime can be avoided by
    a) being absolutely sure (because you're downstream from a profile validator) that cardinality will be 1 or
    b) defensively use mechanisms like first(),
    c) Have static validation capabilities in the compiler (which can be switched on/off or are effectively warnings) to point out where cardinalities can cause throwing errors.

  • Introduce a type filter ofType() or of() or type() to work with choice elements (which I think can also be used to filter '**' or '*' expressions to filter only certain types of nodes, which would enable static typechecking to continue after such expressions)

view this post on Zulip Ewout Kramer (Jan 14 2016 at 21:20):

Ok, switch from Skype....

view this post on Zulip Bryn Rhodes (Jan 16 2016 at 18:20):

  • Regarding "Stick to null propagation": In general, CQL operations return null if any argument is null. There are a few exceptions to ensure expected behavior, but they are all documented in the operator appendix.
  • Regarding "ofType()": In CQL, we have "is", "as", and "cast as", with semantics equivalent to the "is", "as", and "cast" of C#. We have a type specifier production rule that allows these clauses to be used with any type. In FHIRPath, I would think there would just be ofType() operators for each primitive, yes?

view this post on Zulip Bryn Rhodes (Jan 16 2016 at 18:21):

Oh, and for consistency of naming, I wonder if "asType" would be okay?

view this post on Zulip Ewout Kramer (Jan 18 2016 at 19:34):

ofType(x), where x is one of the primitives, yes, that's what I mean. asType() would be perfect!

view this post on Zulip z Brian Postlethwaite (old - don't use) (Feb 01 2016 at 08:23):

Looking for how I might prepare this xpath expression as a fhirpath expression
if(//Condition/code/coding/code[@value='ihd' or @value='hearf']) then 'Yes' else ''

view this post on Zulip z Brian Postlethwaite (old - don't use) (Feb 01 2016 at 11:28):

How does this look for people?
('Yes'.where($resource.code.coding.where(code='ihd' or code='hearf')) | '').first()

view this post on Zulip z Brian Postlethwaite (old - don't use) (Feb 01 2016 at 11:44):

Simpler example: ('Yes'.where(false) | 'No').first() returns 'No'
and ('Yes'.where(true) | 'No').first() returns 'Yes'

view this post on Zulip Ewout Kramer (Feb 01 2016 at 12:55):

very creative ;-) Looking for an if function?

view this post on Zulip z Brian Postlethwaite (old - don't use) (Feb 01 2016 at 12:57):

Yes, an if function would have made it much nicer,,,

view this post on Zulip Grahame Grieve (Feb 05 2016 at 05:58):

Yes I like the if function

view this post on Zulip Bryn Rhodes (Feb 10 2016 at 17:38):

Sorry, just now seeing this. CQL defines an "if" that looks just like the XPath syntax. Not sure that would fit within FluentPath, but worth considering I think.

view this post on Zulip Ewout Kramer (Feb 15 2016 at 09:47):

Yes, I was thinking along those lines....I will update the spec this week.

view this post on Zulip Ewout Kramer (Feb 22 2016 at 14:18):

So, I have basically decided to add an iif(), https://en.wikipedia.org/wiki/IIf. where the "false" part will be selected when the input is either false or empty.

view this post on Zulip Jason Walonoski (Feb 22 2016 at 15:25):

Having missed Orlando, I probably missed the plan for FHIRPath/FluentPath... when is this going to replace the XPath invariants in the StructureDefinitions?

view this post on Zulip Ewout Kramer (Feb 22 2016 at 15:28):

It's actually already there in the build, but just as an extension, e.g.

            <constraint>
              <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-expression">
                <valueString value="compose.import.count() != 1 or compose.include or compose.exclude or codeSystem"/>
              </extension>
              <key value="vsd-2"/>
              <severity value="error"/>
              <human value="A value set with only one import SHALL also have an include and/or an exclude unless the value set includes and inline code system"/>
              <xpath value="not(exists(f:compose)) or (count(f:compose/f:import)!=1 or exists(f:compose/f:include) or exists(f:compose/f:exclude) or exists(f:codeSystem))"/>
            </constraint>

view this post on Zulip Jason Walonoski (Feb 22 2016 at 15:29):

Are they being kept in-sync?

view this post on Zulip Jason Walonoski (Feb 22 2016 at 15:30):

I'm trying to decide how heavily I'm going to invest development time in fhirpath... is the XPath going to go away?

view this post on Zulip Grahame Grieve (Feb 22 2016 at 19:45):

Jason - I very much want it to go away, but other people have committed to it. So it looks likely that we will flip to using FHIRPath (or whatever it is called) as the primary, and generate XPath from them

view this post on Zulip Jason Walonoski (Mar 10 2016 at 15:54):

I want to implement support for fhirpath (or is it called fluentpath?) when I move to STU3... is https://github.com/ewoutkramer/fhirpath the official documentation ?

view this post on Zulip Michel Rutten (Mar 10 2016 at 16:27):

@Jason that is correct, Ewout has documented the official FHIR Path syntax definition.

view this post on Zulip Jason Walonoski (Mar 10 2016 at 16:29):

@Michel Rutten thanks. Is there an official reference implementation?

view this post on Zulip Michel Rutten (Mar 10 2016 at 16:39):

@Jason Walonoski Ewout has been implementing FHIR Path into the .NET FHIR API. This implementation now covers most - if not all - of the spec, verified by a set of unit tests. So you could consider this as a reference implementation. There are also implementations available in other languages.

view this post on Zulip Jason Walonoski (Mar 10 2016 at 16:40):

@Michel Rutten Ok, thanks!

view this post on Zulip Bryn Rhodes (Mar 10 2016 at 17:12):

Note that it's still a work in progress and we're currently updating it. So what's there is changing, and we'll be balloting the update in the May ballot cycle.

view this post on Zulip Bryn Rhodes (Mar 10 2016 at 17:13):

You might want to hold off a little bit on implementing until those changes are in place, over the next few weeks.

view this post on Zulip Jason Walonoski (Mar 10 2016 at 18:08):

Well, is there a stable core? I wanted to be checking the invariants at the connectathon.

view this post on Zulip Bryn Rhodes (Mar 10 2016 at 20:12):

The fluentpath.g4 that's there is very close, there's another round of changes we're still discussing, but they're minor changes to the syntax itself. Our goal is to be validating by the connectathon as well.

view this post on Zulip Ewout Kramer (Mar 14 2016 at 09:38):

Hi Jason, the invariants that are currently present in the spec are based on the jan/orlando draft of the FHIRPath spec. In Orlando we've discussed FHIRPath broadly and we've embarked on aligning it with the needs of the CQL team (of which Bryn is a member). The rename to "FluentPath" signals the fact that it is no longer a FHIR-only technology....

view this post on Zulip Grahame Grieve (Dec 07 2016 at 10:51):

btw, as well as updated versions of everything else, we have posted the candidate STU1 version of FHIRPath at http://hl7.org/fhirpath. It's not finally approved by the relevent committee yet, but we expect it will be soon, and we don't expect any substantiative changes. Thanks to @Bryn Rhodes for taking the lead on this

view this post on Zulip Brian Postlethwaite (Dec 10 2016 at 06:49):

Yes, a big thanks @Bryn Rhodes

view this post on Zulip David Hay (Aug 14 2017 at 19:40):

Is it possible for a fhir expression to follow references? for example, suppose you have a contained resource and you want to follow the reference form the parent resource to return it. For example, suppose that Observation.supbect refers to a contained Patient resource, who could you return that Patient? sort of: Observation.contained.where(id=Observation.subject.reference.substring(1)) ...

view this post on Zulip Grahame Grieve (Aug 14 2017 at 20:33):

search in the fhirpath spec for .resolve()

view this post on Zulip David Hay (Aug 14 2017 at 21:25):

Thanks Grahame - alas it doesn't seem to work in the javascript version that's on the web (as it's a couple of years old I guess that's not too surprising :) ) . Hopefully will be resolved when the new version is available...

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:05):

ITS is planning to ballot FHIRPath as normative in May. There's several implementations in different languages by different authors, there's plenty of use in the FHIR spec, there's a solid set of tests. There's some production use. And there's been very little substantiative change

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:06):

there is several change requests:

view this post on Zulip Dale Nelson (Jan 07 2018 at 21:08):

Yes we are so planning to ballot. Curious if there has been any substantive change?

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:09):

  • add sum()
  • add quantity comparison
  • clarify about date rounding
  • relax definitions of concept equivalents

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:09):

Dale: no substantiative change proposed as yet

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:09):

maybe the last one might count as substantiative?possible.

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:10):

anyway, this is a call for comments and consideration on making this normative. In particular, has anyone used the v2 part (other than me?)

view this post on Zulip Dale Nelson (Jan 07 2018 at 21:14):

We would have a hard time arguing to go another round of STU rather than normative, IMO. For all the reasons you stated.

view this post on Zulip Grahame Grieve (Jan 07 2018 at 21:16):

need to do some stuff in the appendices:
- Appendix A needs to be normalised in the spec
- Appendix D probably needs to be trial use still
- Appendix E might need to be moved to somewhere else non-normative to allow it to be updated

view this post on Zulip Dale Nelson (Jan 07 2018 at 21:26):

Agree, Appendix E should not be part of normative spec, and we might want to think about V2/Appendix D. So some work to do, but clearly on a May normative track.

view this post on Zulip Lloyd McKenzie (Jan 07 2018 at 21:56):

Has it been published as STU in 2 publication cycles?

view this post on Zulip Grahame Grieve (Jan 07 2018 at 22:21):

no. only one.

view this post on Zulip Lloyd McKenzie (Jan 07 2018 at 22:31):

Is there a reason we wouldn't adhere to the 2-cycle rule for this one to get to FMM-5 (which is the pre-req for normative) that we have for all FHIR artifacts?

view this post on Zulip Grahame Grieve (Jan 07 2018 at 22:35):

because it's not a FHIR artifact directly. And the implementation hasn't thrown up the kind of content model issues that make that investment of time necessary. And because ITS indicated a desire go straight to normative

view this post on Zulip Grahame Grieve (Jan 07 2018 at 23:02):

and as you say elsewhere, we use it in some candidate normative artifacts

view this post on Zulip Lloyd McKenzie (Jan 07 2018 at 23:27):

We will be using things in normative artifacts that aren't normative for the next 5-10 years. So that's not a compelling reason to move forward. Nor is a WG's indication of desire. Given the high level of dependence FHIR has on FHIRPath, I would hope that we'd adhere to the same quality expectations. At minimum, I'd expect to see an argument presented of how the objectives intended by the requirements we're waiving are either met or irrelevant in this situation with supporting evidence or rationale. I'd also expect evidence of why adhering to the requirement was problematic. None of that's been shared yet.

view this post on Zulip Grahame Grieve (Jan 07 2018 at 23:38):

"We will be using things in normative artifacts that aren't normative for the next 5-10 years" - really? what?

view this post on Zulip Lloyd McKenzie (Jan 08 2018 at 01:41):

Many resources have References that point to other resources that will include at least some resources that aren't normative yet. And I expect there it'll take us at least 3 more publications after R4 becore the vast majority of resources are normative.

view this post on Zulip Grahame Grieve (Jan 08 2018 at 01:46):

so there's a big difference between 'target of a reference' and included right in the resource

view this post on Zulip Andy Stechishin (Jan 08 2018 at 01:57):

To be clear, ITS has not decided anything about going Normative. Bryn was asked what he would like to do with the STU period coming to a close. Bryn indicated he thought it should go Normative and so this will be discussed in the joint ITS/FHIR-i quarter at the WGM. If you feel this is inapproriate, I would suggest that you attend this session as I would expect Bryn to be making a motion at some point.

view this post on Zulip Grahame Grieve (Jan 08 2018 at 02:24):

I should have been clear about that. No formal decision at this point, but that's the proposed motion

view this post on Zulip Lloyd McKenzie (Jan 08 2018 at 02:42):

@Andy Stechishin Unfortunately I can't make that session, which is why I'm sharing my concerns now. I think the risk of leaving it non-normative is low. If we are going to take it normative, I think we need to establish why we think the FMM level rules should be waived, at least in part. Out of curiousity, what management group is responsible for FHIRPath?

view this post on Zulip Grahame Grieve (Jan 08 2018 at 03:04):

it is in the FHIR product family. I don't think we've really talked about the difference between FMG scope and FHIR product family

view this post on Zulip Lloyd McKenzie (Jan 08 2018 at 03:08):

Something for the TSC to discuss? (And perhaps for the FMG and other management groups to share their thoughts on?)

view this post on Zulip Lloyd McKenzie (Jan 08 2018 at 03:09):

@Anne Wizauer Can you tentatively add this to the next FMG agenda?

view this post on Zulip Dale Nelson (Jan 08 2018 at 03:12):

Actually, I would believe that FHIRPath is broader than FHIR and resides outside of FMG. Recall the name of the product was only b/c of copyrights not b/c it was a FHIR-specific language

view this post on Zulip Grahame Grieve (Jan 08 2018 at 03:12):

that's correct. But it's still in the FHIR Product family.

view this post on Zulip Dale Nelson (Jan 08 2018 at 03:18):

So yes, FMG can share thoughts as you say, also V2, CQI, SDTC etc - but the decision on normative readiness would not be based on the FMM criteria.

view this post on Zulip Anne Wizauer (Jan 08 2018 at 14:35):

@Anne Wizauer Can you tentatively add this to the next FMG agenda?

Sure thing!

view this post on Zulip nicola (RIO/SS) (Jan 09 2018 at 22:05):

please, split FHIRpath into simple core and set of extensions (like time operators etc)

view this post on Zulip Grahame Grieve (Jan 09 2018 at 22:10):

why?

view this post on Zulip Ewout Kramer (Jan 15 2018 at 12:43):

@nicola (RIO/SS), are you referring to our previous discussion on subsets of FHIRPath?: a simple subset to use in Discriminators, a subset for searches etc. I think the invariants may want to use everything there is, but I can imaginge some useful subsets.

view this post on Zulip Ewout Kramer (Jan 15 2018 at 12:45):

Then, about FHIRPath language extensions. You mentioned "sum()". One of the major "usual" operations that come with these kind of languages is fold/aggregate (of which sum() would be a specialization). We might need to talk about whether we just stick to sum() or take a look at fold() (though that would need lambda notation in the language, now we're talking major changes).

view this post on Zulip Katarina (May 08 2019 at 10:01):

I want to set a constraint for a practitioner's name (German base profile). With fhirpath I would like to express that at least one name should be official (use = "official"). I have formulated the following fhirpath expression: (use = 'official').count ()> 0 . When I validate an example practitioner that does not have a name with use=official, I expect an error, but there is no. Can anyone help me with fhirpath expression?

view this post on Zulip nicola (RIO/SS) (May 08 2019 at 10:06):

@Ewout Kramer i think we have to wait for more database-oriented people to start this subset - I would define it as efficient FHIRpath subset for data extraction to index and search FHIR resources. For DSL I think it's ok to have min, max, sum and avg as built-ins (for performance reason)

view this post on Zulip Grahame Grieve (May 08 2019 at 10:19):

@Katarina I expect that to work - whatever the problem is not in the FHIRPath statement. Can you turn it into a profile / instance combination and submit an issue so I can look at it?

view this post on Zulip Katarina (May 08 2019 at 13:47):

@ Grahame Grieve Thanks for your feedback. My profile looks like this:

<StructureDefinition xmlns="http://hl7.org/fhir">
<url value="https://example.de/fhir/StructureDefinition/MyPractitioner"/>
<name value="MyPractitioner"/>
<status value="draft"/>
<fhirVersion value="3.0.1"/>
<kind value="resource"/>
<abstract value="false"/>
<type value="Practitioner"/>
<baseDefinition value="http://fhir.de/StructureDefinition/practitioner-de-basis/0.2"/>
<derivation value="constraint"/>
<differential>
<element id="Practitioner.name">
<path value="Practitioner.name"/>
<min value="1"/>
<constraint>
<key value="oneOfficialName"/>
<severity value="error"/>
<human value="One name must be official."/>
<expression value="(use='official').count()>0"/>
</constraint>
</element>
<element id="Practitioner.name.family">
<path value="Practitioner.name.family"/>
<min value="1"/>
</element>
<element id="Practitioner.name.given">
<path value="Practitioner.name.given"/>
<min value="1"/>
</element>
<element id="Practitioner.address">
<path value="Practitioner.address"/>
<min value="1"/>
</element>
<element id="Practitioner.address.use">
<path value="Practitioner.address.use"/>
<fixedCode value="work"/>
</element>
<element id="Practitioner.address.type">
<path value="Practitioner.address.type"/>
<fixedCode value="physical"/>
</element>
<element id="Practitioner.address.line.extension:Postfach">
<path value="Practitioner.address.line.extension"/>
<sliceName value="Postfach"/>
<max value="0"/>
</element>
<element id="Practitioner.address.state">
<path value="Practitioner.address.state"/>
<binding>
<strength value="required"/>
<description value="Bundesländer"/>
</binding>
</element>
<element id="Practitioner.address.postalCode">
<path value="Practitioner.address.postalCode"/>
<min value="1"/>
</element>
<element id="Practitioner.address.country">
<path value="Practitioner.address.country"/>
<min value="1"/>
<binding>
<strength value="required"/>
</binding>
</element>
<element id="Practitioner.gender">
<path value="Practitioner.gender"/>
<max value="0"/>
</element>
<element id="Practitioner.birthDate">
<path value="Practitioner.birthDate"/>
<max value="0"/>
</element>
<element id="Practitioner.photo">
<path value="Practitioner.photo"/>
<max value="0"/>
</element>
<element id="Practitioner.communication">
<path value="Practitioner.communication"/>
<max value="0"/>
</element>
</differential>
</StructureDefinition>

And my example:

<?xml version="1.0" encoding="UTF-8"?>
<Practitioner xmlns="http://hl7.org/fhir">
<meta>
<profile value = "https://example.de/fhir/StructureDefinition/MyPractitioner"/>
</meta>
<active value="true"/>
<name>
<use value = "temp"/>
<family value="Meier"/>
<given value="Maria"/>
<given value="Anna"/>
<prefix value = "Dr.med."/>
</name>
<name>
<use value = "maiden"/>
<family value="Müller"/>
<given value="Maria"/>
<given value="Anna"/>
<prefix value = "Dr.med."/>
</name>
<telecom>
<system value="phone" />
<value value= "030-1234567"/>
<use value = "work"/>
</telecom>
<telecom>
<system value="email" />
<value value= "meierA@hno.de"/>
<use value = "work"/>
</telecom>
<address>
<use value = "work"/>
<type value = "physical"/>
<postalCode value = "10117"/>
<country value = "DE"/>
<state value = "DE-BE"/>
</address>
</Practitioner>

view this post on Zulip Eric Mays (Jan 22 2020 at 15:43):

Want to be sure I'm reading this correctly.
Have this fhirpath expression:
<expression value="Xor(Observation.valueCodeableConcept.exists(), Observation.dataAbsentReason.exists())"/>
Get:
Exception in thread "main" java.lang.Error: Not done yet (ValidatorHostServices.resolveFunction): Xor
This means not implemented? Or is something else going on?

view this post on Zulip Paul Lynch (Jan 22 2020 at 18:00):

I am not sure this is the problem, but I think "xor" should be all lowercase.

view this post on Zulip Eric Mays (Jan 22 2020 at 20:36):

Thanks, but that's not it:
Exception in thread "main" java.lang.Error: Not done yet (ValidatorHostServices.resolveFunction): xor
Have a workaround, so moving on...

view this post on Zulip Lloyd McKenzie (Jan 22 2020 at 20:37):

@Grahame Grieve

view this post on Zulip Grahame Grieve (Jan 22 2020 at 21:32):

xor is an operator not a function

view this post on Zulip Eric Mays (Jan 22 2020 at 23:17):

Thanks. Got it. Ooops...

view this post on Zulip Katarina (Feb 21 2020 at 11:36):

Hi, I have the following usecase: I have an extension that is a reference to an organization profile. For the organization the type has a valueSet binding. I would like to make restrictions on the organizations that can be referenced. How would I write a fhirpath constraint to say that in the extension only organizations can be referenced for these only a restricted valueSet is valid?

My Organization profile with valueSet binding:

<?xml version="1.0" encoding="utf-8"?>
<StructureDefinition xmlns="http://hl7.org/fhir">
<url value="https://example/fhir/StructureDefinition/Facility" />
<name value="Facility" />
<status value="draft" />
<fhirVersion value="3.0.1" />
<kind value="resource" />
<abstract value="false" />
<type value="Organization" />
<baseDefinition value="http://fhir.de/StructureDefinition/organization-de-basis/0.2" />
<derivation value="constraint" />
<differential>
<element id="Organization.type">
<path value="Organization.type" />
<min value="1" />
<max value="1" />
</element>
<element id="Organization.type.coding">
<path value="Organization.type.coding" />
<min value="1" />
<max value="1" />
</element>
<element id="Organization.type.coding.system">
<path value="Organization.type.coding.system" />
<min value="1" />
<binding>
<strength value="required" />
<valueSetUri value="https://example/fhir/ValueSet/facilityType" />
</binding>
</element>
<element id="Organization.type.coding.code">
<path value="Organization.type.coding.code" />
<min value="1" />
</element>
</differential>
</StructureDefinition>

Usage of the extension:
<Bundle xmlns="http://hl7.org/fhir">
<type value="document" />
<entry>
<resource>
<Composition>
...
<extension url="https://example/fhir/StructureDefinition/IsCaredIn">
<extension url="organization" >
<valueReference>
<reference value="urn:uuid:61ebe359-bfdc-4613-8bf2-c5e300945f22" />
</valueReference>
</extension>
</extension>
</Composition>
</resource>
</entry>
<entry>
<fullUrl value="urn:uuid:61ebe359-bfdc-4613-8bf2-c5e300945f22" />
<resource>
<Organization>
<meta>
<profile value="https://example/fhir/StructureDefinition/Facility" />
</meta>
<name value="Waldkindergarten"/>
here not every code in https://example/fhir/ValueSet/facilityType should be allowed, only a specific set
</Organization>
</resource>
</entry>
</Bundle>

Is fhirpath the right way or are there other possibilities?

view this post on Zulip Lloyd McKenzie (Feb 21 2020 at 17:44):

It seems that you would just declare a targetProfile for the reference indicating that the Organization needs to be valid against the specified profile

view this post on Zulip Katarina (Feb 26 2020 at 09:52):

Hi, how can I get the valueReference in a complex extension with fhirpath?

I tried this:
Composition.where(extension('https://example/fhir/StructureDefinition/IsCaredIn')).children().where(extension('organization').value='12345')

My Composition looks like this:
<Composition>
...
<extension url="https://example/fhir/StructureDefinition/IsCaredIn">
<extension url="groupInOrganization" >
<valueString value="Spechte und Käuze" />
</extension>
<extension url="lastStayInOrganization" >
<valueDate value="2020-02-02" />
</extension>
<extension url="organization" >
<valueReference>
<reference value="12345" />
</valueReference>
</extension>
</extension>
</Composition>

view this post on Zulip Katarina (Feb 26 2020 at 09:57):

And another question:

"Bundle.entry.resource.ofType(Composition)" should bring all Composition-entries in the bundle, right?
I have three compositions in the bundle, but "Bundle.entry.resource.ofType(Composition).count()=3" does not validate in true. What am I doing wrong?

view this post on Zulip Lloyd McKenzie (Feb 26 2020 at 16:25):

@Bryn Rhodes

view this post on Zulip Bryn Rhodes (Feb 26 2020 at 20:03):

The extension is a reference, so that it will have the structure of a Reference, so you need to dig in to the actual reference element: ...extension('organization').value.reference='12345'

view this post on Zulip Bryn Rhodes (Feb 26 2020 at 20:07):

On the second one, that seems like that ought to work, but I wonder if it's getting tripped up by the way resource elements are actually serialized. Can you try Bundle.entry.where(resource is Composition).count() = 3?

view this post on Zulip Katarina (Feb 27 2020 at 15:55):

Hi, thank you @Bryn Rhodes that worked!.

How can I check if the type of an Organization is within a valueSet?

This seems not to work:
entry.where(fullUrl='urn:uuid:61ebe359-bfdc-4613-8bf2-c5e300945f22').select(resource as Organization).type.coding.code.memberOf('https://example/fhir/ValueSet/organizationTypesCaredIn')

also

...type.coding.code='code1' seems not to work.

view this post on Zulip Bryn Rhodes (Feb 28 2020 at 16:21):

Hmm... that seems like that memberOf ought to work, what environment are you running the FHIRPath in?

view this post on Zulip Katarina (Mar 02 2020 at 09:39):

I use Vonk.Server/3.1.1.

My Organization looks like this:
<Organization>
<id value="23"/>
<meta>
<profile value="https://example/fhir/StructureDefinition/Facility" />
</meta>
<name value="Waldkindergarten"/>
<type>
<coding>
<system value="https://example/fhir/ValueSet/organizationTypesCaredIn"/>
<code value="foodfacility"/>
</coding>
</type>
</Organization>

I checked the CodeSystem organizationType that contains "foodfacility" and the corresponding ValueSet.
But I get an error no matter if i put "foodfacility" as value for code or some other value not contained in the ValueSet.

view this post on Zulip Nikhil (May 18 2020 at 07:17):

Hi,

Needed a clarification regarding the FHIRPath expression defined in SearchParameter for value[x] parameters.

The expression for searchparameter to search a value[x] field should have all possible variants allowed for seach ?
for example, As of now the FHIRPath expression for the field CarePlan->activity->detail->scheduled is defined as

  1. "CarePlan.activity.detail.scheduled"
    OR

  2. "CarePlan.activity.detail.scheduled as Timing | CarePlan.activity.detail.scheduled as Period | CarePlan.activity.detail.scheduled as string" ?

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 02:47):

What is 'System' referred in System.String? It basically points to the datatype of the language we implement it. Can someone help?

view this post on Zulip Richard Townley-O'Neill (Jun 02 2020 at 04:24):

Are you asking about Resource.language? http://hl7.org/fhir/R4/resource.html#Resource
What do you want to know?

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 04:42):

When i read the FHIRPath specification, I saw about FHIRPath type that talks about

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 04:42):

The evaluation engine will automatically convert the value of FHIR types representing primitives to FHIRPath types when they are used in expressions according to the following mapping:

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 04:43):

FHIRPath type represents different values : System.Boolean, System.String, System.Integer

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 04:43):

What does System refer to?

view this post on Zulip Lloyd McKenzie (Jun 02 2020 at 04:45):

@Bryn Rhodes

view this post on Zulip Bryn Rhodes (Jun 02 2020 at 05:22):

The System namespace is used to define all the system-defined types in FHIRPath (and CQL). The models topic in FHIRPath talks about the System namespace.

view this post on Zulip Keerthivasan Ramanathan (Jun 02 2020 at 10:09):

Thanks @Bryn Rhodes and @Lloyd McKenzie

view this post on Zulip Grey Faulkenberry (Jun 22 2021 at 14:10):

Quick question about the FHIRPath spec on the hl7 site. I was just wondering if one of the lines is misplaced.
toDate() : Date It states nothing about partial dates
convertsToDate() : Boolean it states "If the item contains a partial date (e.g. '2012-01'), the result is a partial date."
toDateTime() : DateTime it states "If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime."
convertsToDateTime() : Boolean it states nothing about partial dateTimes

view this post on Zulip Grahame Grieve (Jun 22 2021 at 14:32):

can you ask this on #fhirpath

view this post on Zulip Gabriela Espinosa (Jan 12 2022 at 01:11):

I have a question about restricting one of multiple types of references allowed. For an Observation.basedOn field which allows multiple references, I would like to define a requirement where a reference to a specific profile should only be allowed once. Other references to other profiles should still be valid. Is there a way to express this? I have not been able to find an example or the right syntax.

view this post on Zulip Richard Townley-O'Neill (Jan 12 2022 at 03:19):

To check whether the is only one use count().
The following test will return true with 0 or 1 matching instances of basedOn.display and false otherwise.
basedOn.where(display='HHH').count()<=1

view this post on Zulip Richard Townley-O'Neill (Jan 12 2022 at 03:25):

Why do you want to ensure that at most one referent conforms to the profile? Is it enough to say that only 1 referent of a resource type is allowed, e.g. at most one CarePlan?

view this post on Zulip Richard Townley-O'Neill (Jan 12 2022 at 03:32):

To follow a reference use the resolve() function

view this post on Zulip Lloyd McKenzie (Jan 12 2022 at 03:58):

You can also slice by profile and set a max cardinality of 1 on your slice

view this post on Zulip Gabriela Espinosa (Jan 12 2022 at 18:29):

Lloyd McKenzie said:

You can also slice by profile and set a max cardinality of 1 on your slice

I like the idea of adding a slice for the particular reference and setting the cardinality there. Thanks for the feedback!


Last updated: Apr 12 2022 at 19:14 UTC