Skip to main content

Plone powered provider for fhirpath

Project description

Egg Status Travis Build Status Test Coverage Python Versions Latest Version License https://img.shields.io/badge/code%20style-black-000000.svg

Background (collective.fhirpath)

fhirpath implementation in Plone, essential battery included, ready to use.

Installation

Install collective.fhirpath by adding it to your buildout:

[buildout]
...
eggs +=
    collective.fhirpath

and then running bin/buildout

From Plone controlpanel in the addon settings, install collective.fhirpath.

How It Works

``FhirResource`` the fhirfield

Make sure this specialized field is used properly according to plone.app.fhirfield documentation.

Make field indexable

A specilized Catalog PluginIndexes is named FhirFieldIndex is available, you will use it as like other catalog indexes.

Example:

<?xml version="1.0"?>
<object name="portal_catalog" meta_type="Plone Catalog Tool">
    <index name="organization_resource" meta_type="FhirFieldIndex">
        <indexed_attr value="organization_resource"/>
    </index>
</object>

Elasticsearch settings

Make sure elasticsearch has been configured accourding to collective.elasticsearch docs.

Usages

FHIR Search::
>>> from fhirpath.interfaces import IElasticsearchEngineFactory
>>> from fhirpath.interfaces import IFhirSearch
>>> from fhirpath.interfaces import ISearchContextFactory
>>> from plone import api
>>> from collective.elasticsearch.es import ElasticSearchCatalog
>>> from zope.component import queryMultiAdapter
>>> es_catalog = ElasticSearchCatalog(api.portal.get_tool("portal_catalog"))
>>> factory = queryMultiAdapter(
....        (es_catalog,), IElasticsearchEngineFactory
.... )
>>> engine = factory(fhir_release="STU3")
>>> search_context = queryMultiAdapter((engine,), ISearchContextFactory)(
.... resource_type, unrestricted=False)
>>> search_factory = queryMultiAdapter((search_context,), IFhirSearch)
>>> params = (
....        ("_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"),
....    )
>>> bundle = search_factory(params)
>>> len(bundle.entry)
2
>>> # with query string.
>>> # query_string = self.request["QUERY_STRING]
>>> query_string = "_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"
>>> bundle = search_factory(query_string=query_string)
>>> len(bundle.entry)
2
ZCatlog FHIR Search::
>>> from collective.fhirpath.interfaces import IZCatalogFhirSearch
>>> zcatalog_factory = queryMultiAdapter((search_context,), IZCatalogFhirSearch)
>>> # with query string.
>>> # query_string = self.request["QUERY_STRING]
>>> query_string = "_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"
>>> brains = zcatalog_factory(query_string=query_string)
>>> len(brains)
2
FHIR Query::
>>> from fhirpath.interfaces import IElasticsearchEngineFactory
>>> from fhirpath.interfaces import IFhirSearch
>>> from fhirpath.interfaces import ISearchContextFactory
>>> from plone import api
>>> from collective.elasticsearch.es import ElasticSearchCatalog
>>> from zope.component import queryMultiAdapter
>>> from fhirpath.query import Q_
>>> from fhirpath.fql import T_
>>> from fhirpath.fql import sort_
>>> from fhirpath.enums import SortOrderType
>>> es_catalog = ElasticSearchCatalog(api.portal.get_tool("portal_catalog"))
>>> factory = queryMultiAdapter(
....        (es_catalog,), IElasticsearchEngineFactory
.... )
>>> engine = factory(fhir_release="STU3")
>>> query_builder = Q_(resource="Organization", engine=engine)
....    query_builder = query_builder.where(
....        T_("Organization.meta.profile", "http://hl7.org/fhir/Organization")
....    ).sort(sort_("Organization.meta.lastUpdated", SortOrderType.DESC))
>>> result = query_builder(async_result=False, unrestricted=True).fetchall()
>>> result.header.total
2
>>> query_result = query_builder(async_result=False, unrestricted=True)
>>> for resource in query_result:
....        count += 1
....        assert resource.__class__.__name__ == "Organization"
>>> query_builder = Q_(resource="Organization", engine=engine)
>>> query_builder = query_builder.where(T_("Organization.id", "f001"))
>>> result_query = query_builder(async_result=False, unrestricted=True)
>>> resource = result_query.single()
>>> resource is not None
True
>>> query_builder = Q_(resource="Organization", engine=engine)
>>> query_builder = query_builder.where(
....        T_("Organization.meta.profile", "http://hl7.org/fhir/Organization")
....    )
>>> result_query = builder(async_result=False, unrestricted=True)
>>> result = result_query.first()
>>> isinstance(result, result_query._query.get_from()[0][1])
True

Use FHIRModelServiceMixin

For better performance optimization, you should use FHIRModelServiceMixin to response FHIRModel, FhirFieldValue object efficiently.

Example 1:

>>> from plone.restapi.services import Service
>>> from collective.fhirpath.utils import FHIRModelServiceMixin
>>> class MyFHIRGetService(FHIRModelServiceMixin, Service):
....     """ """
....     def reply(self):
....        # do return bellow's types of data
....        # could be ``dict`` type data
....        # could be instance of ``FHIRAbstractModel`` derrived class.
....        # could be instance of ``plone.app.fhirfield.FhirResourceValue`` derrived class.
....        # or self.reply_no_content()

configuration

This product provides three plone registry based records fhirpath.es.index.mapping.nested_fields.limit, fhirpath.es.index.mapping.depth.limit, fhirpath.es.index.mapping.total_fields.limit. Those are related to ElasticSearch index mapping setup, if you aware about it, then you have option to modify from plone control panel (Registry).

Documentation

Full documentation for end users can be found in the “docs” folder, and is also available online at https://collective-fhirpath.readthedocs.io/

Contribute

Support

If you are having issues, please let us know at: Md Nazrul Islam<email2nazrul@gmail.com>

License

The project is licensed under the GPLv2.

REST Client Examples

Getting single resource, here we are getting Patient resource by ID.

Example(1):

>>> response = admin_session.get('/@fhir/Patient/19c5245f-89a8-49f8-b244-666b32adb92e')
>>> response.status_code
200
<BLANKLINE>
>>> response.json()['resourceType'] == 'Patient'
True
<BLANKLINE>
>>> response = admin_session.get('/@fhir/Patient/19c5245f-fake-id')
>>> response.status_code
404
<BLANKLINE>

Search Observation by Patient reference with status condition. Any observation until December 2017 and earlier than January 2017.

Example(2):

>>> response = admin_session.get('/@fhir/Observation?patient=Patient/19c5245f-89a8-49f8-b244-666b32adb92e&status=final&_lastUpdated=lt2017-12-31T00%3A00%3A00%2B00%3A00&_lastUpdated=gt2017-01-01T00%3A00%3A00%2B00%3A00')
>>> response.status_code
200
>>> response.json()["total"]
1
<BLANKLINE>

Add FHIR Resource through REST API

Example(3):

>>> import os
>>> import json
>>> import uuid
>>> import DateTime
>>> import time

>>> with open(os.path.join(FIXTURE_PATH, 'Patient.json'), 'r') as f:
...     fhir_json = json.load(f)

>>> fhir_json['id'] = str(uuid.uuid4())
>>> fhir_json['name'][0]['text'] = 'Another Patient'
>>> response = admin_session.post('/@fhir/Patient', json=fhir_json)
>>> response.status_code
201
>>> time.sleep(1)
>>> response = admin_session.get('/@fhir/Patient?active=true')
>>> response.json()["total"]
2

Update (PATCH) FHIR Resource the Patient is currently activated, we will deactive.

Example(4):

>>> patch = [{'op': 'replace', 'path': '/active', 'value': False}]
>>> response = admin_session.patch('/@fhir/Patient/19c5245f-89a8-49f8-b244-666b32adb92e', json={'patch': patch})
>>> response.status_code
204
<BLANKLINE>

Contributors

Changelog

0.8.0 (2022-06-13)

New features

  • A patch has been added in response to issue#91 on collective.elasticsearch.

0.7.6 (2021-05-04)

  • minimum fhir.resources version is now 6.1.0 and minimum collective.elasticsearch version is now 3.0.5

0.7.5 (2020-12-17)

0.7.4 (2020-11-19)

  • Minimum required fhirpath version is now 0.10.4 (see it’s changes log) and added compabilities.

0.7.3 (2020-10-24)

  • new helper function json_body has been created, which is using orjson deserializer.

  • FHIRModelServiceMixin is now more performance optimized.

0.7.2 (2020-10-06)

  • Bundle resposne as dict option enable in ZCatalog based search.

0.7.1 (2020-10-05)

  • fhirpath``minimum version has been updated, which includes minimum ``fhir.resources version 6.0.0b5.

  • Improvements for FHIRModelServiceMixin as orjson serializer used.

0.7.0 (2020-09-25)

Improvements

Fixes

  • utils.FHIRModelServiceMixin can now handle list type data in response.

0.6.1 (2020-09-09)

  • plone.app.fhirfield:default``has been added in dependency, so no need separete install of ``plone.app.fhirfield.

0.6.0 (2020-09-09)

Improvements

  • FHIRModelServiceMixin class has been available under utils module, which can be used with your plone.restapi services to response type as FhirModel aka pydantic’s BaseModel or plone.app.fhirfield.FhirFieldValue object with the best possible effecient way.

0.5.0 (2020-08-18)

Improvements

  • Supports the revolutionary version of fhir.resources via fhirpath we may expect some refactor on your existing codebase because of some breaking changes, please see changes at fhir.resources, plone.app.fhirfield and fhirpath.

  • Brings back support for Python version 3.6

  • Three configurations (fhirpath.es.index.mapping.nested_fields.limit, fhirpath.es.index.mapping.depth.limit, fhirpath.es.index.mapping.total_fields.limit) based on plone registry has now been available.

0.4.0 (2020-05-15)

Breakings

  • As a part of supporting latest fhirpath version (from 0.6.1), drop python version later than 3.7.0.

  • ElasticsearchEngineFactory.__call__’s argument name fhir_version changed to fhir_release.

0.3.0 (2019-11-10)

Improvements

  • ZCatalog featured fhir search added, from which you will get ZCatalog´s brain feature.

  • FhirFieldIndex named PluginIndex is now available.

  • FHIR STU3``and ``R4 search mapping is now available.

  • Others improvements that make able to use in production project (of course without guarantee.)

0.2.0 (2019-09-16)

  • first working versions, with lots of improvements.

0.1.0 (2019-09-06)

  • Initial release. [nazrulworld]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

collective.fhirpath-0.8.0.tar.gz (97.5 kB view details)

Uploaded Source

Built Distribution

collective.fhirpath-0.8.0-py2.py3-none-any.whl (332.2 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file collective.fhirpath-0.8.0.tar.gz.

File metadata

  • Download URL: collective.fhirpath-0.8.0.tar.gz
  • Upload date:
  • Size: 97.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.8.2 requests/2.27.1 setuptools/42.0.2 requests-toolbelt/0.9.1 tqdm/4.63.0 CPython/3.7.8

File hashes

Hashes for collective.fhirpath-0.8.0.tar.gz
Algorithm Hash digest
SHA256 d58b20f440774b8de287b6ea6d7b13d973822b022977aaf795844b489a4100bf
MD5 f63313f6e4a707907213356d6509f5d0
BLAKE2b-256 1a96ef8bab4177fbb5306473aaf46585506d1631e830be7fe9b03bf925759f89

See more details on using hashes here.

File details

Details for the file collective.fhirpath-0.8.0-py2.py3-none-any.whl.

File metadata

  • Download URL: collective.fhirpath-0.8.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 332.2 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.8.2 requests/2.27.1 setuptools/42.0.2 requests-toolbelt/0.9.1 tqdm/4.63.0 CPython/3.7.8

File hashes

Hashes for collective.fhirpath-0.8.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 c1116eba802d866c5a67ae4e457a1199dd7188ff1efd2e7f4b97fb8c5c0dc103
MD5 b2a49682679f75ed9669d0734e5417ff
BLAKE2b-256 304297b93a00d08f1fd84e46d2addf4b169b2e9f234b578cf9ac460cc335aea9

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page