Giter Club home page Giter Club logo

fhirpath's Introduction

Introduction

image

Documentation Status

Test Coverage

Python Versions

Language grade: Python

image

License

Downloads

HL7® FHIR®

FHIRPath Normative Release (v2.0.0) implementation in Python, along side it provides support for FHIR Search API and Query (we called it fql(FHIR Query Language)) API to fetch FHIR resources from any data-source(database). This library is built in ORM like approach. Our goal is to make 100% (as much as possible) FHIRPath Normative Release (v2.0.0) specification compliance product.

Usages

This library is kind of abstract type, where all specifications from FHIRPath Normative Release (v2.0.0) are implemented rather than completed solution (ready to go). The main reason behind this design pattern, to support multiple database systems as well as well as any framework, there is no dependency.

fhirpath never taking care of creating indexes, mappings (elasticsearch) and storing data, if you want to use this library, you have to go through any of existing providers (see list bellow) or make your own provider (should not too hard work).

Simple example

Assumption:

  1. Elasticsearch server 7.x.x Installed.
  2. Mappings and indexes are handled manually.
  3. Data (document) also are stored manually.

Create Connection and Engine:

>>> from fhirpath.connectors import create_connection
>>> from fhirpath.engine.es import ElasticsearchEngine
>>> from fhirpath.engine import dialect_factory
>>> from fhirpath.enums import FHIR_VERSION

>>> host, port = "127.0.0.1", 9200
>>> conn_str = "es://@{0}:{1}/".format(host, port)
>>> connection = create_connection(conn_str, "elasticsearch.Elasticsearch")
>>> connection.raw_connection.ping()
True
>>> engine = ElasticsearchEngine(FHIR_VERSION.R4, lambda x: connection, dialect_factory)

Basic Search:

>>> from fhirpath.search import Search
>>> from fhirpath.search import SearchContext

>>> search_context = SearchContext(engine, "Organization")
>>> params = (
....    ("active", "true"),
....    ("_lastUpdated", "2010-05-28T05:35:56+00:00"),
....    ("_profile", "http://hl7.org/fhir/Organization"),
....    ("identifier", "urn:oid:2.16.528.1|91654"),
....    ("type", "http://hl7.org/fhir/organization-type|prov"),
....    ("address-postalcode", "9100 AA"),
....    ("address", "Den Burg"),
.... )
>>> fhir_search = Search(search_context, params=params)
>>> bundle = fhir_search()
>>> len(bundle.entry) == 0
True

Basic Query:

>>> from fhirpath.enums import SortOrderType
>>> from fhirpath.query import Q_
>>> from fhirpath.fql import T_
>>> from fhirpath.fql import V_
>>> from fhirpath.fql import exists_
>>> query_builder = Q_(resource="Organization", engine=engine)
>>>  query_builder = (
....    query_builder.where(T_("Organization.active") == V_("true"))
....    .where(T_("Organization.meta.lastUpdated", "2010-05-28T05:35:56+00:00"))
....    .sort(sort_("Organization.meta.lastUpdated", SortOrderType.DESC))
.... )
>>> query_result = query_builder(async_result=False)
>>> for resource in query_result:
....    assert resource.__class__.__name__ == "OrganizationModel"
>>> # test fetch all
>>> result = query_result.fetchall()
>>> result.__class__.__name__ == "EngineResult"
True

>>> query_builder = Q_(resource="ChargeItem", engine=engine)
>>> query_builder = query_builder.where(exists_("ChargeItem.enteredDate"))
>>> result = query_builder(async_result=False).single()
>>> result is not None
True
>>> isinstance(result, builder._from[0][1])
True

>>> query_builder = Q_(resource="ChargeItem", engine=engine)
>>> query_builder = query_builder.where(exists_("ChargeItem.enteredDate"))
>>> result = query_builder(async_result=False).first()
>>> result is not None
True
>>> isinstance(result, builder._from[0][1])
True

Available Provider (known)

Currently very few numbers of providers available, however more will coming soon.

A guillotina framework powered provider, battery included, ready to go! Please follow associated documentation.

  1. Engine: Elasticsearch
  2. PyPi: https://pypi.org/project/fhirpath-guillotina/
  3. Source: https://github.com/nazrulworld/fhirpath_guillotina

A Plone powered provider, like fhirpath-guillotina every thing is included. ready to go, although has a dependency on plone.app.fhirfield.

  1. Engine: Elasticsearch
  2. PyPi: https://pypi.org/project/collective.fhirpath/
  3. Source: https://github.com/nazrulworld/collective.fhirpath

unlisted

Why are you waiting for? You are welcome to list your provider here! Developing provider should not be so hard, as fhirpath is giving you convenient APIs.

Elasticsearch Custom Analyzer

To get some special search features for reference type field, you will need to setup custom analyzer for your elasticsearch index.

Example Custom Analyzer:

settings = {
    "analysis": {
        "normalizer": {
            "fhir_token_normalizer": {"filter": ["lowercase", "asciifolding"]}
        },
        "analyzer": {
            "fhir_reference_analyzer": {
                "tokenizer": "keyword",
                "filter": ["fhir_reference_filter"],
            },
        },
        "filter": {
            "fhir_reference_filter": {
                "type": "pattern_capture",
                "preserve_original": True,
                "patterns": [r"(?:\w+\/)?(https?\:\/\/.*|[a-zA-Z0-9_-]+)"],
            },
        },
        "char_filter": {},
        "tokenizer": {},
    }

Example Mapping (Reference Field):

"properties": {
  "reference": {
    "type": "text",
    "index": true,
    "store": false,
    "analyzer": "fhir_reference_analyzer"
}

ToDo

  1. fhirbase engine aka provider implementation.
  2. All methods/functions are defined in FHIRPath specification, would be completed.
  3. Implement https://github.com/ijl/orjson
  4. https://developers.redhat.com/blog/2017/11/16/speed-python-using-rust/

Credits

This package skeleton was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.

© Copyright HL7® logo, FHIR® logo and the flaming fire are registered trademarks owned by Health Level Seven International

"FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7" https://github.com/beda-software/fhirpath-py

fhirpath's People

Contributors

jasopaum avatar nazrulworld avatar simonvadee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

fhirpath's Issues

Nested GroupTerm search returns no matches

  • fhirpath version: 0.10.4
  • Python version: 3.9.0
  • Operating System: MacOS

Description

This is not a bug report but a question.

What I Did

I created a Patient resource with the following content

{
  "resourceType": "Patient",
  "id": "1",
  "name": [
    {
      "given": [
        "John"
      ],
      "family": "Mercer"
    },
    {
      "given": [
        "Alex"
      ],
      "family": "Connor"
    }
  ]
}

Then, I tried the following search

search_context = SearchContext(engine, "Patient")
# equivalent to /Patient?name=John&name=Connor
params = (("name", "John"), ("name", "Connor"), )
search_tool = Search(search_context, params=params)
bundle = search_tool()
assert bundle.total > 0

No documents are matched due to the nested wrapper on the top-most GroupTerm.

A similar query on HAPI Test Server returns a non-zero response

curl -X GET "http://hapi.fhir.org/baseR4/Patient?name=Ajay&name=Mishra&_pretty=true"

I could not any relevant documentation or rules around such matches on FHIR Search.

Is this behavior server specific or something that I may have missed in FHIR specification?

Documentation on developing new providers

Description

Hey @nazrulworld and congratulations for the amazing work you've done here! I'm currently building a FHIR api in python and fhirpath seems to supports many features i'm interested in (search params, chaining, many modifiers etc..) so I was thinking of giving it a go! However I already have my own "provider" as you call it, and I would like to write an integration for my provider to work with fhirpath (just like what you did with fhirpath_guillotina).

The library I use is called fhirstore and it is based on mongoDB (storage) and elasticsearch (indexing) so I was thinking that maybe it could be easy to write my own integration but I don't really know which interfaces I need to implement and I did not find more detailed documentation. I started digging in the code of fhirpath_guillotina but there is a lot of called imported from the guillotina framework and I don't fully understand what's going on.

Would you be willing to share more details on how to write a new provider ?

The company I work with dedicates some of its resources to develop the FHIR ecosystem (mostly python libs) and would be happy to contribute to fhirpath!

Cheers :)

add support for :_include modifier

Description

The search is not yet able to handle the _include modifier which allows to "join" resources between them.
For instance, the query string /Observation?category=laboratory&_include=Observation:encounter which is equivalent to

search_context = SearchContext(engine, "Observation")
params = (("category", "laboratory"), ("_include", "Observation:encounter"))
fhir_search = Search(search_context,  params=params)

should output a Bundle like:

{
    "id": "1",
    "meta": {},
    "entry": [
        {
            "fullUrl": "Observation/123",
            "resource": {
                "...": "...",
                "resourceType": "Observation"
            },
            "search": {
                "mode": "match"
            }
        },
        {
            "fullUrl": "Encounter/456",
            "resource": {
                "...": "...",
                "resourceType": "Encounter"
            },
            "search": {
                "mode": "include"
            }
        }
    ],
    "link": [
        {
            "relation": "self",
            "url": "https://some.url"
        }
    ],
    "total": 1,
    "type": "searchset",
    "resourceType": "Bundle"
}

I'm not sure how we should implement "relations" between documents but the parent-child relationship using the join datatype seems to be a good fit.
A first implementation could also consist in running multiple ES queries and construct a bundle from multiple results.

Switch to Apache License 2.0 ?

The project is currently licensed under GPLv3, which (if I'm not mistaken) makes dependent projects using GPLv3 as well (see https://choosealicense.com/licenses/gpl-3.0/).

We are currently building open-source software on top of fhirpath (and fhir.resources) but we are using the more permissive Apache2 license (like most projects hosted at https://github.com/FHIR or popular projects like https://github.com/hapifhir/hapi-fhir or https://github.com/IBM/FHIR).
Apache2 details (and TLDR) can be found here: https://choosealicense.com/licenses/apache-2.0/
Note that we would not be impacted by other permissive licenses like the MIT License.

I know we already discussed the subject and you seemed to be open to changing the licensing model but this is becoming an issue on our end.

Related: arkhn/fhir-river#281

multiple negative not working!

  • fhirpath version: 0.7.1
  • Python version: 3.7
  • Operating System: MacOS

Description

I need to search for Task those statuses are not in completed, cancelled, rejected.

What I Did

query = {
            "status:not": "completed,cancelled,rejected",
            "code:not": "|consentTask",
        }

Didn’t get the expected result, but when do query positive term like "status": "ready,in-progress", it's working!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.