FHIR Chat · fluentpath · implementers

Stream: implementers

Topic: fluentpath


view this post on Zulip Grahame Grieve (Apr 02 2016 at 04:57):

I have some questions about fluent path based on implementing it

view this post on Zulip Grahame Grieve (Apr 02 2016 at 04:59):

when does $this apply? can we say that $this is only available in a function when evaluating parameters, and then only as the proximal value in a parameter, and when you encounter it, it's the object on which the function is being evaluated

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:00):

but that means that it's only the iterator functions (where, select, all)

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:00):

That was my understanding, it would only be available within the iterators.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:01):

k. I'll implement it so. And I'll try and remember to make a ballot comment that we need to be more specific anbout this

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:01):

I'll make a note as well.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:10):

another thing I haven't figured out - how can is and as be operators?

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:10):

I've found that I need special handling for the function parameters for is and as because they are evaluated in the type space, not the instance space.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:11):

but when they'er operators, I don't know how to do that because I process the operands before the operation.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:11):

thoughts?

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:14):

Yeah, they're more like generic operators in that they have a compile-time resolve.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:15):

What we do in the CQL-to-ELM translator is resolve the type at compile-time and save it in the object model.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:15):

hmm. I hadn't thought of it like that. but that implies that there has to be a compile step

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:16):

Well, either that or your run-time has to have some way to resolve a type.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:16):

I've implemented it both ways.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:16):

Do you have a context you could use at run-time to reach into the type model?

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:17):

well, it's not so much that I can resolve a type or not, but that I have to know that I'm in the type space not the instance space

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:18):

Yeah I see that's special case code because of the way the FluentPath grammar is built then.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:19):

should we note that?

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:19):

You basically have to say, if this is an "is" or "as", remember that the operand is an type.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:20):

So, for the "is" and "as" expressions (where they are keywords), we do have a different production rule.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:20):

typeSpecifier

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:20):

But for ".is()" and ".as()", we don't specify those in the grammar at all, so I'm not sure how we would handle that.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:21):

we say that in the definition of the functions. they were easier for me

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:21):

We could introduce specific rules for just those invocations.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:21):

Or....

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:21):

we could introduce a typeof keyword...

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:22):

Then Type would be a type and you could declare the .is() and .as() operators to take arguments of type Type.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:22):

(formatted for clarity)

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:23):

typeof is a keyword in the definitions or the language? it seems retrograde to have to specify it in is() and as()

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:23):

and I can see how to solve it for me - it's similar to the notion of short cut boolean evaluation

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:23):

and I do it a the same point

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:24):

Keyword or method, either way would work.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:24):

well, let's just make sure we ballot about it

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:24):

But if you have a solution, we can just note it as something to add clarifying documentation around.

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:24):

Yep.

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:24):

no point wasting cycles solving it now. it might be solved with better doco, or it might need something more. we can decide later

view this post on Zulip Grahame Grieve (Apr 02 2016 at 05:25):

for now, I know how to implement it, but it is kind of unexpected

view this post on Zulip Bryn Rhodes (Apr 02 2016 at 05:26):

Agreed.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:30):

I have a problem with '-'. Take this expression:

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:31):

Patient.name.given.where(substring($this.length()-3) = 'out')

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:31):

here, - is an operator.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:31):

but take this expression:

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:31):

Patient.name.given.count() > -3

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:32):

- here is part of the constant.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:32):

I don't know how to tell these apart in my lexer

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 04:38):

Could be wrong, I didn't do the stuff in the .net implementation, but could have a look over what Ewout did.
3 tokens at the end of the stream ">", "-", "3"
So you have the "-" token inbetwen an operator and a constant, so it should merge it into the const token.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 04:39):

see, that breaks the separation between the lexer and the grammar

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 04:46):

Yes, tokenizer breaks into the words, then the lexer needs to convert the tokens into correct tree for execution. In this case it is merging those 2 tokens into the constant as the substract operator when following a comparison operator.
I haven't gone that close into the grammar to see how that fits into it.

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 04:46):

(I have been meaning to do that to review Ewout's implementation though)

view this post on Zulip Grahame Grieve (Apr 03 2016 at 05:03):

I'll have to figure that out, I guess

view this post on Zulip Grahame Grieve (Apr 03 2016 at 05:03):

a question:

view this post on Zulip Grahame Grieve (Apr 03 2016 at 05:03):

'12345'.startsWith('') = false

view this post on Zulip Grahame Grieve (Apr 03 2016 at 05:03):

true? or false?

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 05:10):

empty string?

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 05:11):

good question, would also be good question for if the string was null/not found

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 05:11):

maybe that's something that should be defined by the startswith operator

view this post on Zulip Grahame Grieve (Apr 03 2016 at 06:01):

that's why I'm asking. Clearly, if it's empty for some reason, then the string can't start with it. but the empty string is different.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 06:01):

it's not allowed in fhir btw

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 06:02):

but a null is.

view this post on Zulip Grahame Grieve (Apr 03 2016 at 07:34):

Another problem in the spec: the type datetime should be dateTime

view this post on Zulip Brian Postlethwaite (Apr 03 2016 at 08:28):

the only date functions are today() and now(), I think we need some date manipulation functions also.
Lots of validations have date relative features. But I guess that can be added later e.g. dateAdd(month, 12)

view this post on Zulip Bryn Rhodes (Apr 03 2016 at 18:54):

Regarding the unary minus, that should come back from the parser as a unary expression. The Antlr visitor will just do that, are you not using an Antlr generated visitor?

view this post on Zulip Bryn Rhodes (Apr 03 2016 at 19:00):

Regarding '12345'.startsWith(''), startsWith is usually defined in terms of a substring of the same length, which means startsWith('') would return true.

view this post on Zulip Bryn Rhodes (Apr 03 2016 at 19:00):

I'll note that we need to clarify the behavior.

view this post on Zulip Grahame Grieve (Apr 05 2016 at 00:19):

I'm not using an Antlr grammar

view this post on Zulip Grahame Grieve (Apr 05 2016 at 00:19):

I don't like the way all() is defined.

view this post on Zulip Grahame Grieve (Apr 05 2016 at 00:20):

it should take a criteria - does all this collection meet this criteria?

view this post on Zulip Grahame Grieve (Apr 05 2016 at 00:21):

as it is, you have to do select(criteria).all() - but the selection does - or could - drop the cases that don't meet the criteria, so .all() will be true.

view this post on Zulip Grahame Grieve (Apr 05 2016 at 00:21):

it's a lot easier if it's .all(criteria)

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:30):

consider this invariant: entry.where(fullUrl).select(fullUrl+resource.meta.versionId).distinct()

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:31):

if versionId is present, it contributes to the assessment of null. but it might not be. So this invariant fails because:

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:32):

"The math operators require each operand to be a single element. Both operands must be of the same type, each operator below specifies which types are supported."

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:32):

but resource.meta.versionId might not be present

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:32):

at present the only way I could approach this is:

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:32):

entry.where(fullUrl).select(fullUrl+iif(resource.meta.versionId, resource.meta.versionId, '')).distinct()

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:33):

that's painful.

view this post on Zulip Grahame Grieve (Apr 06 2016 at 23:33):

I think I need to bring back & operator

view this post on Zulip Grahame Grieve (Apr 07 2016 at 04:56):

I have brought it back for FHIR.

view this post on Zulip Grahame Grieve (Apr 07 2016 at 04:56):

it's just too finicty to deal with the stupid rules aorund plus that make sense for integers, but not strings

view this post on Zulip Brian Postlethwaite (Apr 08 2016 at 05:07):

Not sure I follow this last one, plus for integers, not strings?
Is the & the concatenation for strings instead of +?

view this post on Zulip Grahame Grieve (Apr 11 2016 at 04:19):

in my implementation, you can do string + String

view this post on Zulip Grahame Grieve (Apr 11 2016 at 04:20):

but if either string is missing, it's an error, according to the rules for +, since they are type safe

view this post on Zulip Grahame Grieve (Apr 11 2016 at 04:20):

& is not type safe - it simply appends left and right as strings together, and ignores missing parameters

view this post on Zulip Grahame Grieve (Apr 11 2016 at 04:21):

I have 2 differences between my implementation and the spec after ignoring the little details above in this topic:
- I have the & operator
- I allow a selector on the .all() operation

view this post on Zulip Grahame Grieve (Apr 11 2016 at 04:22):

hopefully I'll be upgrading both my DSTU2 and Montreal servers to use current fluent path in the next few hours - just doing testing now

view this post on Zulip Bryn Rhodes (Apr 11 2016 at 17:11):

@Grahame Grieve: "but if either string is missing, it's an error, according to the rules for +, since they are type safe" It's not an error, it's just that the result is empty. In CQL we define a _coalesce_ operator that collapses the .iif() logic you have above. So with that operator it would be:

view this post on Zulip Bryn Rhodes (Apr 11 2016 at 17:11):

entry.where(fullUrl).select(fullUrl + resource.meta.versionId.coalesce('')).distinct()

view this post on Zulip Bryn Rhodes (Apr 11 2016 at 17:13):

Having said that, I do like the notion of defining a string concatentation operator that is different than +, and having it treat empty differently would simplify things even further. But I would still propose the need for something like a coalesce operator.

view this post on Zulip Bryn Rhodes (Apr 11 2016 at 17:13):

I'll note the & operator in the FluentPath comments.

view this post on Zulip René Spronk (Apr 11 2016 at 17:52):

I've asked Bryn to speak about CQL (using FluentPath) at the upcoming WGM in Montreal. It would be nice to also have a speaker about FluentPath and its implementation aspects. Any volunteers? We need to spread the word about these two topics somewhat, most in the FHIR user comunity won't have heard about them..

view this post on Zulip Brian Postlethwaite (Apr 12 2016 at 13:55):

Looking to see if there has been any progress on date manipulation operations/functions.
My use cases are for comparing dates 6 or 12 months in past/future, both for validation and defaulting values (in my case with quesitonnaires)

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 15:21):

The current FluentPath specification does not define date/time arithmetic. CQL defines a complete set though, so we have two options 1) incorporate the date/time arithmetic operations, or 2) use full CQL to express your use case.

view this post on Zulip Grahame Grieve (Apr 12 2016 at 19:16):

I think that the preference will be 1, but do we need a complete set?

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 19:45):

We can start with just the date arithmetic definitions to support this particular use case.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 19:48):

so +(dateTime, quantity), +(time, quantity), -(dateTime, quantity), -(time, quantity)

view this post on Zulip Grahame Grieve (Apr 12 2016 at 20:02):

why would we not use + / - for this?

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 20:21):

Agreed, that is the syntax CQL uses.

view this post on Zulip Brian Postlethwaite (Apr 12 2016 at 21:01):

Is it documented how to express a const quantity? do I can represent 1d or -6m or +1y

view this post on Zulip Grahame Grieve (Apr 12 2016 at 21:02):

I don't think it is, but given the complexity, I would define a function....

view this post on Zulip Brian Postlethwaite (Apr 12 2016 at 21:30):

something like a Quantity resource constructor?

view this post on Zulip Grahame Grieve (Apr 12 2016 at 21:53):

quantity(value, unit) or quantity(value, unit, system code)

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:54):

CQL defines a quantity selector, but we did not define that in FluentPath. We talked about adding it, but never reached a decision.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:54):

Nope, I take it back.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:54):

It's in the grammar, just not documented in the md.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:55):

The syntax in the grammar is <NUMBER unit?>

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

Where unit is either a singular or plural date time precision (year(s), month(s), day(s), hour(s), minute(s), second(s), millisecond(s)), or a UCUM unit as a string.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

So you can say:

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

6 months

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

or

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

6 'mo'

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 21:56):

I'll add a comment to document that in the md.

view this post on Zulip Grahame Grieve (Apr 12 2016 at 21:57):

but see, this doesn't deal with questions around the units

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 22:15):

The simplest implementation is to just require that units be respected. A more sophisticated implementation could do conversion where possible.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 22:16):

For date/time arithmetic, it's fairly straightforward, and I imagine most implementations would just pass through to an underlying library to perform the computation.

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 22:16):

For quantity arithmetic, the implementation just needs to ensure that if the values have units, they're the same, or it's an error.

view this post on Zulip Grahame Grieve (Apr 12 2016 at 22:17):

well, which units? we should use ucum units if we're going to have a simple form

view this post on Zulip Bryn Rhodes (Apr 12 2016 at 22:17):

Yeah, the expectation is UCUM units.

view this post on Zulip Grahame Grieve (Apr 12 2016 at 23:13):

that's not what you said above

view this post on Zulip Grahame Grieve (Apr 12 2016 at 23:14):

and I don't understand how that's not grammatically ambiguous

view this post on Zulip Bryn Rhodes (Apr 13 2016 at 01:36):

For the date/time precisions specifically, CQL defines keywords that are synonyms for the UCUM date/time precision.

view this post on Zulip Bryn Rhodes (Apr 13 2016 at 01:42):

As far as ambiguity, there's no other context where an expression is allowed to be followed by a literal like that. It requires lookahead, but I don't think it's ambiguous.

view this post on Zulip Grahame Grieve (Apr 13 2016 at 06:03):

regrding ambiguity, some ucum codes are ambiguous - e.g. *10

view this post on Zulip Grahame Grieve (Apr 21 2016 at 13:38):

So, still working on fluent path quallity....

view this post on Zulip Grahame Grieve (Apr 21 2016 at 13:40):

Lloyd has this series of constraints on Questionnaire Extensions:

view this post on Zulip Grahame Grieve (Apr 21 2016 at 13:40):

valueInteger = 0 or $parent.required
valueInteger <= 1 or $parent.repeats
$parent.type!='display'
$parent.type!='display'
$parent.type='choice' or $parent.type='open-choice'
$parent.type='choice' or $parent.type='open-choice'
$parent.type!='display'
$parent.type='reference'
$parent.type='display'
$parent.type='reference'
$parent.type!='display'
$parent.type='reference'
$parent.type='integer' or $parent.type='decimal'
$parent.type='integer' or $parent.type='decimal'

view this post on Zulip Grahame Grieve (Apr 21 2016 at 13:41):

these are all illegal, and not implementable under the current spec

view this post on Zulip Grahame Grieve (Apr 21 2016 at 13:41):

it's not obvious to me how this should be resolved

view this post on Zulip Lloyd McKenzie (Apr 21 2016 at 13:47):

So the general use-case is the need to be able to make assertions about the context in which an extension is allowed to appear

view this post on Zulip Bryn Rhodes (Apr 21 2016 at 14:10):

Can they be expressed on the parent node in terms of the children instead of on the children in terms of the parent?

view this post on Zulip Lloyd McKenzie (Apr 21 2016 at 14:37):

No because their defined on the extension - and are trying to further constrain the type of node they're allowed to appear on.

view this post on Zulip Bryn Rhodes (Apr 21 2016 at 14:42):

I see, so it's a context invariant. The validation is already doing that with extensions, so it seems like it would work if we had a way to say 'this is a context invariant, evaluate it in terms of the container to which the extension is being applied', rather than 'this is an invariant, evaluate it in terms of the extension'.

view this post on Zulip Grahame Grieve (Apr 21 2016 at 20:01):

I think that makes sense

view this post on Zulip Grahame Grieve (Apr 21 2016 at 22:26):

@Bryn Rhodes : according to fluentpath, .length() can only be used for strings. but we have constraints on date lengths - lots of them - and you could imagine lengths being imposed for decimals and integers in some cases. so I think length() should be applicable to primitives, not strings

view this post on Zulip Grahame Grieve (Apr 21 2016 at 22:27):

and do uris, codes, etc count as strings? avoid that question....

view this post on Zulip Bryn Rhodes (Apr 22 2016 at 14:26):

@Grahame Grieve So for length constraints on decimals and integers, why not express it as a value constraint? value between 1 and 1000, e.g.

view this post on Zulip Bryn Rhodes (Apr 22 2016 at 14:27):

for length constraints on date/times, wouldn't it be better to express it in terms of precision? (i.e. what does date.length() < 4 mean?)

view this post on Zulip Bryn Rhodes (Apr 22 2016 at 14:28):

And for uris, codes, yes, I think those are treated as strings. In the CQL implementation, I'm defining implicit conversions from the FluentPath/CQL primitives to the FHIR types, that should make it totally transparent to the user.

view this post on Zulip Lloyd McKenzie (Apr 22 2016 at 14:37):

Sometimes you want to enforce a pure length. So "-50" and "100" and "2.3" all have a length of "3". That said, that's a fairly low frequency use-case.

view this post on Zulip Bryn Rhodes (Apr 22 2016 at 14:50):

I think in that case, you could always do a value.toString().length() = 3

view this post on Zulip Lloyd McKenzie (Apr 22 2016 at 17:00):

That works for me

view this post on Zulip Grahame Grieve (Apr 22 2016 at 19:29):

well, ok, we could consider something more direct in terms of dates. Precision of dates is particularly frequent thing in constraints.

view this post on Zulip Grahame Grieve (Apr 22 2016 at 19:29):

but what would that look like?

view this post on Zulip Grahame Grieve (Apr 25 2016 at 18:48):

Bryn - I didn't join the ballot pool for FluentPath - can you submit all my comments?

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:46):

Sure, I've tracked them, I'll get them submitted.

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:50):

Regarding the constraints on date precision, within CQL, we would say:

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:50):

month from DatetimeValue is null

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:51):

To enforce that a date/time could only be specified to a year, for example.

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:51):

I imagine the FluentPath for that would look like:

view this post on Zulip Bryn Rhodes (Apr 26 2016 at 16:51):

DateTimeValue.month().isNull()

view this post on Zulip Grahame Grieve (Apr 26 2016 at 17:07):

.exists(). but we haven't defined a date time that works like that.

view this post on Zulip Grahame Grieve (Apr 26 2016 at 17:07):

it's a lot harder to convert to real world constraints like XPath too

view this post on Zulip Ewout Kramer (Apr 27 2016 at 13:44):

So, I missed most of this thread because I must have misclicked in Zulip and it was all marked as read :-(

That was my understanding, it would only be available within the iterators.

I think what is the matter is that in some functions we're not passing VALUES as parameters (like the length into the substring() function), but we're passing functions as parameters, which are lazyly evaluated at the right moment by the function that is called. So, what happens with all() and any() is not that they are iterators, it's that they are functions that are passed (anonymous) functions (or in FP expressions that are lazily evaluated).

So, internally, in my AST after parsing, these functions receive a parameter that's a lambda expression, with $this as the single parameter. That would be compatible with just allowing $this in these iterators (though currently, $this works everywhere in the expressions on .NET)

view this post on Zulip Grahame Grieve (Apr 27 2016 at 13:45):

but it's not definable what $this actually is in any other case

view this post on Zulip Ewout Kramer (Apr 27 2016 at 13:48):

Informally, it's the outcome of the last statement before the "." invocation. Even if we would not allow it everywhere, it's present everywhere. I have assumed that:

Patient.name.substring(length()-4,2) is actually Patient.name.substring($this.length()-4,2). Isn't that equivalent? So you need to have $this available everywhere anyway?

view this post on Zulip Grahame Grieve (Apr 27 2016 at 13:49):

I could only read Patient.name.substring(length()-4,2) to mean that length refers to the collection of names from Patient.name

view this post on Zulip Ewout Kramer (Apr 27 2016 at 13:59):

Right. Which in my interpretation means $this refers to the collection of names from Patient.name. Removing $this means removing the possibility for the user to refer back to that resultset. Why would we do that?

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:00):

I don't understand. allowing $this implies that there's some other choice

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:00):

and, in fact, that's how I found it being used

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:00):

trying to refer a step further back

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:01):

Yeah I see that's special case code because of the way the FluentPath grammar is built then.

It's turned into a separate AST node type indeed, since it's so special. I was reassured when I saw the .NET LINQ compiler treats these kind of nodes as a special case as well: https://msdn.microsoft.com/en-us/library/system.linq.expressions.typebinaryexpression(v=vs.110).aspx

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:02):

(from the doc: TypeBinaryExpression Represents an operation between an expression and a type)

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:07):

Grahame Grieve: I don't like the way all() is defined.
Grahame Grieve: it should take a criteria - does all this collection meet this criteria?

Agree. I thought it was defined that way, I even put an example in the text that suggest it does ;-)

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:07):

yeah. Bryn defined it differently, but I just treated it as if it took a criteria throughout the FHIR invariants

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:08):

Regarding '12345'.startsWith(''), startsWith is usually defined in terms of a substring of the same length, which means startsWith('') would return true.

For what it's worth, the .NET StartsWith() function would return 'true' in this case.

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:13):

I think I need to bring back & operator

So, this would the first case where an operator does NOT propagate empty..I worry that this would be a source of confusion, though I do understand why you'd do it. Maybe coalesce() would be a better option.

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:13):

that just moves the deck chairs

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:14):

but no, it's not about propgating empty - I don't use it on {} and expect to get anything but {}

view this post on Zulip Ewout Kramer (Apr 27 2016 at 14:16):

But it is about propagating empty. We've defined ALL our operators to propagate empty: 3+{}={}, "adfadfs" + {} = {}. Now we want "asdfadf" + {} = "asdfadf". So the new & would NOT propagate empty anymore. Or would convert empty to '' automatically if you want. I think that is confusing.

view this post on Zulip Grahame Grieve (Apr 27 2016 at 14:24):

well, ok. but it's absolutely what is needed - to swallow nothing into nothing in the string. You might tihnk it's confusing, but try writing an expression without it - stringing your iif()s together... yuck

view this post on Zulip Brian Postlethwaite (Apr 27 2016 at 21:48):

Ah the joys of timezones.
We added the today/now expression in fluentpath (great).
My new question is how do we communicate the intended timezone for evaluation?
The expected answer is "the person who is calling the operation"
But what about when the server and client are in different timezones, how is this offset handled? Can we have a standard way to communicate this to the Evaluation engines?
Set of parameters that can be provided to the evaluator for execution.

view this post on Zulip Ewout Kramer (Apr 28 2016 at 02:29):

Brian can you explain to me what the intended timezone for evaluation is? Is that the preferred timezone the datetimes are expressed in? As longs as each of the instances of dateTime's has a timezone when the hour component is there, what's the use of passing in the "actual" timezone?

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 03:30):

the today or now functions.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 03:30):

rest of them, yes you're right.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 03:31):

actually, really only today.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 03:31):

comparisons should be ok where there are all timezones. But when only considering the date part, the timezone is important.

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:19):

no I don't follow

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:22):

consider a fhirpath validation rule that says
Appointment.Start >= today()

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:23):

today evaluates to 28 April 2016 (here in australia) but in USA this might evaulate to 27 April 2016 and thus rule will fail.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:24):

So the zone where the evaluation of the rule occurs makes a difference here.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:24):

(This is basically the rule that we have failing)

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:25):

this is a question about your pre-conditions. If you're actually running this about Australia, then that's correct.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:26):

Our deployment is Server in Melbourne, clients in Adelaide and Perth. So part of the day has issues submitting forms.

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:27):

well, you can't make a rule that's so simple as appointment.start > today - the rule itself lacks expressivity

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:27):

appointment.start.universal() >= today().universal()

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:39):

(in the case I'm working with both properties are dates)

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:39):

In the questionnaire

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:41):

so?

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:41):

The complete rule that I can't express is
today() < date1 < date2 < today().add(6, months)

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:41):

why can't you express that?

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:42):

Can't add the months part at the end, and the timezone issue with evaulating today()

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:42):

apart from that, is ok.

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:42):

well, the general issue is: need date and time functions on the date/time class

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:43):

yes, and the zone for evaluating today, and I'd be happy

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:47):

I don't follow about the timezone for today bit, What's that got to do with the expression?

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:54):

if the execution is done in a different timezone to the client, then the value may be different

view this post on Zulip Grahame Grieve (Apr 28 2016 at 06:54):

what's that got to do with the expresssion?

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:55):

Expression is correct.

view this post on Zulip Brian Postlethwaite (Apr 28 2016 at 06:56):

evaluation isnt

view this post on Zulip Elliot Silver (Apr 28 2016 at 18:19):

Interesting. We had this same discussion in IHE yesterday related to XDS submission/queries.
How do I find encounters handled by the night shift (not necessarily during my night, but during the night where it occured)? Documents submitted in the morning? The TZ offset at the querying client isn't necessarily the same as the offset at the server, or the offset at the system that submitted the resource. And, the time zone in effect at any of those today, isn't necessarily the same as the offset in effect when the resource was submitted.

view this post on Zulip Brian Postlethwaite (Apr 29 2016 at 04:15):

Has also found a bug in the dotnet fluentpath implementation...
We cache the execution tree to reduce the amount of re-parses are required.
And then the first execution turns the today() into the value, and is not exectuted again, even when the value changes - which is worse when implementing the now() function.

view this post on Zulip Bryn Rhodes (Apr 29 2016 at 04:36):

So, in the CQL definitions of Today() and Now(), we define them to return the same value for a given "evaluation", and we define them to return based on the "evaluation request time", which is left somewhat open, but would typically be tied to the request date time (or an "evaluateAsOf" parameter if you wanted to support evaluation as of a certain point in time).

view this post on Zulip Bryn Rhodes (Apr 29 2016 at 04:37):

This way the engine can support caching within any given evaluation, but not across them, and the expression result is guaranteed to be deterministic.

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 00:30):

Question to others that are implementing and/or testing this.
Should these 2 expressions parse and evaluate correctly?
1 < 2
1 < -2
+1 < +2

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 00:31):

The dotnet fluentpath evaluator doesn't handle the inclusion of the negative (or positive)

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 00:32):

or this one
-1<2

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 00:35):

the notepad++ fhir addin really doesn't like these either.

view this post on Zulip Bryn Rhodes (Apr 30 2016 at 00:44):

The FluentPath grammar supports them, and the CQL/FluentPath translator I'm working on handles them, but I don't think the other implementations are using the generated Antlr visitors. And IIRC, the initial FhirPath used to treat unary negation as part of the number literal rather than as a separate syntax, so that could be holdover behavior.

view this post on Zulip Grahame Grieve (Apr 30 2016 at 00:54):

the notepad++ plug-in should accept them. I'll add tests for them. I would have thought that negation is ok but not +

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 01:03):

I wouldn't be fussed by the absense of the +
I found it testing an implementation of an experimental dateadd('mm', -6) function with the dotnet client

view this post on Zulip Grahame Grieve (Apr 30 2016 at 01:10):

fixed in both the java and pascal implemnetations. will release updates to notepad++ and my server soon

view this post on Zulip Brian Postlethwaite (Apr 30 2016 at 01:12):

Thanks Grahame, I'll look forward to testing it out.

view this post on Zulip Grahame Grieve (May 02 2016 at 02:25):

@Bryn Rhodes is it too late to add ballot comments on fluentpath?

view this post on Zulip Lloyd McKenzie (May 02 2016 at 02:46):

Close is tomorrow, so shouldn't be

view this post on Zulip Bryn Rhodes (May 02 2016 at 03:01):

Hi Grahame, nope, if you get them to me now I can still add them in.

view this post on Zulip Grahame Grieve (May 02 2016 at 03:04):

2 FHIR specific additions:
- we need a concise way to say 'no modifier extensions except for these ones'. Right now I'm not sure how I'd actually do that one
- we need a .slice(structure, name) operation that allows an author to select a particular slice as defined in the referenced structure definition

view this post on Zulip Bryn Rhodes (May 02 2016 at 03:26):

Captured.

view this post on Zulip Grahame Grieve (May 02 2016 at 06:38):

thanks

view this post on Zulip Brian Postlethwaite (May 02 2016 at 06:44):

I'd also like to propose a date based function "dateadd" that takes 2 parameters
1. datepart (yy, mm, dd, hh, mi, ss) as a string (happy if other literals are used, pulled these from TSQL)
2. value (the number of units to add to that part of the date)

This will then permit the creation of an invariant like:
valueDate < today().dateadd("mm", 6)
To cover a business rule for things like must be reviewed within 6 months.

view this post on Zulip Grahame Grieve (May 02 2016 at 06:45):

we've got - generally - the need for date operations/operators in the ballot comments

view this post on Zulip Brian Postlethwaite (May 02 2016 at 06:47):

Just wanted to be sure someone had put in a ballot comment for it.

view this post on Zulip Brian Postlethwaite (May 02 2016 at 06:47):

The above is what I have put in as an experimental while I wait for an official function.

view this post on Zulip James Agnew (May 02 2016 at 15:20):

The FP for Patient:deceased seems decidedly wrong: Patient.deceased.exists() since this returns true if the value of Patient.deceased is false

What's the right way to report this? Tracker?

view this post on Zulip James Agnew (May 02 2016 at 18:09):

Hmm, I could swear I posted in this topic already. What's going on here? Oh well, take two.. From the latest SVN trunk:

Patient:deceased specifies the path Patient.deceased.exists() which seems wrong, since it will evaluate to true if the patient has a populated value of false

Practitioner:phone specifies the path Practitioner.telecom.where(system='email') or Practitioner.practitionerRole.telecom.where(system='email'), which evaluates to a boolean instead of two separate expressions. Should that or be a | like other "joined" expressions use?

view this post on Zulip James Agnew (May 02 2016 at 18:19):

oh... now both posts are here. sorry, Zulip is being flaky on me.

view this post on Zulip Grahame Grieve (May 02 2016 at 18:24):

"The FP for Patient:deceased " - what FP? invariant? index?

view this post on Zulip Grahame Grieve (May 02 2016 at 18:24):

yes the second should be |

view this post on Zulip James Agnew (May 02 2016 at 20:01):

Oh sorry, for deceased search parameter

view this post on Zulip James Agnew (May 02 2016 at 20:05):

The problem of course being that with the way that FP is written, a search for Patient?deceased=true will match any patient that has a value for Patient.deceased, whether that value is true or false.

view this post on Zulip Grahame Grieve (May 02 2016 at 20:36):

yes that is wrong

view this post on Zulip James Agnew (May 02 2016 at 21:59):

Would these require a tracker item, or can I just fix them?

view this post on Zulip Grahame Grieve (May 02 2016 at 22:28):

I think you can just fix them and use tracker....

view this post on Zulip Grahame Grieve (May 02 2016 at 22:30):

nah can't find it

view this post on Zulip Bryn Rhodes (May 02 2016 at 22:45):

@Brian Postlethwaite the comment we have so far is to add +(DateTime, Quantity), -(DateTime, Quantity), +(Time, Quantity) and -(Time, Quantity).

view this post on Zulip Bryn Rhodes (May 02 2016 at 22:46):

So for your example that would look like valueDate < today().add(6 'mo')

view this post on Zulip Brian Postlethwaite (May 02 2016 at 23:08):

as long as the quantity can be defined/described to cover each of the components in the date, then all good.

view this post on Zulip Brian Postlethwaite (May 02 2016 at 23:09):

(You can tag me as someone interested in that ballot item if there's a way to do that too)

view this post on Zulip Grahame Grieve (May 07 2016 at 09:19):

sub-topic: reflection in fluent path

view this post on Zulip Grahame Grieve (May 07 2016 at 09:20):

one of the issues in the fluent path ballot is that we need to be able to access the definitions of the element in an expression

view this post on Zulip Grahame Grieve (May 07 2016 at 09:21):

in FHIR, the idea is that you'd do something like:

Observation.value.definition().max - .definition() would return a handle to an ElementDefinition, which you can navigate like any other object.

view this post on Zulip Grahame Grieve (May 07 2016 at 09:21):

I'm not sure what you'd get from .definition in non-FHIR contexts

view this post on Zulip Grahame Grieve (May 07 2016 at 09:23):

but the really interesting thing you want to do here is reason from the semantics in the definition - say, Snomed CT mappings. And to do this in a cross-profile way. E.g. you could define a base (explicit) profile that defines a constraint, and have the constraint refer to a definition that's found in a dictionary rather than an explicit profile (see the HSPC lab profile for an example of this)

view this post on Zulip Grahame Grieve (May 07 2016 at 09:24):

so the natural question that follows is, .definition() refers to the base definition of the spec, but that's not the really useful definition to get hold of. I want the one of the definitions in one of the applicable profiles... but how do I ask for that?

view this post on Zulip Ewout Kramer (May 08 2016 at 13:33):

Maybe the "as" operator should take a url, so you can "cast" to a specific profile....

view this post on Zulip Ewout Kramer (May 08 2016 at 13:34):

By the way, I see this in a lot of examples:

Patient.name.empty().not()

There is however a short-cut in the current version of FP:

Patient.name.exists()

view this post on Zulip Grahame Grieve (May 08 2016 at 13:35):

where do these come from? I thought I want through and replaced all of those

view this post on Zulip Ewout Kramer (May 08 2016 at 13:36):

I saw them in an example you showed yesterday, but I also see others use this on the Zulip chats... (so it was not specifically about the fp's in the spec)

view this post on Zulip Grahame Grieve (May 08 2016 at 13:36):

ok

view this post on Zulip Josh Mandel (May 12 2016 at 15:22):

From http://hl7-fhir.github.io/fluentpath

Patient.contained.all($this is Patient implies age > 10)

Is age a thing?

view this post on Zulip Josh Mandel (May 12 2016 at 15:28):

repeat(projection: expression) : collection

Does repeat here mean something like "recurse" (i.e. repeat the procedure on its own output)?

view this post on Zulip Grahame Grieve (May 12 2016 at 15:30):

age is not a thing. where did you get that from?

view this post on Zulip Grahame Grieve (May 12 2016 at 15:30):

and yes, that's what it means

view this post on Zulip Josh Mandel (May 12 2016 at 15:30):

I got that from the URL I cited before my quotation :p

view this post on Zulip Josh Mandel (May 12 2016 at 15:31):

Does fluentpath express data math enough to say "Patients over 20 years old"? I assume yes but I couldn't figure out how.

view this post on Zulip Josh Mandel (May 12 2016 at 15:31):

now() seems useful... but without date subtraction I can't put it together.

view this post on Zulip Grahame Grieve (May 12 2016 at 15:32):

not right now - ballot comment that we need date operations, and then the answer will be yes

view this post on Zulip Josh Mandel (May 12 2016 at 15:32):

adding.

view this post on Zulip Ewout Kramer (May 13 2016 at 00:26):

This is an example Bryn added, so I guess this is something that's there in the CQM, but not in FHIR. Remember, the examples are not necessarily FHIR anymore ;-)

view this post on Zulip Josh Mandel (May 13 2016 at 01:53):

That's not a great answer for whatever documentation is published in the FHIR build .

view this post on Zulip Ewout Kramer (May 13 2016 at 02:38):

Yeah. I have to get used to that myself too. But that's also the reason for the name change (no more FHIR in the name).

As to publishing, what's the alternative? We've thought a bit about that at HIMSS...an external website with a publishing cycle not connected to the FHIR spec would be one option.

view this post on Zulip Brian Postlethwaite (May 13 2016 at 04:28):

we already noted the date addition logic

view this post on Zulip Brian Postlethwaite (May 13 2016 at 04:31):

Sorry, that was simple manipulation, not diffs of dates (which can return a timespan)

view this post on Zulip Grahame Grieve (May 13 2016 at 07:53):

well, we have to sort out the publication issue

view this post on Zulip Lloyd McKenzie (May 29 2016 at 22:51):

Is the XHTML accessable from within fluentpath? I'm trying to figure out how to write a constraint that says "narrative must be a single string node with no mark-up"

view this post on Zulip Grahame Grieve (May 29 2016 at 23:04):

we haven't said anything about this, but there's no object model for xhtml, and I'm not keen to make one up. This constraint would be easy if we said the xhtml was a string, and you could use a regex (.matches())

view this post on Zulip Lloyd McKenzie (May 29 2016 at 23:33):

So a regex that prohibited tags greater-than? That might work here. It's not going to work well for other use-cases we'd talked about, for example "this element needs to appear in the third row of the first table". There are lots of use-cases for wanting to have fairly strict control over what the narrative looks like. I'd hate to have that go away in the transition from xpath to fluentpath. When you say there's no object model, why not? We have a schema. My impression was that fluentpath would work for anything you could express by schema.

view this post on Zulip Grahame Grieve (May 29 2016 at 23:50):

schema is not quite the same as object model because of... you guessed it.... mixed content

view this post on Zulip Lloyd McKenzie (May 29 2016 at 23:58):

Mixed content isn't really an issue. That's just a "text node". My guess is what really causes grief is there are some parts that are non-ordered - you can specify repeating properties interspersed with other properties.

view this post on Zulip Bryn Rhodes (Jun 06 2016 at 15:43):

Following up on the discussion about reflection in FluentPath, I think the use of .as() to get at the profile information is the right approach, but what structure should be returned in non-FHIR contexts? The documentation says FluentPath works on a "MOF-equivalent type system", so in general we would need to expose a structure that provided that information, yes?

view this post on Zulip Bryn Rhodes (Jun 06 2016 at 15:45):

CQL has a generic "model info" structure that supports this, it's just a simple exposure of classes, could we use that in the general case and then for FHIR specifically, provide a way to access the elementDefinition using the proposed .definition() operator?

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 05:38):

Looking to check if my understanding of using fluentpath with extensions is correct (and I'm not missing something)
Patient.extension.where(url='http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName').valueString

Is how I should read the Mothers maiden name for a patient in a fluentpath expression (for a custom search parameter)

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:19):

yes, but there's a short cut in the FHIR appendix:

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:19):

Patient.extension('http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName').value

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:20):

actually, your first bit was wrong - it's value, not valueString

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 06:22):

And it will work out that it needs to skip the valueString part, and go to @value
xpath fhir:extension[@url='...']/fhir:valueString/@value

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 06:22):

Is that defined in fluentpath, or the localized fhir version?
That's pretty fhir specific.

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:23):

yes, the @value is implicit. The String itself is the value. Think about the json alternative...

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 06:32):

Still seems kinda fhir specific. (happy with that, but appears like a fhir localization)

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:48):

which bit? the extension() bit is for sure

view this post on Zulip Grahame Grieve (Jun 20 2016 at 06:48):

it's documented as a FHIR specific thing

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 06:49):

Thanks, will recheck.

view this post on Zulip Brian Postlethwaite (Jun 20 2016 at 13:31):

does this mean that extension is a reserved word in the fluentpath for fhir?
and thus the syntax/format that I used wouldn't work (as extension is a reserved word)?

view this post on Zulip Grahame Grieve (Jun 20 2016 at 22:30):

.extension() is different to .extension

view this post on Zulip Jason Walonoski (Jun 30 2016 at 12:47):

Question about the fluentpath invariant sdf-12.

Currently it is written as snapshot.element.base implies baseType

Believe it should say snapshot.element.select(base) implies baseType

Can any of the fluentpath experts chime in?

view this post on Zulip Bryn Rhodes (Jun 30 2016 at 13:29):

Those should both work to enforce that invariant, if there are base elements, then there must be a baseType. The first one will give a list of base elements, the second one will give a list of list of base elements, either way, interpreting that list as a boolean is effectively an exists.

view this post on Zulip Brian Postlethwaite (Jul 05 2016 at 12:55):

The fluentpath expression today().toString().length() = 10 that is in the unit tests uses toString on a date. The toString defined here http://hl7-fhir.github.io/fluentpath.html#1.32.4.4 doesn't say what to do with dates.

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

they have an innate string representation

view this post on Zulip Brian Postlethwaite (Jul 05 2016 at 13:03):

given the others were explicitly called out what to do for them, should it also be explicitly stated?

view this post on Zulip Brian Postlethwaite (Jul 05 2016 at 13:04):

(Yes, I've updated it to return the string representation too)

view this post on Zulip nicola (RIO/SS) (Sep 12 2016 at 23:06):

One more query language with implementation: https://stedolan.github.io/jq/manual/.

view this post on Zulip nicola (RIO/SS) (Sep 12 2016 at 23:17):

curl http://spark.furore.com/fhir/Patient?_format=json | jq '.entry[].resource| {lastName: .name[0].family[0], firstName: .name[0].given[0], id: .id}'

Last updated: Apr 12 2022 at 19:14 UTC