Skip to content

v9.1.0#2520

Merged
johngrimes merged 80 commits intomainfrom
release/9.1.0
Nov 24, 2025
Merged

v9.1.0#2520
johngrimes merged 80 commits intomainfrom
release/9.1.0

Conversation

@johngrimes
Copy link
Member

@johngrimes johngrimes commented Nov 20, 2025

This release includes significant enhancements to FHIRPath and SQL on FHIR functionality, along with improvements to the Python and R APIs.

Key features

Conversion functions

Implemented toQuantity() and convertsToQuantity() FHIRPath conversion functions with full UCUM unit conversion support. These functions now support optional unit parameters for converting quantities between different units, with proper handling of both multiplicative and additive conversions via the ucumate library.

Repeat directive for SQL on FHIR

Added support for the repeat directive in SQL on FHIR view definitions, enabling recursive traversal of nested structures such as QuestionnaireResponse items. The traversal depth is configurable via query configuration.

Query configuration in APIs

Exposed query configuration options in both Python and R APIs, allowing users to customise query behaviour including repeat traversal depth. Implemented a builder pattern for PathlingContext with type-safe configuration access via the Configurable interface.

Improvements

  • Enhanced UCUM integration with support for calendar duration conversions and canonical value handling
  • Improved projection handling with new selection interfaces (UnarySelection, CompositeSelection) for better structure and clarity
  • Added comprehensive test coverage for conversion functions, encoding configuration, and nested item structures
  • Refactored quantity column operations with the new QuantityValue class
  • Updated conversion logic to use try_cast for compatibility with Spark 3.6 behaviour
  • Added QuestionnaireResponse test data generator and benchmark

piotrszul and others added 30 commits October 17, 2025 16:12
…L types; enhance date and time validation in DSL tests
…unctions

Lazy singularity checks from asSingular() were not being evaluated when
conversion functions returned without using the column value, causing
array error tests to fail. Added ensureSingular() method to force
constraint evaluation on the original input before singularization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…n FHIRPath spec lookup and third-party code lookup on Github.
Added comprehensive test cases for empty typed fields across all 14
conversion functions (toBoolean, toInteger, toDecimal, toString, toDate,
toDateTime, toTime, and their convertsTo variants). Empty typed fields
now correctly return empty results instead of boolean values.

Enhanced null handling in performConversion and performValidation to
properly detect and handle empty typed collections that maintain type
information but contain null data values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed IntelliJ/Sonar warnings to improve code maintainability:
- Replaced single-case switch statements with if statements
- Fixed javadoc warnings by using {@code} tags for boolean literals
- Removed unnecessary lambda parentheses

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Streamlined performConversion() and performValidation() template methods
by eliminating intermediate variables and using functional composition with
Optional.map(). This reduces cognitive load and makes the conversion flow easier to follow.

Enhanced type safety by adding @nonnull annotations to column representation
methods and all conversion functions. Standardize null handling to use lit(null) instead of bare null for consistency with Spark SQL Column semantics.

These changes improve maintainability while preserving all existing behavior and test coverage.
Introduced static registries in ConversionLogic and ValidationLogic to
automatically determine the appropriate conversion/validation function
and collection builder based on the target FHIRPath type. This eliminates
redundant parameters from template methods, simplifying the API from
4 parameters to 2 for conversions and 3 to 2 for validations.

Registries map FhirPathType enum values to their corresponding function
implementations using method references, centralizing the type-to-function
mapping logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…tions

Implemented FHIRPath toQuantity() and convertsToQuantity() functions per
specification, supporting conversion from Boolean, Integer, Decimal, and
String types to Quantity values.

Key features:
- Boolean conversion: true → 1.0 '1', false → 0.0 '1'
- Numeric conversion: wraps Integer/Decimal in quantity with unit '1'
- String parsing: supports UCUM units ('10 \'mg\''), calendar durations
  ('4 days'), and numeric values without units ('42' → '42 \'1\'')
- Optional unit parameter: added with UnsupportedFhirPathFeatureError for
  future UCUM unit conversion support

Implementation details:
- Created StringToQuantity UDF for parsing FHIRPath quantity literals
- Added QuantityEncoding.encodeFromFhirpath() to convert FhirpathQuantity
  to Row representation with proper canonicalization
- Updated QUANTITY_REGEX in FhirpathQuantity and ConversionLogic to make
  unit optional per FHIRPath spec
- Enhanced null handling in encodeNumeric() to return fully null structs
  for null values, maintaining FHIRPath empty collection semantics
- Restricted bareword calendar duration validation to valid units only
  (year, month, week, day, hour, minute, second, millisecond)

Testing:
- Added comprehensive DSL tests (40 test cases) covering all conversion
  scenarios
- Added YAML test exclusions for known limitations:
  * Null values in collections converting incorrectly
  * Calendar duration vs UCUM quantity comparisons not supported

All existing tests pass. YamlReferenceImplTest shows 1821 tests with 0
failures, 1 error (equivalence operator issue under investigation), and
1116 skipped tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added FhirPathType.NOTHING enum value to explicitly represent empty
collections and unknown types, replacing Optional.map().orElse() pattern
in both ConversionLogic and ValidationLogic.

Key changes:
- Added NOTHING type mapping to DataTypes.NullType and EmptyCollection
- Updated ConversionLogic to use NOTHING as default for unknown types
- Updated ValidationLogic to use NOTHING as default for unknown types
- Simplified type handling from Optional.map().orElse() to explicit
  orElse(FhirPathType.NOTHING) pattern in both classes

Benefits:
- More explicit and type-safe conversion/validation logic
- Consistent pattern across ConversionLogic and ValidationLogic
- Better null/void type handling in coalesce operations
- Cleaner, more readable code

Fixes:
- Resolved equivalence operator (~) error when comparing quantities from
  different systems (calendar duration vs UCUM)
- Prevents INVALID_EXTRACT_BASE_FIELD_TYPE errors in complex expressions

Testing:
- Updated YAML test exclusions for calendar duration comparison cases
- All YamlReferenceImplTest tests pass: 1821 tests, 0 failures, 0 errors
- All ConversionFunctionsDslTest tests pass: 259 tests, 0 failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Refactored QuantityEncoding to work exclusively with FhirpathQuantity
instead of org.hl7.fhir.r4.model.Quantity:

- Removed old encode(Quantity) and decode()→Quantity methods
- Renamed encodeFromFhirpath() to encode() and decodeToFhirpath() to decode()
- Updated QuantityToLiteral to use FhirpathQuantity-based decode()
- Updated StringToQuantity to use renamed encode() method
- Removed FHIR Quantity imports where no longer needed

This establishes FhirpathQuantity as the canonical representation for
quantities throughout the FHIRPath evaluation engine.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… formatting

Improved string conversion for decimals and quantities:

- DecimalToLiteral: Changed toString() to toPlainString() to avoid
  scientific notation (e.g., "1E+10" → "10000000000")
- QuantityToLiteral: Added stripTrailingZeros() to remove unnecessary
  trailing zeros (e.g., "1.000000 '1'" → "1 '1'")
- Updated test expectations to match cleaner output format

This produces more readable and concise string representations while
maintaining numerical accuracy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive documentation for implementing new FHIRPath features:
- Specification & research phase guidance
- Core implementation steps with package references
- Testing requirements and procedures
- Iteration & refinement best practices
- Review & commit workflow
- Discovery patterns for learning from existing code

Added important policy note for test exclusions:
- Require user approval before adding exclusions to config.yaml
- Mandate proper justification with comments and issue references
- Document exclusion types (feature, bug, wontfix, etc.)

This documentation helps both human and AI developers understand
the standard workflow and policies for extending FHIRPath functionality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ToQuantity()

Adds support for the optional unit parameter in FHIRPath conversion functions, enabling unit-specific validation for quantity conversions. Implements exact string matching on unit field per FHIRPath spec allowance; full UCUM unit conversion and calendar duration conversion deferred to future issues #2504 and #2505. Refactors tests to use more idiomatic testTrue()/testFalse() assertions for improved readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Introduces QuantityValue in fhirpath.column package to unify all Quantity-related SQL column operations. Moves ValueWithUnit record from QuantityComparator into QuantityValue as a public nested record, making it reusable across the codebase.

Key improvements:
- Better package organization: fhirpath.column.QuantityValue (was sql.misc.SQLQuantity)
- Clearer naming: originalValue(), normalizedValue() methods
- Enhanced factory methods: normalizedValueOf(), originalValueOf(), literalValueOf()
- Convenience API: Added QuantityValue.of(ColumnRepresentation) overload with automatic singularity checking
- Simplified implementations: QuantityCollection uses map() with QuantityValue, QuantityComparator delegates to QuantityValue methods
- Added UNIT_COLUMN constant to QuantityEncoding for consistency
- Eliminated ~60 lines of code duplication from QuantityComparator

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
# Conflicts:
#	fhirpath/src/main/java/au/csiro/pathling/fhirpath/encoding/QuantityEncoding.java
#	fhirpath/src/main/java/au/csiro/pathling/sql/misc/QuantityToLiteral.java
…patibility with Spark 3.6 behaviour in ConversionLogic and ValidationLogic.
…nvertsToQuantity(unit)

Implements issue #2504 by adding complete UCUM unit conversion support using the
ucumate ConverterService. Previously, these functions only supported exact string
matching between units.

Key changes:
- Add FhirPathQuantity.convertToUnit() method with UCUM conversion logic using
  ConverterService.convert() for cleaner, more maintainable code
- Create ConvertQuantityToUnit Spark UDF that delegates to FhirPathQuantity
- Add QuantityValue.isUcum() and isCalendarDuration() helper methods
- Fix short-circuit optimization in QuantityValue.toUnit() and convertibleToUnit()
  to check system field, preventing incorrect conversions for non-UCUM quantities
  (e.g., Money with system "urn:iso:std:iso:4217")
- Update ConversionFunctions documentation to reflect full UCUM conversion support
- Refactor tests: separate by parameter presence (no-unit vs with-unit) with
  comprehensive coverage of UCUM conversions
- Remove test exclusions from config.yaml for UCUM conversion tests

Technical implementation:
- Leverages io.github.fhnaumann.funcs.ConverterService for direct unit conversion
  instead of manual canonicalization, reducing code from ~83 to ~42 lines
- Maintains backward compatibility: exact string match as fast path, UCUM
  conversion as fallback
- Calendar duration conversions reserved for future work (issue #2505)

Test results: 337 tests pass, 0 failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…cross conversion functions and related classes
…IRPath calendar duration units and conversions
# Conflicts:
#	fhirpath/src/main/java/au/csiro/pathling/fhirpath/CalendarDurationUnit.java
…it and update FhirPathQuantity method names for consistency
…ures. Adding unit test for exact ConversionFactor applications. Removing 'claude.md' which should have been ignored.
…ructures

Implements issue #2481 - adds repeat directive to SQL on FHIR view runner for automatic flattening of hierarchical data to any depth.
@github-project-automation github-project-automation bot moved this to Backlog in Pathling Nov 20, 2025
@johngrimes johngrimes moved this from Backlog to In progress in Pathling Nov 20, 2025
Add a "Supported versions" section documenting that Pathling requires
Apache Spark 4.0.x. Also update the R example to use Spark 4.0.1 instead
of the outdated 3.5.6 version.

Resolves #2356 (comment)
Add tests demonstrating issue #2519 where getResourceKey() returns
versioned IDs (e.g., Patient/123/_history/1) while getReferenceKey()
returns unversioned references (e.g., Patient/123), causing join
mismatches.

Encoder tests verify:
- meta.versionId does not affect id_versioned column
- IdType with version produces full versioned reference in id_versioned

DSL test (currently failing) verifies:
- getResourceKey() should return unversioned key matching reference format

See: #2519
Changes getResourceKey() to construct keys using resourceType + "/" + id
instead of using the id_versioned column. This ensures that resources with
versioned IDs return keys that match the format used by getReferenceKey(),
enabling correct joins between resources and their references.

Fixes #2519
@johngrimes johngrimes merged commit 19e1fbe into main Nov 24, 2025
4 checks passed
@johngrimes johngrimes deleted the release/9.1.0 branch November 24, 2025 09:49
@github-project-automation github-project-automation bot moved this from In progress to Done in Pathling Nov 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Pull request that represents a new release

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants