Source code for fhirpath.fhirpath

# -*- coding: utf-8 -*-
"""Main module."""
import inspect
import typing
from abc import ABC
from functools import wraps
from typing import TYPE_CHECKING, Any, DefaultDict, List, Optional, Type, Union, cast

from pydantic.fields import ModelField
from zope.interface import implementer

from fhirpath.enums import FHIR_VERSION
from fhirpath.interfaces import ITypeInfoWithElements
from fhirpath.utils import lookup_fhir_class

from .exceptions import MultipleResultsFound
from .storage import MemoryStorage
from .types import TypeSpecifier

if TYPE_CHECKING:
    from fhir.resources.fhirabstractmodel import FHIRAbstractModel  # noqa: F401

__author__ = "Md Nazrul Islam <email2nazrul>"

FHIR_PREFIX = "FHIR"
FHIRPATH_DATA_TYPES = {
    "bool": "Boolean",
    "str": "String",
    "int": "Integer",
    "float": "Decimal",
    "date": "Date",
    "datetime": "DateTime",
    "time": "Time",
    "bytes": "String",
}


[docs]def collection_type_required(func: typing.Callable): """ """ @wraps(func) def wrapper(self, *args, **kwargs): if not isinstance(self.get_type(), ListTypeInfo): raise ValueError( f"You are allowed to use this method ´{func.__name__}´, " "for collection(list) type value only" ) return func(self, *args, **kwargs) return wrapper
[docs]class SimpleTypeInfo: """For primitive types such as String and Integer, the result is a SimpleTypeInfo:""" namespace: str name: str baseType: TypeSpecifier
[docs] @classmethod def from_type_specifier(cls, specifier: TypeSpecifier) -> "SimpleTypeInfo": """ """ ns, name = specifier.split(".") self = cls() self.namespace = ns self.name = name self.baseType = TypeSpecifier("{0}<Any>".format(ns)) return self
[docs]class ClassInfoElement: name: str type: TypeSpecifier isOneBased: typing.Optional[bool] # ``_one_of_many_name`` represents one of many _one_of_many_name: typing.Optional[str] # property name in python class _py_name: str # FHIR Resource Class _model_class: Optional[Type["FHIRAbstractModel"]] def __init__( self, name: str, *, py_name: str, type_: TypeSpecifier, is_one_based: bool = None, one_of_many_name: str = None, ): """ """ self.name = name self._py_name = py_name self.type = type_ self.isOneBased = is_one_based self._one_of_many_name = one_of_many_name
[docs] @classmethod def from_model_field(cls, field: ModelField) -> "ClassInfoElement": """ """ assert field.field_info.extra.get("element_property", False) is True visit_name: Optional[str] = None if TYPE_CHECKING: is_primitive: Optional[bool] = None model_class: Optional[Type["FHIRAbstractModel"]] = None name = field.alias py_name = field.name is_one_based = (str(field.outer_type_)[:12] == "typing.List[") is False if getattr(field.type_, "is_primitive", None) is None: if field.type_ == bool: visit_name = "boolean" is_primitive = True else: raise NotImplementedError else: is_primitive = field.type_.is_primitive() if is_primitive is False: # AbstractBaseType tn = "{0}.{1}".format(FHIR_PREFIX, field.type_.__resource_type__) model_class = lookup_fhir_class( field.type_.__resource_type__, FHIR_VERSION[field.type_.__fhir_release__], ) else: # Primitive visit_name = getattr(field.type_, "__visit_name__", visit_name) tn = "{0}.{1}".format(FHIR_PREFIX, visit_name) model_class = None if is_one_based is False: tn = "List<{0}>".format(tn) self = cls( name, py_name=py_name, type_=TypeSpecifier(tn), is_one_based=is_one_based, one_of_many_name=field.field_info.extra.get("one_of_many", None), ) # xxx: cache it self._model_class = model_class return self
[docs] def build_simple_type_info(self) -> SimpleTypeInfo: """ """ inst = SimpleTypeInfo() if self.isOneBased: ns, name = self.type.split(".") else: ns, name = self.type[5:-1].split(".") inst.namespace = ns inst.name = name inst.baseType = TypeSpecifier(ns + ".Primitive") return inst
[docs]@implementer(ITypeInfoWithElements) class ClassInfo: """ """ name: str namespace: str baseType: TypeSpecifier element: typing.List[ClassInfoElement] _indexes: typing.List[str]
[docs] @classmethod def from_model(cls, model_class: Type["FHIRAbstractModel"]) -> "ClassInfo": """ """ self = cls() klass_name = model_class.__name__ self.namespace = FHIR_PREFIX self.name = klass_name base_class = inspect.getmro(model_class)[1] self.baseType = TypeSpecifier( "{0}.{1}".format(FHIR_PREFIX, base_class.__name__) ) self._indexes = list() elements = ClassInfo.build_elements(model_class) for el in elements: self._indexes.append(el.name) self.element = elements # Ensure base in cache base_bases = inspect.getmro(base_class) if ( "FHIRAbstractModel" in str(base_bases) and self.baseType not in FHIRPath.__storage__ and base_class.__name__ != "FHIRAbstractModel" ): base_self = ClassInfo.from_model(base_class) FHIRPath.__storage__[self.baseType] = base_self return self
[docs] def get_elements(self) -> List[ClassInfoElement]: """ """ return self.element
[docs] @staticmethod def build_elements( model_class: Type["FHIRAbstractModel"], ) -> List[ClassInfoElement]: """ """ elements = list() for field in model_class.element_properties(): el = ClassInfoElement.from_model_field(field) elements.append(el) return elements
def __repr__(self): """ """ return ( f"<{self.__class__.__name__} name='{self.name}', " f"namespace='{self.namespace}', baseType='{self.baseType}'," f" element='{len(self.element)}'>" )
[docs]@implementer(ITypeInfoWithElements) class ListTypeInfo: """For collection types, the result is a ListTypeInfo: ``ListTypeInfo { elementType: TypeSpecifier }`` For example: ``Patient.address.type()`` Results in: ``{ListTypeInfo { elementType: 'FHIR.Address' }}`` """ elementType: TypeSpecifier
[docs] @classmethod def from_specifier(cls, specifier) -> "ListTypeInfo": """ """ assert "." in specifier, "Must contains with prefix!" self = cls() self.elementType = specifier return self
[docs] def get_elements( self, ) -> Union[List["ClassInfoElement"], List["TupleTypeInfoElement"]]: """ """ klass_info = FHIRPath.__storage__[self.elementType] if not isinstance(klass_info, SimpleTypeInfo): return klass_info.get_elements() raise NotImplementedError
[docs]class TupleTypeInfoElement(ClassInfoElement): """ """
[docs]@implementer(ITypeInfoWithElements) class TupleTypeInfo: """Anonymous types are structured types that have no associated name, only the elements of the structure. For example, in FHIR, the Patient.contact element has multiple sub-elements, but is not explicitly named. For types such as this, the result is a TupleTypeInfo: @see http://hl7.org/fhirpath/N1/#anonymous-types""" element: List[TupleTypeInfoElement]
[docs] @classmethod def from_model(cls, model_class: Type["FHIRAbstractModel"]) -> "TupleTypeInfo": """ """ self = cls() elements = TupleTypeInfo.build_elements(model_class) self.element = elements return self
[docs] def get_elements(self) -> List[TupleTypeInfoElement]: """ """ return self.element
[docs] @staticmethod def build_elements( model_class: Type["FHIRAbstractModel"], ) -> List[TupleTypeInfoElement]: """ """ elements = list() for field in model_class.element_properties(): el = cast( TupleTypeInfoElement, TupleTypeInfoElement.from_model_field(field) ) elements.append(el) return elements
[docs]class FHIRPath(ABC): """http://hl7.org/fhirpath/N1""" # Global Cache __storage__: DefaultDict[ TypeSpecifier, Union[ClassInfo, TupleTypeInfo, SimpleTypeInfo] ] = MemoryStorage() _obj: typing.Any _predecessor: "FHIRPath" _type_info: Union[TupleTypeInfo, ListTypeInfo, ClassInfo, SimpleTypeInfo] _prop_name: str _of_many: bool __slots__ = ("_obj", "_predecessor", "_type_info", "_prop_name", "_of_many") def __init__(self, _obj: Any, predecessor: "FHIRPath" = None): """ """ if predecessor is None and "FHIRAbstractModel" not in str( inspect.getmro(type(_obj)) ): raise ValueError( "root fhirpath cannot be initialized, " "without a object (must be derived from " "``fhir.resources::FHIRAbstractModel``)" ) object.__setattr__(self, "_obj", _obj) object.__setattr__(self, "_predecessor", predecessor) object.__setattr__(self, "_type_info", None) object.__setattr__(self, "_prop_name", None) object.__setattr__(self, "_of_many", None) def __getattr__(self, item): """ """ if item in self.__slots__: return object.__getattribute__(self, item) if self._obj is None: raise AttributeError(f"'NoneType' object/value has no attribute '{item}'") try: obj = getattr(self._obj, item) # another instance of FHIRPath with predecessor's referenced return self._create_successor(obj, item) except AttributeError: # special case for `value` name valid = False obj = None for el in self.get_type().get_elements(): if el._one_of_many_name is not None and el._one_of_many_name == item: valid = True value = getattr(self._obj, el.name, None) if value is not None: obj = value break if valid is True: return self._create_successor(obj, item, of_many=True) # Real Error raise def __setattr__(self, attr, value): """ """ raise AttributeError("Readonly Object!") def __call__(self): """ """ return self._obj
[docs] @staticmethod def element_from_predecessor( predecessor: "FHIRPath", prop_name: str ) -> Union[ClassInfoElement, TupleTypeInfoElement]: """ """ if predecessor() is None: raise NotImplementedError predecessor_type = predecessor.get_type() if not ITypeInfoWithElements.providedBy(predecessor_type): raise NotImplementedError for el in predecessor_type.get_elements(): if el.name == prop_name: return el elif el._one_of_many_name == prop_name: # xxx: extra care required. return el raise NotImplementedError
[docs] @staticmethod def convert_and_cache_elements( elements: Union[List[ClassInfoElement], List[TupleTypeInfoElement]] ) -> None: """ """ for el in elements: specifier = el.type if specifier.startswith("List<"): specifier = TypeSpecifier(specifier[5:-1]) if specifier not in FHIRPath.__storage__: klass_info = FHIRPath.build_type_info_from_el(el) if not isinstance(klass_info, ListTypeInfo): FHIRPath.__storage__[specifier] = klass_info
[docs] @staticmethod def build_type_info_from_el( element: Union[ClassInfoElement, TupleTypeInfoElement] ) -> Union[ClassInfo, SimpleTypeInfo, ListTypeInfo, TupleTypeInfo]: """ """ if element._model_class is None: return element.build_simple_type_info() klass_info: Union[ClassInfo, SimpleTypeInfo, ListTypeInfo, TupleTypeInfo] bases = inspect.getmro(element._model_class) if "FHIRAbstractModel" in str(bases): # FHIR type! klass_info = FHIRPath.build_fhir_abstract_type_info(klass=bases[0]) else: specifier = element.type if specifier.startswith("List<"): specifier = TypeSpecifier(specifier[5:-1]) klass_info = SimpleTypeInfo.from_type_specifier(specifier) return klass_info
[docs] @staticmethod def build_fhir_abstract_type_info( klass: Type["FHIRAbstractModel"], is_one_based: bool = True ) -> Union[ClassInfo, ListTypeInfo, TupleTypeInfo]: """ """ key = TypeSpecifier(".".join([FHIR_PREFIX, klass.__name__])) if key not in FHIRPath.__storage__: mod = inspect.getmodule(klass) assert mod is not None mod_base_name = mod.__name__.split(".")[-1] klass_info: Union[TupleTypeInfo, ClassInfo] if mod_base_name == klass.__name__.lower(): klass_info = ClassInfo.from_model(klass) else: # TupleType klass_info = TupleTypeInfo.from_model(klass) # cache it! FHIRPath.__storage__[key] = klass_info FHIRPath.convert_and_cache_elements(klass_info.element) if is_one_based is False: return ListTypeInfo.from_specifier(key) else: return FHIRPath.__storage__[key] # type: ignore
def _assign_type_info(self) -> None: """ """ type_info: Optional[ Union[ClassInfo, SimpleTypeInfo, ListTypeInfo, TupleTypeInfo] ] = None element: Optional[Union[ClassInfoElement, TupleTypeInfoElement]] = None is_one_based = True if self._prop_name and self._predecessor: element = FHIRPath.element_from_predecessor( self._predecessor, self._prop_name ) if element is not None: is_one_based = element.isOneBased is None or element.isOneBased if self._obj is None: if element is not None: if element._model_class is None: object.__setattr__( self, "_type_info", element.build_simple_type_info() ) return bases = inspect.getmro(element._model_class) else: return else: bases = inspect.getmro(type(self._obj)) if element is None and isinstance(self._obj, list): is_one_based = False if "FHIRAbstractModel" in str(bases): # FHIR type! if self._obj is None: klass = bases[0] else: klass = type(self._obj) type_info = FHIRPath.build_fhir_abstract_type_info(klass, is_one_based) object.__setattr__(self, "_type_info", type_info) elif isinstance(self._obj, list) and self._prop_name and self._predecessor: """Do special treatment""" specifier = None element = None for el in self._predecessor.get_type().get_elements(): if el.name == self._prop_name: specifier = TypeSpecifier(el.type[5:-1]) element = el break if specifier is None: raise NotImplementedError if specifier not in FHIRPath.__storage__: # cache it, important! assert element is not None type_info = FHIRPath.build_type_info_from_el(element) if not isinstance(type_info, ListTypeInfo): FHIRPath.__storage__[specifier] = type_info else: raise NotImplementedError type_info = ListTypeInfo() type_info.elementType = specifier object.__setattr__(self, "_type_info", type_info) else: if self._predecessor: predecessor_type = self._predecessor.get_type() type_info = None if isinstance(predecessor_type, ListTypeInfo): type_info = FHIRPath.__storage__[predecessor_type.elementType] elif self._prop_name: for el in self._predecessor.get_type().get_elements(): if el.name == self._prop_name: new_type = el.type if new_type.startswith("List<"): new_type = new_type[5:-1] # check in cache if new_type not in FHIRPath.__storage__: FHIRPath.__storage__[ new_type ] = SimpleTypeInfo.from_type_specifier(new_type) type_info = FHIRPath.__storage__[new_type] break if type_info is None: raise NotImplementedError object.__setattr__(self, "_type_info", type_info) else: specifier = TypeSpecifier( "System." + FHIRPATH_DATA_TYPES[bases[0].__name__] ) if specifier not in FHIRPath.__storage__: type_info = SimpleTypeInfo.from_type_specifier(specifier) FHIRPath.__storage__[specifier] = type_info object.__setattr__(self, "_type_info", FHIRPath.__storage__[specifier]) def _create_successor( self, _obj: Any, prop_name: str = None, of_many: bool = None ) -> "FHIRPath": """ """ successor: FHIRPath = FHIRPath(_obj, predecessor=self) object.__setattr__(successor, "_prop_name", prop_name) object.__setattr__(successor, "_of_many", of_many) return successor def _clone(self, obj: Any = None) -> "FHIRPath": """ """ if obj is None: obj = self._obj newone = FHIRPath(obj, predecessor=self._predecessor) object.__setattr__(newone, "_prop_name", self._prop_name) object.__setattr__(newone, "_of_many", self._of_many) return newone # 5.1. Existence
[docs] @collection_type_required def empty(self) -> bool: """5.1.1. empty() : Boolean Returns true if the input collection is empty ({ }) and false otherwise. """ if self._obj is None: return True return len(self._obj) == 0
[docs] @collection_type_required def exists(self): """5.1.2. exists([criteria : expression]) : Boolean Returns true if the collection has any elements, and false otherwise. This is the opposite of empty(), and as such is a shorthand for empty().not(). If the input collection is empty ({ }), the result is false. The function can also take an optional criteria to be applied to the collection prior to the determination of the exists. In this case, the function is shorthand for where(criteria).exists(). """ raise NotImplementedError
[docs] def all(self): """5.1.3. all(criteria : expression) : Boolean Returns true if for every element in the input collection, criteria evaluates to true. Otherwise, the result is false. If the input collection is empty ({ }), the result is true. ``generalPractitioner.all($this is Practitioner)`` """ raise NotImplementedError
[docs] def allTrue(self): """5.1.4. allTrue() : Boolean Takes a collection of Boolean values and returns true if all the items are true. If any items are false, the result is false. If the input is empty ({ }), the result is true. The following example returns true if all of the components of the Observation have a value greater than 90 mm[Hg]: ``Observation.select(component.value > 90 'mm[Hg]').allTrue()`` """ raise NotImplementedError
[docs] def anyTrue(self): """5.1.5. anyTrue() : Boolean Takes a collection of Boolean values and returns true if any of the items are true. If all the items are false, or if the input is empty ({ }), the result is false. The following example returns true if any of the components of the Observation have a value greater than 90 mm[Hg]: ``Observation.select(component.value > 90 'mm[Hg]').anyTrue()`` """ raise NotImplementedError
[docs] def allFalse(self): """5.1.6. allFalse() : Boolean Takes a collection of Boolean values and returns true if all the items are false. If any items are true, the result is false. If the input is empty ({ }), the result is true. The following example returns true if none of the components of the Observation have a value greater than 90 mm[Hg]: ``Observation.select(component.value > 90 'mm[Hg]').allFalse()`` """ raise NotImplementedError
[docs] def anyFalse(self): """5.1.7. anyFalse() : Boolean Takes a collection of Boolean values and returns true if any of the items are false. If all the items are true, or if the input is empty ({ }), the result is false. he following example returns true if any of the components of the Observation have a value that is not greater than 90 mm[Hg]: ``Observation.select(component.value > 90 'mm[Hg]').anyFalse()`` """ raise NotImplementedError
[docs] def subsetOf(self): """5.1.8. subsetOf(other : collection) : Boolean Returns true if all items in the input collection are members of the collection passed as the other argument. Membership is determined using the = (Equals) (=) operation. Conceptually, this function is evaluated by testing each element in the input collection for membership in the other collection, with a default of true. This means that if the input collection is empty ({ }), the result is true, otherwise if the other collection is empty ({ }), the result is false. The following example returns true if the tags defined in any contained resource are a subset of the tags defined in the MedicationRequest resource: ``MedicationRequest.contained.meta.tag.subsetOf(MedicationRequest.meta.tag)`` """ raise NotImplementedError
[docs] def supersetOf(self): """5.1.9. supersetOf(other : collection) : Boolean Returns true if all items in the collection passed as the other argument are members of the input collection. Membership is determined using the = (Equals) (=) operation. Conceptually, this function is evaluated by testing each element in the other collection for membership in the input collection, with a default of true. This means that if the other collection is empty ({ }), the result is true, otherwise if the input collection is empty ({ }), the result is false. The following example returns true if the tags defined in any contained resource are a superset of the tags defined in the MedicationRequest resource: ``MedicationRequest.contained.meta.tag.supersetOf(MedicationRequest.meta.tag)`` """ raise NotImplementedError
[docs] @collection_type_required def count(self) -> int: """5.1.10. count() : Integer Returns the integer count of the number of items in the input collection. Returns 0 when the input collection is empty. """ return self._obj is not None and len(self._obj) or 0
[docs] def distinct(self): """5.1.11. distinct() : collection Returns a collection containing only the unique items in the input collection. To determine whether two items are the same, the = (Equals) (=) operator is used, as defined below. If the input collection is empty ({ }), the result is empty. Note that the order of elements in the input collection is not guaranteed to be preserved in the result. The following example returns the distinct list of tags on the given Patient: ``Patient.meta.tag.distinct()`` """ raise NotImplementedError
[docs] def isDistinct(self): """5.1.12. isDistinct() : Boolean Returns true if all the items in the input collection are distinct. To determine whether two items are distinct, the = (Equals) (=) operator is used, as defined below. Conceptually, this function is shorthand for a comparison of the count() of the input collection against the count() of the distinct() of the input collection: ``X.count() = X.distinct().count()`` This means that if the input collection is empty ({ }), the result is true. """ raise NotImplementedError
# 5.2.Filtering and projection
[docs] def where(self): """5.2.1. where(criteria : expression) : collection Returns a collection containing only those elements in the input collection for which the stated criteria expression evaluates to true. Elements for which the expression evaluates to false or empty ({ }) are not included in the result If the input collection is empty ({ }), the result is empty. If the result of evaluating the condition is other than a single boolean value, the evaluation will end and signal an error to the calling environment, consistent with singleton evaluation of collections behavior. The following example returns the list of telecom elements that have a use element with the value of 'official': ``Patient.telecom.where(use = 'official')`` """ raise NotImplementedError
[docs] def select(self): """5.2.2. select(projection: expression) : collection Evaluates the projection expression for each item in the input collection. The result of each evaluation is added to the output collection. If the evaluation results in a collection with multiple items, all items are added to the output collection (collections resulting from evaluation of projection are flattened). This means that if the evaluation for an element results in the empty collection ({ }), no element is added to the result, and that if the input collection is empty ({ }), the result is empty as well. ``Bundle.entry.select(resource as Patient)`` This example results in a collection with only the patient resources from the bundle. ``Bundle.entry.select((resource as Patient).telecom.where(system = 'phone'))`` This example results in a collection with all the telecom elements with system of phone for all the patients in the bundle. ``Patient.name.where(use = 'usual').select(given.first() + ' ' + family)`` This example returns a collection containing, for each "usual" name for the Patient, the concatenation of the first given and family names. """ raise NotImplementedError
[docs] def repeat(self): """5.2.3. repeat(projection: expression) : collection A version of select that will repeat the projection and add it to the output collection, as long as the projection yields new items (as determined by the = (Equals) (=) operator). This function can be used to traverse a tree and selecting only specific children: ``ValueSet.expansion.repeat(contains)`` Will repeat finding children called contains, until no new nodes are found. ``Questionnaire.repeat(item)`` Will repeat finding children called item, until no new nodes are found. Note that this is slightly different from: ``Questionnaire.descendants().select(item)`` which would find any descendants called item, not just the ones nested inside other item elements. The order of items returned by the repeat() function is undefined. """ raise NotImplementedError
[docs] def ofType(self, type_cls: typing.Union[type, str]): """5.2.4. ofType(type : type specifier) : collection Returns a collection that contains all items in the input collection that are of the given type or a subclass thereof. If the input collection is empty ({ }), the result is empty. The type argument is an identifier that must resolve to the name of a type in a model. For implementations with compile-time typing, this requires special-case handling when processing the argument to treat it as type specifier rather than an identifier expression: ``Bundle.entry.resource.ofType(Patient)`` In the above example, the symbol Patient must be treated as a type identifier rather than a reference to a Patient in context. """ raise NotImplementedError
# 5.3. Subsetting def __getitem__(self, key: typing.Union[int, slice]): """5.3.1. [ index : Integer ] : collection The indexer operation returns a collection with only the index-th item (0-based index). If the input collection is empty ({ }), or the index lies outside the boundaries of the input collection, an empty collection is returned. ``Note: Unless specified otherwise by the underlying Object Model, the first item in a collection has index 0.Note that if the underlying model specifies that a collection is 1-based (the only reasonable alternative to 0-based collections), any collections generated from operations on the 1-based list are 0-based.`` The following example returns the element in the name collection of the Patient with index 0: ``Patient.name[0]`` """ if not isinstance(self.get_type(), ListTypeInfo): raise NotImplementedError("Must be collection") try: if isinstance(key, slice): print(key.start, key.stop) obj = self._obj[key.start : key.stop] if len(obj) == 0: return return self._clone(obj) else: obj = self._obj[key] return self._create_successor(obj) except IndexError: pass
[docs] @collection_type_required def single(self): """5.3.2. single() : collection Will return the single item in the input if there is just one item. If the input collection is empty ({ }), the result is empty. If there are multiple items, an error is signaled to the evaluation environment. This function is useful for ensuring that an error is returned if an assumption about cardinality is violated at run-time. The following example returns the name of the Patient if there is one. If there are no names, an empty collection, and if there are multiple names, an error is signaled to the evaluation environment: ``Patient.name.single()`` """ if self._obj is None or (isinstance(self._obj, list) and len(self._obj) == 0): return None if len(self._obj) == 1: return self[0] raise MultipleResultsFound
[docs] @collection_type_required def first(self): """5.3.3. first() : collection Returns a collection containing only the first item in the input collection. This function is equivalent to item[0], so it will return an empty collection if the input collection has no items. """ if self._obj is None or (isinstance(self._obj, list) and len(self._obj) == 0): return None return self[0]
[docs] @collection_type_required def last(self): """5.3.4. last() : collection Returns a collection containing only the last item in the input collection. Will return an empty collection if the input collection has no items. """ if self._obj is None or (isinstance(self._obj, list) and len(self._obj) == 0): return None return self[-1]
[docs] @collection_type_required def tail(self): """5.3.5. tail() : collection Returns a collection containing all but the first item in the input collection. Will return an empty collection if the input collection has no items, or only one item. """ if self._obj is None or (isinstance(self._obj, list) and len(self._obj) < 2): return None return self[1:]
[docs] @collection_type_required def skip(self, num: int): """5.3.6. skip(num : Integer) : collection Returns a collection containing all but the first num items in the input collection. Will return an empty collection if there are no items remaining after the indicated number of items have been skipped, or if the input collection is empty. If num is less than or equal to zero, the input collection is simply returned. """ raise NotImplementedError
[docs] @collection_type_required def take(self, num: int): """5.3.7. take(num : Integer) : collection Returns a collection containing the first num items in the input collection, or less if there are less than num items. If num is less than or equal to 0, or if the input collection is empty ({ }), take returns an empty collection. """ raise NotImplementedError
[docs] def intersect(self): """5.3.8. intersect(other: collection) : collection Returns the set of elements that are in both collections. Duplicate items will be eliminated by this function. Order of items is not guaranteed to be preserved in the result of this function. """ raise NotImplementedError
[docs] def exclude(self): """5.3.9. exclude(other: collection) : collection Returns the set of elements that are not in the other collection. Duplicate items will not be eliminated by this function, and order will be preserved. e.g. ``(1 | 2 | 3).exclude(2) returns (1 | 3)``. """ raise NotImplementedError
# 5.4. Combining
[docs] def union(self): """5.4.1. union(other : collection) Merge the two collections into a single collection, eliminating any duplicate values (using = (Equals) (=) to determine equality). There is no expectation of order in the resulting collection. In other words, this function returns the distinct list of elements from both inputs. For example, consider two lists of integers A: 1, 1, 2, 3 and B: 2, 3: ``A union B // 1, 2, 3`` ``A union { } // 1, 2, 3`` This function can also be invoked using the | operator. ``a.union(b)`` is synonymous with ``a | b`` """ raise NotImplementedError
[docs] def combine(self): """5.4.2. combine(other : collection) : collection Merge the input and other collections into a single collection without eliminating duplicate values. Combining an empty collection with a non-empty collection will return the non-empty collection. There is no expectation of order in the resulting collection. """ raise NotImplementedError
# 5.5. Conversion
[docs] def iif(self): """5.5.1. iif(criterion: expression, true-result: collection [, otherwise-result: collection]) : collection The iif function in FHIRPath is an immediate if, also known as a conditional operator (such as C’s ? : operator). The criterion expression is expected to evaluate to a Boolean. If criterion is true, the function returns the value of the true-result argument. If criterion is false or an empty collection, the function returns otherwise-result, unless the optional otherwise-result is not given, in which case the function returns an empty collection. Note that short-circuit behavior is expected in this function. In other words, true-result should only be evaluated if the criterion evaluates to true, and otherwise-result should only be evaluated otherwise. For implementations, this means delaying evaluation of the arguments. """ raise NotImplementedError
# 5.5.2. Boolean Conversion Functions
[docs] def toBoolean(self): """5.5.2 toBoolean() : Boolean If the input collection contains a single item, this function will return a single boolean if: - the item is a Boolean - the item is an Integer and is equal to one of the possible integer representations of Boolean values - the item is a Decimal that is equal to one of the possible decimal representations of Boolean values - the item is a String that is equal to one of the possible string representations of Boolean values If the item is not one the above types, or the item is a String, Integer, or Decimal, but is not equal to one of the possible values convertible to a Boolean, the result is empty. @see: https://www.hl7.org/fhirpath/#boolean-conversion-functions """ raise NotImplementedError
[docs] def convertsToBoolean(self): """5.5.2. convertsToBoolean() : Boolean If the input collection contains a single item, this function will return true if: - the item is a Boolean - the item is an Integer that is equal to one of the possible integer representations of Boolean values - the item is a Decimal that is equal to one of the possible decimal representations of Boolean values - the item is a String that is equal to one of the possible string representations of Boolean values If the item is not one of the above types, or the item is a String, Integer, or Decimal, but is not equal to one of the possible values convertible to a Boolean, the result is false. Possible values for Integer, Decimal, and String are described in the toBoolean() function. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.3. Integer Conversion Functions
[docs] def toInteger(self): """5.5.3 toInteger() : Integer If the input collection contains a single item, this function will return a single integer if: - the item is an Integer - the item is a String and is convertible to an integer - the item is a Boolean, where true results in a 1 and false results in a 0. If the item is not one the above types, the result is empty. If the item is a String, but the string is not convertible to an integer (using the regex format ``(\\+|-)?\\d+)``, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
[docs] def convertsToInteger(self): """5.5.3 convertsToInteger() : Boolean If the input collection contains a single item, this function will return true if: - the item is an Integer - the item is a String and is convertible to an Integer - the item is a Boolean If the item is not one of the above types, or the item is a String, but is not convertible to an Integer (using the regex format (\\+|-)?\\d+), the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.4. Date Conversion Functions
[docs] def toDate(self): """5.5.4 toDate() : Date If the input collection contains a single item, this function will return a single date if: - the item is a Date - the item is a DateTime - the item is a String and is convertible to a Date If the item is not one of the above types, the result is empty. If the item is a String, but the string is not convertible to a Date (using the format YYYY-MM-DD), the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
[docs] def convertsToDate(self): """5.5.4. convertsToDate() : Boolean If the input collection contains a single item, this function will return true if: - the item is a Date - the item is a DateTime - the item is a String and is convertible to a Date If the item is not one of the above types, or is not convertible to a Date (using the format YYYY-MM-DD), the result is false. If the item contains a partial date (e.g. '2012-01'), the result is a partial date. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.5. DateTime Conversion Functions
[docs] def toDateTime(self): """5.5.5 toDateTime() : DateTime If the input collection contains a single item, this function will return a single datetime if: - the item is a DateTime - the item is a Date, in which case the result is a DateTime with the year, month, and day of the Date, and the time components empty (not set to zero) - the item is a String and is convertible to a DateTime If the item is not one of the above types, the result is empty. If the item is a String, but the string is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is empty. If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
[docs] def convertsToDateTime(self): """5.5.5. convertsToDateTime() : Boolean If the input collection contains a single item, this function will return true if: - the item is a DateTime - the item is a Date - the item is a String and is convertible to a DateTime If the item is not one of the above types, or is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.6. Decimal Conversion Functions
[docs] def toDecimal(self): """5.5.6. toDecimal() : Decimal If the input collection contains a single item, this function will return a single decimal if: - the item is an Integer or Decimal - the item is a String and is convertible to a Decimal - the item is a Boolean, where true results in a 1.0 and false results in a 0.0. If the item is not one of the above types, the result is empty. If the item is a String, but the string is not convertible to a Decimal (using the regex format (\\+|-)?\\d+(\\.\\d+)?), the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
[docs] def convertsToDecimal(self): """5.5.6. convertsToDecimal() : Boolean If the input collection contains a single item, this function will true if: - the item is an Integer or Decimal - the item is a String and is convertible to a Decimal - the item is a Boolean If the item is not one of the above types, or is not convertible to a Decimal (using the regex format (\\+|-)?\\d+(\\.\\d+)?), the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.7. Quantity Conversion Functions
[docs] def toQuantity(self): """5.5.7. toQuantity([unit : String]) : Quantity If the input collection contains a single item, this function will return a single quantity if: - the item is an Integer, or Decimal, where the resulting quantity will have the default unit ('1') - the item is a Quantity - the item is a String and is convertible to a Quantity - the item is a Boolean, where true results in the quantity 1.0 '1', and false results in the quantity 0.0 '1' If the item is not one of the above types, the result is empty. If the item is a String, but the string is not convertible to a Quantity using the following regex format: ``(?'value'(\\+|-)?\\d+(\\.\\d+)?)\\s*('(?'unit'[^']+)'|(?'time'[a-zA-Z]+))?`` then the result is empty. For example, the following are valid quantity strings: ``'4 days'`` ``'10 \'mg[Hg]\''`` If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. @see https://www.hl7.org/fhirpath/#toquantityunit-string-quantity """ raise NotImplementedError
[docs] def convertsToQuantity(self): """5.5.7. convertsToQuantity([unit : String]) : Boolean If the input collection contains a single item, this function will return true if: - the item is an Integer, Decimal, or Quantity - the item is a String that is convertible to a Quantity - the item is a Boolean If the item is not one of the above types, or is not convertible to a Quantity using the following regex format: ``(?'value'(\\+|-)?\\d+(\\.\\d+)?)\\s*('(?'unit'[^']+)'|(?'time'[a-zA-Z]+))?`` then the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. @see https://www.hl7.org/fhirpath/#convertstoquantityunit-string-boolean """ raise NotImplementedError
# 5.5.8. String Conversion Functions
[docs] def toString(self): """5.5.8. toString() : String If the input collection contains a single item, this function will return a single String if: - the item in the input collection is a String - the item in the input collection is an Integer, Decimal, Date, Time, DateTime, or Quantity the output will contain its String representation - the item is a Boolean, where true results in 'true' and false in 'false'. If the item is not one of the above types, the result is false. @see https://www.hl7.org/fhirpath/#tostring-string """ raise NotImplementedError
[docs] def convertsToString(self): """5.5.8. convertsToString() : String If the input collection contains a single item, this function will return true if: - the item is a String - the item is an Integer, Decimal, Date, Time, or DateTime - the item is a Boolean - the item is a Quantity If the item is not one of the above types, the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.5.9. Time Conversion Functions
[docs] def toTime(self): """5.5.9. toTime() : Time If the input collection contains a single item, this function will return a single time if: - the item is a Time - the item is a String and is convertible to a Time If the item is not one of the above types, the result is empty. If the item is a String, but the string is not convertible to a Time (using the format hh:mm:ss.fff(+|-)hh:mm), the result is empty. If the item contains a partial time (e.g. '10:00'), the result is a partial time. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
[docs] def convertsToTime(self): """5.5.9 convertsToTime() : Boolean If the input collection contains a single item, this function will return true if: - the item is a Time - the item is a String and is convertible to a Time If the item is not one of the above types, or is not convertible to a Time (using the format hh:mm:ss.fff(+|-)hh:mm), the result is false. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. If the input collection is empty, the result is empty. """ raise NotImplementedError
# 5.6. String Manipulation
[docs] def indexOf(self): """5.6.1. indexOf(substring : String) : Integer Returns the 0-based index of the first position substring is found in the input string, or -1 if it is not found. If substring is an empty string (''), the function returns 0. If the input or substring is empty ({ }), the result is empty ({ }). If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. ``` 'abcdefg'.indexOf('bc') // 1 'abcdefg'.indexOf('x') // -1 'abcdefg'.indexOf('abcdefg') // 0 ``` """ raise NotImplementedError
[docs] def substring(self): """5.6.2. substring(start : Integer [, length : Integer]) : String Returns the part of the string starting at position start (zero-based). If length is given, will return at most length number of characters from the input string. If start lies outside the length of the string, the function returns empty ({ }). If there are less remaining characters in the string than indicated by length, the function returns just the remaining characters. If the input or start is empty, the result is empty. If an empty length is provided, the behavior is the same as if length had not been provided. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abcdefg'.substring(3) // 'defg' 'abcdefg'.substring(1, 2) // 'bc' 'abcdefg'.substring(6, 2) // 'g' 'abcdefg'.substring(7, 1) // { } `` """ raise NotImplementedError
[docs] def startsWith(self): """5.6.3. startsWith(prefix : String) : Boolean Returns true when the input string starts with the given prefix. If prefix is the empty string (''), the result is true. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abcdefg'.startsWith('abc') // true 'abcdefg'.startsWith('xyz') // false `` """ raise NotImplementedError
[docs] def endsWith(self): """5.6.4. endsWith(suffix : String) : Boolean Returns true when the input string ends with the given suffix. If suffix is the empty string (''), the result is true. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abcdefg'.endsWith('efg') // true 'abcdefg'.ednsWith('abc') // false `` """ raise NotImplementedError
[docs] def contains(self): """5.6.5. contains(substring : String) : Boolean Returns true when the given substring is a substring of the input string. If substring is the empty string (''), the result is true. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abc'.contains('b') // true 'abc'.contains('bc') // true 'abc'.contains('d') // false `` `` Note: The .contains() function described here is a string function that looks for a substring in a string. This is different than the contains operator, which is a list operator that looks for an element in a list. `` """ raise NotImplementedError
[docs] def upper(self): """5.6.6. upper() : String Returns the input string with all characters converted to upper case. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abcdefg'.upper() // 'ABCDEFG' 'AbCdefg'.upper() // 'ABCDEFG' `` """ raise NotImplementedError
[docs] def lower(self): """5.6.7. lower() : String Returns the input string with all characters converted to lower case. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'ABCDEFG'.lower() // 'abcdefg' 'aBcDEFG'.lower() // 'abcdefg' `` """ raise NotImplementedError
[docs] def replace(self): """5.6.8. replace(pattern : String, substitution : String) : String Returns the input string with all instances of pattern replaced with substitution. If the substitution is the empty string (''), instances of pattern are removed from the result. If pattern is the empty string (''), every character in the input string is surrounded by the substitution, e.g. 'abc'.replace('','x') becomes 'xaxbxcx'. If the input collection, pattern, or substitution are empty, the result is empty ({ }). If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 'abcdefg'.replace('cde', '123') // 'ab123fg' 'abcdefg'.replace('cde', '') // 'abfg' 'abc'.replace('', 'x') // 'xaxbxcx' `` """ raise NotImplementedError
[docs] def matches(self): """5.6.9. matches(regex : String) : Boolean Returns true when the value matches the given regular expression. Regular expressions should function consistently, regardless of any culture- and locale-specific settings in the environment, should be case-sensitive, use 'single line' mode and allow Unicode characters. If the input collection or regex are empty, the result is empty ({ }). If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. """ raise NotImplementedError
[docs] def replaceMatches(self): """5.6.10. replaceMatches(regex : String, substitution: String) : String Matches the input using the regular expression in regex and replaces each match with the substitution string. The substitution may refer to identified match groups in the regular expression. If the input collection, regex, or substitution are empty, the result is empty ({ }). If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. This example of replaceMatches() will convert a string with a date formatted as MM/dd/yy to dd-MM-yy:: '11/30/1972'.replace('\\b(?<month>\\d{1,2})/ (?<day>\\d{1,2})/(?<year>\\d{2,4})\\b', '${day}-${month}-${year}') `` Note: Platforms will typically use native regular expression implementations. These are typically fairly similar, but there will always be small differences. As such, FHIRPath does not prescribe a particular dialect, but recommends the use of the [PCRE] flavor as the dialect most likely to be broadly supported and understood.`` """ raise NotImplementedError
[docs] def length(self): """5.6.11. length() : Integer Returns the length of the input string. If the input collection is empty ({ }), the result is empty. """ raise NotImplementedError
[docs] def toChars(self): """5.6.12. toChars() : collection Returns the list of characters in the input string. If the input collection is empty ({ }), the result is empty. `` 'abc'.toChars() // { 'a', 'b', 'c' } `` """ raise NotImplementedError
# 5.7.Math
[docs] def abs(self): """5.7.1. abs() : Integer | Decimal | Quantity Returns the absolute value of the input. When taking the absolute value of a quantity, the unit is unchanged. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` (-5).abs() // 5 (-5.5).abs() // 5.5 (-5.5 'mg').abs() // 5.5 'mg' `` """ raise NotImplementedError
[docs] def ceiling(self): """5.7.2. ceiling() : Integer Returns the first integer greater than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 1.ceiling() // 1 1.1.ceiling() // 2 (-1.1).ceiling() // -1 `` """ raise NotImplementedError
[docs] def exp(self): """5.7.3. exp() : Decimal Returns e raised to the power of the input. If the input collection contains an Integer, it will be implicitly converted to a Decimal and the result will be a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 0.exp() // 1.0 (-0.0).exp() // 1.0 `` """ raise NotImplementedError
[docs] def floor(self): """5.7.4. floor() : Integer Returns the first integer less than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 1.floor() // 1 2.1.floor() // 2 (-2.1).floor() // -3 `` """ raise NotImplementedError
[docs] def ln(self): """5.7.5. ln() : Decimal Returns the natural logarithm of the input (i.e. the logarithm base e). When used with an Integer, it will be implicitly converted to a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 1.ln() // 0.0 1.0.ln() // 0.0 `` """ raise NotImplementedError
[docs] def log(self): """5.7.6. log(base : Decimal) : Decimal Returns the logarithm base base of the input number. When used with Integers, the arguments will be implicitly converted to Decimal. If base is empty, the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 16.log(2) // 4.0 100.0.log(10.0) // 2.0 `` """ raise NotImplementedError
[docs] def power(self): """5.7.7. power(exponent : Integer | Decimal) : Integer | Decimal Raises a number to the exponent power. If this function is used with Integers, the result is an Integer. If the function is used with Decimals, the result is a Decimal. If the function is used with a mixture of Integer and Decimal, the Integer is implicitly converted to a Decimal and the result is a Decimal. If the power cannot be represented (such as the -1 raised to the 0.5), the result is empty. If the input is empty, or exponent is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 2.power(3) // 8 2.5.power(2) // 6.25 (-1).power(0.5) // empty ({ }) `` """ raise NotImplementedError
[docs] def round(self): """5.7.8. round([precision : Integer]) : Decimal Rounds the decimal to the nearest whole number using a traditional round (i.e. 0.5 or higher will round to 1). If specified, the precision argument determines the decimal place at which the rounding will occur. If not specified, the rounding will default to 0 decimal places. If specified, the number of digits of precision must be >= 0 or the evaluation will end and signal an error to the calling environment. If the input collection contains a single item of type Integer, it will be implicitly converted to a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 1.round() // 1 3.14159.round(3) // 3.142 `` """ raise NotImplementedError
[docs] def sqrt(self): """5.7.9. sqrt() : Decimal Returns the square root of the input number as a Decimal. If the square root cannot be represented (such as the square root of -1), the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. Note that this function is equivalent to raising a number of the power of 0.5 using the power() function. `` 81.sqrt() // 9.0 (-1).sqrt() // empty `` """ raise NotImplementedError
[docs] def truncate(self): """5.7.10. truncate() : Integer Returns the integer portion of the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment. `` 101.truncate() // 101 1.00000001.truncate() // 1 (-1.56).truncate() // -1 `` """ raise NotImplementedError
# 5.8. Tree navigation
[docs] def children(self): """5.8.1. children() : collection Returns a collection with all immediate child nodes of all items in the input collection. Note that the ordering of the children is undefined and using functions like first() on the result may return different results on different platforms. """ raise NotImplementedError
[docs] def descendants(self): """5.8.2. descendants() : collection Returns a collection with all descendant nodes of all items in the input collection. The result does not include the nodes in the input collection themselves. This function is a shorthand for repeat(children()). Note that the ordering of the children is undefined and using functions like first() on the result may return different results on different platforms. note`` Note: Many of these functions will result in a set of nodes of different underlying types. It may be necessary to use ofType() as described in the previous section to maintain type safety. See Type safety and strict evaluation for more information about type safe use of FHIRPath expressions. `` """ raise NotImplementedError
# 5.9. Utility functions
[docs] def trace(self): """5.9.1. trace(name : String [, projection: Expression]) : collection Adds a String representation of the input collection to the diagnostic log, using the name argument as the name in the log. This log should be made available to the user in some appropriate fashion. Does not change the input, so returns the input collection as output. If the projection argument is used, the trace would log the result of evaluating the project expression on the input, but still return the input to the trace function unchanged. ``contained.where(criteria).trace('unmatched', id).empty()`` The above example traces only the id elements of the result of the where. """ raise NotImplementedError
# 5.9.2. Current date and time functions # @see https://www.hl7.org/fhirpath/#current-date-and-time-functions
[docs] def now(self): """now() : DateTime Returns the current date and time, including timezone offset. """ raise NotImplementedError
[docs] def timeOfDay(self): """timeOfDay() : Time Returns the current time. """ raise NotImplementedError
[docs] def today(self): """today() : Date Returns the current date. """ raise NotImplementedError
# 6. Operations # Coming soon # ------------- # 6.3. Types
[docs] def is_(self, type_cls: typing.Union[type, str]): """6.3.2. is(type : type specifier) The is() function is supported for backwards compatibility with previous implementations of FHIRPath. Just as with the is keyword, the type argument is an identifier that must resolve to the name of a type in a model. For implementations with compile-time typing, this requires special-case handling when processing the argument to treat it as a type specifier rather than an identifier expression: ``Patient.contained.all($this.is(Patient) implies age > 10)`` """ DeprecationWarning( "The is() function is supported for backwards compatibility " "with previous implementations of FHIRPath" ) raise NotImplementedError
[docs] def as_(self, type_cls: typing.Union[type, str]): """6.3.4. as(type : type specifier) The as() function is supported for backwards compatibility with previous implementations of FHIRPath. Just as with the as keyword, the type argument is an identifier that must resolve to the name of a type in a model. For implementations with compile-time typing, this requires special-case handling when processing the argument to treat is a type specifier rather than an identifier expression: `` Observation.component.where(value.as(Quantity) > 30 'mg') `` """ DeprecationWarning( "The is() function is supported for backwards compatibility " "with previous implementations of FHIRPath" ) raise NotImplementedError
# 6.4. Collections
[docs] def in_(self): """6.4.2. in (membership) If the left operand is a collection with a single item, this operator returns true if the item is in the right operand using equality semantics. If the left-hand side of the operator is empty, the result is empty, if the right-hand side is empty, the result is false. If the left operand has multiple items, an exception is thrown. The following example returns true if 'Joe' is in the list of given names for the Patient: `` 'Joe' in Patient.name.given `` """ raise NotImplementedError
[docs] def contained(self): """6.4.3. contains (containership) If the right operand is a collection with a single item, this operator returns true if the item is in the left operand using equality semantics. If the right-hand side of the operator is empty, the result is empty, if the left-hand side is empty, the result is false. This is the converse operation of in. The following example returns true if the list of given names for the Patient has 'Joe' in it: ``Patient.name.given contains 'Joe'`` """ raise NotImplementedError
# 10. Types and Reflection
[docs] def get_type(self): """FHIRPath supports reflection to provide the ability for expressions to access type information describing the structure of values. The type() function returns the type information for each element of the input collection, using one of the following concrete subtypes of TypeInfo: """ if self._type_info is None: self._assign_type_info() return self._type_info