Skip to content

feat: Support FHIRPath trace() function#2584

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

feat: Support FHIRPath trace() function#2584
piotrszul wants to merge 6 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 (first argument only) that logs a string representation of the input collection using the name argument, then returns the input unchanged
  • 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)
  • Log trace output at TRACE level via SLF4J
  • 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
  • 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 with new exclusions for unsupported trace() projection argument
  • 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 4 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>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 7, 2026

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