@synanetics/fhir-sort
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

@synanetics/fhir-sort

This package provides an implementation of in memory sorting of FHIR Resources.

Features

  • FHIR STU3 and R4.
  • Sorting FHIR Bundles and arrays of FHIR resources.
  • Custom SearchParameters can be provided in addition to, or replacement of, default SearchParameters
  • Specialised sorting on most FHIR complex data types (e.g FHIR.HumanName)
  • Chained sort terms, to a single depth
  • Sort term validation

Limitations

  • The sorter can only sort resources of the same resource type
    • A bundles "matches" have the same resource type
    • A resources array's values must have the same resource type
    • Included resources, whether in a Bundle or includedResources array, can be of any type
  • For Bundles, the sorter is designed to just support the searchset type
  • The sorter does not follow resource orders that are prescribed in Bundle types
    • E.G The message Bundle type which requires MessageHeader in entry[0]
    • Note: that such Bundles likely have different resource types, and thus are not supported at all

Example Usage

const {
  FhirSorter
} = require('@synanetics/fhir-sort');
// or
import {
  FhirSorter
} from '@synanetics/fhir-sort';

const r4Sorter = new FhirSorter('r4');
const stu3Sorter = new FhirSorter('stu3');

const unsortedBundle: Bundle = {
  resourceType: 'Bundle',
  type: 'searchset',
  total: 3,
  entry: [
    {
      resource: {
        resourceType: 'Patient',
        name: [{
          given: ['Mark'],
          family: 'South',
        }],
      },
    },
    {
      resource: {
        resourceType: 'Patient',
        name: [{
          given: ['Rex'],
          family: 'Ford',
        }],
      },
    },
    {
      resource: {
        resourceType: 'Patient',
        name: [{
          given: ['Adam'],
          family: 'Ford',
        }],
      },
    },
  ]
}

const sortedBundle: Bundle = r4Sorter.sortBundle(unsortedBundle, ['name'], 'Patient');

// Expected output
const sortedBundle: Bundle = {
  resourceType: 'Bundle',
  type: 'searchset',
  total: 3,
  entry: [
    {
      resource: {
        resourceType: 'Patient',
        name: [{
          given: ['Adam'],
          family: 'Ford',
        }],
      },
    },
      {
        resource: {
          resourceType: 'Patient',
          name: [{
            given: ['Rex'],
            family: 'Ford',
          }],
        },
      },
    {
      resource: {
        resourceType: 'Patient',
        name: [{
          given: ['Mark'],
          family: 'South',
        }],
      },
    },
  ]
}

FhirSorter Constructor

const sorter = new FhirSorter(fhirVersion, customSearchParameters, fhirModel);

Arguments

fhirVersion

  • String, either 'stu3 or 'r4'
  • Used to determine default SearchParameters and FHIR model

customSearchParameters

  • This is an optional argument if it is not provided the default SearchParameters for the selected FHIR version will be used
  • Object containing fields mode and searchParameters
    • mode: String, either 'replace' or 'concat'
    • searchParameters: an array of FHIR SearchParameter resources
  • When mode = replace, the provided SearchParameters will be used instead of the default SearchParameters
  • When mode = concat, the provided SearchParameters will be used in addition to the SearchParameters

fhirModel

  • FhirModels are defined in the fhirpath npm package
  • See: https://www.npmjs.com/package/fhirpath
  • It is utilised by the package to determine the type of an evaluated value
  • Example Patient.name = FHIR.HumanName
  • This is an optional argument if it is not provided the default FhirModel for the selected FHIR version will be used
  • This package supports custom FhirModels, but does not support combining custom and default FhirModels
  • It is intended that future versions of this package will not rely on user knowledge of this third party interface

FhirSorter.sortArray

const sorted = sorter.sortArray(resources, sortTerms, resourceType, allowChainedSort, includedResources);

Arguments

resources

  • An unsorted array of FHIR resources to be sorted

sortTerms

  • An array of strings where each string is SearchParameter code
  • e.g ['name', '_lastUpdated']
  • By default the sort order is ascending
  • A sort term can be prefixed with - to make the sort order descending
  • e.g ['-name', '-_lastUpdated']
  • If a SearchParameter related to a sort term cannot be found, an error will be thrown

resourceType

  • A string which is the resourceType that is to be sorted
  • e.g 'Patient'

allowChainedSort

  • allowChainedSort is a boolean that defaults to false
  • If it is true then sorting on chained sort terms is allowed

includedResources

  • This is an optional argument that is only required for chained sorts
  • includedResources is an array of FHIR resources that would be 'included' in the Bundle response of a FHIR search query

Return value

  • This function returns a sorted array of FHIR resources

FhirSorter.sortBundle

const sorted = sorter.sortBundle(bundle, sortTerms, resourceType, allowChainedSort);

Arguments

bundle

  • An unsorted FHIR Bundle resources
  • The entries to be sorted are expected to have search.mode = match

sortTerms

  • An array of strings where each string is SearchParameter code
  • e.g ['name', '_lastUpdated']
  • By default the sort order is ascending
  • A sort term can be prefixed with - to make the sort order descending
  • e.g ['-name', '-_lastUpdated']
  • If a SearchParameter related to a sor term cannot be found, an error will be thrown

resourceType

  • A string which is the resourceType that is to be sorted
  • e.g 'Patient'

allowChainedSort

  • allowChainedSort is a boolean that defaults to false
  • If it is true then sorting on chained sort terms is allowed

Return value

  • This function the input bundle with its matched entries sorted

Chained Sorting

  • Chained sorting is not part of the default FHIR specification however it is supported here to a single depth
  • To perform a chained sort, pass in a chained sort term, and set allowChainedSort to true
    • e.g chained sort term for Patient resource: 'general-practitioner.name'
    • With this example sort term, the sorter would sort Patients based on their general practitioner's name
    • Note that a general practitioner could be a Practitioner, Organization or PractitionerRole
    • A sort term that is valid for one may not be valid for others. E.G 'family' is only a valid sort term for Practitioner
    • The sorter will allow any chained sort term as long as it is valid at least one of of the possible resource types
  • The sorter will attempt to resolve the sort using resources "included" in the input Bundle for sortBundle, or the includedResources array for sortArray
  • For the sorter to find the appropriate included resource, it must be referenced in the base resource with a relative reference
    • e.g 'Practitioner/12345'
  • If a chained sort term is passed in, and the allowChainedSort argument is false, an error will be thrown
  • If a chained sort term with depth > 1 is passed in an error will be thrown
    • e.g 'general-practitioner.partof.name'

How Values Are Sorted

Multiple Values

  • If a given field has multiple possible values, such as Patient.family, the most 'favourable' value is taken
  • e.g when sorting if a patient had three names with family values: 'Banana', 'Pear' and 'Apple:
    • 'Apple' would be used in the final sort when sorting ascending.
    • 'Pear' would be used in the final sort when sorting descending.

Undefined values

  • Undefined values will always appear at the end of the sort regardless of sort order

Normalising DataTypes

All data types are normalised before sorting, and then sorted based upon their sort order

Data Type Normalisation
FHIR.Address
  • Normalised to a string containing each 'line' of the address concatenated followed by the 'postcode'
  • All values are converted to lowercase
FHIR.Annotation
  • Normalised to a string containing 'time' 'text'
  • 'text' is converted to lowercase
FHIR.CodeableConcept
  • Normalised to a string containing the coding's 'system' and 'code'
  • Since a CodeableConcept can have multiple codings, the most favourable coding is chosen
  • Most favourable means the first if ascending and last if descending
FHIR.Coding
  • Normalised to a string containing 'system' and 'code'
FHIR.ContactPoint
  • Normalised to a string containing 'value'
  • 'value' is converted to lowercase
FHIR.HumanName
  • Normalised to a string containing the 'family' and then followed by each 'given' of the name concatenated
  • All values are converted to lowercase
  • No precedence is given to the 'use' of a HumanName
FHIR.Identifier
  • Normalised to a string containing 'value'
FHIR.Money
  • Normalised to 'value' as a number
FHIR.Period
  • For FHIR.Period the normalisation depends on the sort order
  • Ascending
    • String containing 'value.start' if defined, '1000-01-01T00:00:00.000Z' otherwise
    • Periods without a 'start' are considered to have started before everything else
  • Descending
    • String containing 'value.end' if defined,'9999-12-31T00:00:00.000Z' otherwise
    • Periods without a 'end' are considered to have ended before everything else
FHIR.Range
  • For FHIR.Range the normalisation depends on the sort order
  • Ascending
    • 'low.value' as a number if defined, negative infinity otherwise
    • Ranges without a 'low.value' are considered to have lower bound below everything else
  • Descending
    • 'high.value' as a number if defined, positive infinity otherwise
    • Ranges without a 'high.value' are considered to have higher bound above everything else
FHIR.Reference
  • Normalised to a string containing 'reference'
FHIR.Timing
  • Normalised to a string containing the 'event'
  • Since a Timing 'event' can have multiple values, the most favourable value is chosen
  • Most favourable means the first if ascending and last if descending
FHIR.Quantity
  • Normalised to 'value' as a number
FHIR.String
  • Normalised by converting to lowercase
FHIR.Boolean
  • Normalised by setting true to equal positive infinity, and false to equal negative infinity
FHIR.Boolean
  • Unrecognised objects have basic, but consistent normalisation
  • The object keys are sorted
  • Each key value is converted to a string
  • The sorted and stringified values are returned as the result of normalisation

Dependencies (1)

Dev Dependencies (2)

Package Sidebar

Install

npm i @synanetics/fhir-sort

Weekly Downloads

12

Version

1.0.0

License

MIT

Unpacked Size

10.6 MB

Total Files

56

Last publish

Collaborators

  • edward-synanetics
  • luke-syn
  • synjy
  • wrobinsonsynanetics
  • whay-syn
  • sarah-gibson
  • lewis-synanetics
  • oliverm-wethey
  • synrichardbrown
  • gregsynanetics
  • tom-synanetics
  • danielpeterbayley
  • leecampbellsynanetics
  • synsteve