Skip to content

feat: Support FHIRPath trace() function#2584

Open
piotrszul wants to merge 10 commits intorelease/9.6.0from
issue/2580
Open

feat: Support FHIRPath trace() function#2584
piotrszul wants to merge 10 commits intorelease/9.6.0from
issue/2580

Conversation

@piotrszul
Copy link
Copy Markdown
Collaborator

@piotrszul piotrszul commented Apr 2, 2026

Summary

  • Implement the FHIRPath trace() function with both unary trace(name) and binary trace(name, projection) forms, logging a string representation of the input collection (or projected values) at TRACE level via SLF4J
  • Add programmatic trace collection via TraceCollector interface, threading trace entries through SingleInstanceEvaluationResult and PathlingContext.evaluateFhirPath()
  • Expose trace entries in the Python API (evaluate_fhirpath() returns a traces list with label and typed values)
  • Fix sanitiseRow() schema misalignment for nested structs — parent StructField dataType now reflects the sanitised nested schema, preventing field-value shifting in Row.json() output

Closes #2580
Fixes #2583

Test plan

  • TraceFunctionTest — pass-through semantics, SLF4J logging at TRACE level, collector capture, error cases
  • ListTraceCollectorTest — trace collector unit tests
  • TraceExpressionTest — unary and binary trace expression evaluation
  • test_evaluate_fhirpath.py — Python API tests covering basic results, return types, context expressions, variables, trace output structure, and error handling
  • YAML reference tests pass (trace projection exclusion removed now that feature is implemented)
  • SingleInstanceEvaluatorTest — nested struct schema alignment and JSON output correctness

🤖 Generated with Claude Code

piotrszul and others added 2 commits March 31, 2026 11:46
Add the trace(name) function which logs a JSON representation of each
evaluated value via SLF4J, then returns the input collection unchanged.
This uses a custom Spark Catalyst expression (TraceExpression) to
produce the logging side effect during query evaluation.

The optional projection parameter is not yet supported. Two YAML
reference test exclusions are added for the projection parameter and
a known limitation with primitive .id extension access after trace.

Closes #2580

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce TraceCollector interface and ListTraceCollector for capturing
trace() output during FHIRPath evaluation. The collector is threaded
through EvaluationContext into TraceExpression, which now carries
FHIR type metadata alongside the trace label.

A TraceCollectorProxy (serializable, static registry) wraps the
list collector to survive Spark plan serialization. SingleInstance
Evaluator creates a collector per evaluation, expands array values
into individual trace entries, and includes them in the result DTO.

Python bindings return trace data in the result dict under a 'traces'
key with label, type, and values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-project-automation github-project-automation bot moved this to Backlog in Pathling Apr 3, 2026
@piotrszul piotrszul added fhirpath Related to fhirpath reference implementation new feature New feature or request python Pull requests that update Python code labels Apr 3, 2026
@piotrszul piotrszul moved this from Backlog to In progress in Pathling Apr 3, 2026
piotrszul and others added 8 commits April 7, 2026 11:16
…race collection

Cover proxy delegation, close semantics, buildTraceResults grouping and
value expansion, and end-to-end evaluate() with trace() expressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sanitiseRow() stripped null/synthetic fields from nested Rows but kept
the parent StructField pointing at the original schema. Spark's
Row.json() uses the parent's dataType to positionally map nested values,
causing field-value misalignment in JSON output.

Fixes #2583

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Guard TraceExpression hot-path conversion behind log level check, unify
Optional usage for trace collector across builders, deduplicate value
conversion logic, and extract shared typed-value helper in Python API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document that TraceExpression intentionally skips null values via
nullSafeEval. Remove redundant fhirType field from TraceResult — the
per-value type in TypedValue is sufficient. Document the literal-only
limitation for the trace name argument.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The FHIRPath trace() function now accepts an optional second argument
(projection expression) that is evaluated against the input and logged,
while the input collection is still returned unchanged. Also marks
TraceExpression as Nondeterministic to prevent Catalyst from optimizing
away logging side effects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ble evaluation

Chained traces like trace('inner').trace('outer') caused the inner
expression to fire exponentially due to the binary form evaluating both
children independently with Nondeterministic preventing caching.
TraceExpression is now unary (no projection) and TraceProjectionExpression
is binary (with projection), with shared logic in TraceHelper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the shared SLF4J logger into TraceHelper so both TraceExpression
and TraceProjectionExpression use the same instance, and remove the
redundant log parameter from logAndCollect.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eter

The trace(name, projection) feature is now implemented, so the exclusion
that expected this test to error is no longer needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

@johngrimes johngrimes self-requested a review April 10, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fhirpath Related to fhirpath reference implementation new feature New feature or request python Pull requests that update Python code

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

1 participant