Coder Social home page Coder Social logo

fhirbase / fhirbase-plv8 Goto Github PK

View Code? Open in Web Editor NEW
105.0 33.0 39.0 21.18 MB

[DEPRECATED] Fhirbase 2.0 is an FHIR relational storage

Home Page: https://health-samurai.io/fhirbase

License: Other

Shell 3.66% CoffeeScript 75.08% Ruby 0.13% PLpgSQL 3.73% Python 14.56% Roff 2.56% Dockerfile 0.27%

fhirbase-plv8's Introduction

fhirbase-plv8

Build Status

Features

This is new version of fhirbase, with support of DSTU-2 and planned support many advanced features:

  • Extended query syntax
  • Terminologies
  • Profile validation
  • References validation
  • ValueSet validation

Motivation

While crafting Health IT systems we understand an importance of a properly chosen domain model. FHIR is an open source new generation lightweight standard for health data interoperability, which (we hope) could be used as a foundation for Health IT systems. FHIR is based on a concept of resource.

FHIR® is a next generation standards framework created by HL7. FHIR combines the best features of HL7 Version 2, Version 3 and CDA® product lines while leveraging the latest web standards and applying a tight focus on implementability.

We also learned that data is a heart of any information system, and should be reliably managed. PostgreSQL is a battle proven open source database which supports structured documents (jsonb) while preserving ACID guaranties and richness of SQL query language.

PostgreSQL is a powerful, open source object-relational database system. It has more than 15 years of active development and a proven architecture that has earned it a strong reputation for reliability, data integrity, and correctness.

Here is the list of PostgreSQL features that we use:

Installation

To install fhirbase you need postgresql-9.4 and plv8 extension.

sudo apt-get install postgresql-contrib-9.4 postgresql-9.4-plv8  -qq -y
psql -c "CREATE USER \"user\" WITH PASSWORD 'password'"
psql -c 'CREATE DATABASE fhirbase;' -U user
psql -c '\dt' -U postgres
export DATABASE_URL=postgres://user:password@localhost:5432/fhirbase

wget https://github.com/fhirbase/fhirbase-plv8/releases/download/v<version of the fhirbase>/fhirbase-<version of the fhirbase>.sql.zip
unzip fhirbase-<version of the fhirbase>.sql.zip

cat fhirbase-<version of the fhirbase>.sql | psql fhirbase

Upgrade

export DATABASE_URL=postgres://user:password@localhost:5432/fhirbase

wget https://github.com/fhirbase/fhirbase-plv8/releases/download/v<version of the fhirbase>/fhirbase-<version of the fhirbase>-patch.sql.zip
unzip fhirbase-<version of the fhirbase>-patch.sql.zip

cat fhirbase-<version of the fhirbase>-patch.sql | psql fhirbase

Development Installation

Development installation requires node v6.2.0 or newer and npm 3.0.0 or newer, which could be installed by nvm:

# install node < 0.12 by nvm for example
sudo apt-get install postgresql-contrib-9.4 postgresql-9.4-plv8  -qq -y

git clone https://github.com/fhirbase/fhirbase-plv8
cd fhirbase-plv8
git submodule init && git submodule update

npm install && cd plpl && npm install
npm install -g mocha && npm install -g coffee-script

psql -c "CREATE USER fb WITH PASSWORD 'fb'"
psql -c 'ALTER ROLE fb WITH SUPERUSER'
psql -c 'CREATE DATABASE fhirbase;' -U postgres
psql -c '\dt' -U postgres

export DATABASE_URL=postgres://fb:fb@localhost:5432/fhirbase

# build migrations
coffee  utils/generate_schema.coffee -n  | psql fhirbase
cat utils/patch_3.sql | psql fhirbase

# change something
# reload schema

plpl/bin/plpl reload
npm run test

# goto: change something

Run test suite in docker container

git clone https://github.com/fhirbase/fhirbase-plv8 fhirbase
cd fhirbase
docker build .

PostgreSQL Config For Plv8

If you have permissions to edit PostgreSQL config, add directive for auto setting plv8 parameter for every connection. It will make your debugging and development much easier:

echo "plv8.start_proc='plv8_init'" >> /etc/postgresql/9.4/main/postgresql.conf

Usage

To make fhirbase-plv8 work, just after opening connection to postgresql, you have to issue the following command (read more here):

SET plv8.start_proc = 'plv8_init';

Examples

SET plv8.start_proc = 'plv8_init';

-- work with storage

SELECT fhir_create_storage('{"resourceType": "Patient"}');
SELECT fhir_drop_storage('{"resourceType": "Patient"}');
SELECT fhir_truncate_storage('{"resourceType": "Patient"}');
-- delete all resources of specified type

-- the above commands should look like this:
$ psql fhirbase
psql (9.4.6)
Type "help" for help.

fhirbase=# SET plv8.start_proc = 'plv8_init';
SET
fhirbase=# SELECT fhir_create_storage('{"resourceType": "Patient"}');
                  fhir_create_storage                  
-------------------------------------------------------
 {"status":"ok","message":"Table patient was created"}
(1 row)

fhirbase=# 


-- CRUD

SELECT fhir_create_resource('{"resource": {"resourceType": "Patient", "name": [{"given": ["Smith"]}]}}');

-- create will fail if id provided, to create with predefined id pass [allowId] option or use fhir_update_resource
SELECT fhir_create_resource('{"allowId": true, "resource": {"resourceType": "Patient", "id": "smith"}}');

-- conditional create
SELECT fhir_create_resource('{"ifNoneExist": "identifier=007", "resource": {"resourceType": "Patient", "id": "smith", "name": [{"given": ["Smith"]}]}}');

SELECT fhir_read_resource('{"resourceType": "Patient", "id": "smith"}');

SELECT fhir_vread_resource('{"resourceType": "Patient", "id": "????", "versionId": "????"}');

SELECT fhir_resource_history('{"resourceType": "Patient", "id": "smith"}');

SELECT fhir_resource_type_history('{"resourceType": "Patient", "queryString": "_count=2&_since=2015-11"}');

SELECT fhir_update_resource('{"resource": {"resourceType": "Patient", "id": "smith", "name": [{"given": ["John"], "family": ["Smith"]}]}}');

-- conditional update
SELECT fhir_update_resource('{"ifNoneExist": "identifier=007", "resource": {"resourceType": "Patient", "id": "smith", "name": [{"given": ["Smith"]}]}}');

-- update with contention guard
SELECT fhir_update_resource('{"ifMatch": "..versionid..", "resource": {"resourceType": "Patient", "id": "smith", "name": [{"given": ["Smith"]}]}}');

SELECT fhir_search('{"resourceType": "Patient", "queryString": "name=smith"}');

SELECT fhir_index_parameter('{"resourceType": "Patient", "name": "name"}');
SELECT fhir_unindex_parameter('{"resourceType": "Patient", "name": "name"}');

SELECT fhir_search_sql('{"resourceType": "Patient", "queryString": "name=smith"}');
-- see generated SQL

SELECT fhir_explain_search('{"resourceType": "Patient", "queryString": "name=smith"}');
-- see execution plan

-- mark resource as deleted (i.e. keep history)
SELECT fhir_delete_resource('{"resourceType": "Patient", "id": "smith"}');

-- completely delete resource and it history
SELECT fhir_terminate_resource('{"resourceType": "Patient", "id": "smith"}');

-- expand valueset
SELECT fhir_valueset_expand('{"id": "issue-types", "filter": "err"}');

---

SELECT fhir_conformance('{"default": "values"}');
-- return simple Conformance resource, based on created stores

---

-- use different methods to calculate total elements to improve performance: no _totalMethod or _totalMethod=exact uses standard approach
SELECT fhir_search('{"resourceType": "Patient", "queryString": "name=smith"}');
SELECT fhir_search('{"resourceType": "Patient", "queryString": "name=smith&_totalMethod=exact"}');

-- _totalMethod=extimated - faster but 'total' is estimated.
SELECT fhir_search('{"resourceType": "Patient", "queryString": "name=smith&_totalMethod=estimated"}');

-- _totalMethod=no - fastest but no 'total' is returned.
SELECT fhir_search('{"resourceType": "Patient", "queryString": "name=smith&_totalMethod=no"}');

Contributing

See the CONTRIBUTING.md.

License

Copyright © 2016 health samurai.

fhirbase is released under the terms of the MIT License.

fhirbase-plv8's People

Contributors

aitem avatar alexandertakacs avatar alexpetrov avatar bazai avatar ben-healthforge avatar bolik avatar danil avatar dburdick avatar esergueev avatar eugwne avatar harikt avatar jac-c-c avatar karsiwek-kainos avatar maksym avatar mlapshin avatar niquola avatar nwehr avatar pavelone avatar semalexa avatar vadi2 avatar vadimnehta 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  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  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  avatar

Watchers

 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

fhirbase-plv8's Issues

Production Stability?

Hi, i'm wondering how stable this new version is for implementing on a production environment if I instead point it to a MySQL database. Any information would be greatly appreciated.

Put whole fhirbase into one schema

Related to https://github.com/fhirbase/fhirbase/issues/136

We need to have ability to server multiple clients from a single database. Currently fhirbase puts all resource tables in a single schema public. The other schemas contain stored procedures.

Ideally it would be possible to create the schema per tenant. The stored procedures would respect >> search_path so that SET search_path TO 'schema1' would effectively mean that we are using data only from schema1.

The possible extension would be to configure that separate schemas are stored in different tablespaces.

Road map

Create road map for the near future:

  • one schema installation
  • move all logical tests from fhirbase and pass them
  • move all issues from fhirbase
  • documentation
  • handle timezones

Structure definition for MedicationOrder wrong medication reference definition

Structure definition indicates that there is
MedicationOrder.medication[x]
but there is no way to relate it to fields like medicationReference and requests cannot be validated.
Used example from FHIR documentation http://hl7.org/fhir/medicationorderexample1.json.html where there is field medicationReference, cannot be validated with structure definition from fhirbase - no field relation, as cannot get field by path from structure definition.

Search fails on plv8 version 1.4.4

fhir_serarch fails when using PG version 9.4.5 and plv8 version 1.4.4

Example

SELECT fhir_search('{"resourceType": "DeviceUseStatement", "queryString": "patient=x"}');
ERROR:  SyntaxError: Unexpected token o
DETAIL:  undefined() LINE 0: [object Object]

Could be related to this plv8/plv8@37a36d1

Database migrations & Release Tagging etc

We would prefer to use external database migrations mechanism not custom made migrations table approach. There are tools which have more complex checks on migration changesets.

The migration would need to consist everything in sql files. Plain sql without psql tool syntax.

Search by _id doesn't work properly

According to FHIR spec search by id should looks like:

 GET [base]/Patient?_id=23

but now FB finds resources by id only with resourceType within id, i.e.:

 GET [base]/Patient?_id=Patient/23

Repeated _include parameters doesn't work

When using repeated _include-parameter, not all resources are actually included. Comma separating the parameters instead seems to work though.

SELECT fhir_search('{"resourceType": "EpisodeOfCare", "queryString": "_include=care-manager&_include=organization"}');
 {"resourceType":"Bundle","type":"searchset","total":1,"link":[{"relation":"self","url":"EpisodeOfCare/_include=care-manager&_include=organization&page=1"}],"entry":[{"resource":{"id":"episode1","meta":{"versionId":"a09cd778-b82f-4a45-8bcd-4003b26e009c","lastUpdated":"2015-12-07T15:26:34.600Z"},"status":"active","patient":{"reference":"Patient/5212121212"},"careTeam":[{"member":{"reference":"Practitioner/19780909-5674"}},{"member":{"reference":"Practitioner/19841212-1212"}}],"identifier":[{"value":"episode1"}],"careManager":{"reference":"Practitioner/19780909-5674"},"resourceType":"EpisodeOfCare","managingOrganization":{"reference":"Organization/Radiology"}}},{"resource":{"id":"Radiology","meta":{"versionId":"ec09026d-8924-463c-b916-83aeeddac301","lastUpdated":"2015-12-10T09:38:59.604Z"},"name":"Radiology","identifier":[{"value":"Radiology"}],"resourceType":"Organization"}}]}

SELECT fhir_search('{"resourceType": "EpisodeOfCare", "queryString": "_include=care-manager,organization"}');
{"resourceType":"Bundle","type":"searchset","total":1,"link":[{"relation":"self","url":"EpisodeOfCare/_include=care-manager,organization&page=1"}],"entry":[{"resource":{"id":"episode1","meta":{"versionId":"a09cd778-b82f-4a45-8bcd-4003b26e009c","lastUpdated":"2015-12-07T15:26:34.600Z"},"status":"active","patient":{"reference":"Patient/5212121212"},"careTeam":[{"member":{"reference":"Practitioner/19780909-5674"}},{"member":{"reference":"Practitioner/19841212-1212"}}],"identifier":[{"value":"episode1"}],"careManager":{"reference":"Practitioner/19780909-5674"},"resourceType":"EpisodeOfCare","managingOrganization":{"reference":"Organization/Radiology"}}},{"resource":{"id":"19780909-5674","meta":{"versionId":"b7f61715-6598-4d38-9819-9f72edb98df5","lastUpdated":"2015-12-07T08:26:30.414Z"},"name":{"text":"Cecilia Davidsson"},"identifier":[{"value":"19780909-5674"}],"resourceType":"Practitioner","practitionerRole":[{"role":{"coding":[{"code":"224565004","system":"http://snomed.info/sct","display":"Doctor"}]},"managingOrganization":{"reference":"Organization/Radiology"}}]}},{"resource":{"id":"Radiology","meta":{"versionId":"ec09026d-8924-463c-b916-83aeeddac301","lastUpdated":"2015-12-10T09:38:59.604Z"},"name":"Radiology","identifier":[{"value":"Radiology"}],"resourceType":"Organization"}}]}

Milliseconds in timestamps not supported

Inserting a resource containing a timestamp with millisecond precision (following the xsDateTime-format specified by FHIR) causes search on such a parameter to fail.
Example:
First, inserting the following resource object:
SELECT fhir_create_resource( '{ "resource":{"resourceType":"DeviceUseStatement","id":"5b79686b-282b-4dca-aa6b-02aaba3f4dc7","whenUsed":{"start":"2015-11-05T16:06:56.000Z"},"device":{"reference":"Device/C1007-123"},"subject":{"reference":"Patient/1212121212"}}}' )
Then performing the following search yields an error (beware that this search uses a custom search parameter):
SELECT fhir_search('{"resourceType": "DeviceUseStatement", "queryString": "-period=le2015-11-05T16:07:56+00&-period=ge2015-11-05T16:05:56+00&device=C1007-123"}'); ERROR: date.to_range: Don't know how to handle 2015-11-05T16:06:56.000

It seems the millisecond part of a datetime-string is simply not handled in the functions of https://github.com/fhirbase/fhirbase-plv8/blob/master/src/fhir/date.coffee

Patient search by deceased flag fails

Call:

SELECT fhir_search('{"resourceType": "Patient", "queryString": "deceased=true"}');

fails with

ERROR: Token Search: unsuported type {"name":"deceased","resourceType":"Patient","path":["Patient","deceasedDateTime"],"searchType":"token","elementType":"dateTime","pathUsage":"normal","operator":"eq"}
    SQL state: XX000
    Detail: plv8_init() LINE 3842:       throw new Error("Token Search: unsuported type " + (JSON.stringify(meta)

'git clone' errors on windows

forbidden symbols ':' in file names

error: Invalid path 'migrations/2015-07-14T21:24:47.026Z__init.coffee'
error: Invalid path 'migrations/2015-09-22T12:27:00.660Z__schemas.coffee'
error: Invalid path 'migrations/2015-10-13T09:39:16.782Z__metadata.coffee'

fhir_update_resource validation errors

There are some validation issues with fhir_update_resource function

  1. update resource with non existing id and meta - fails
  2. update resource with non existing id - not fails, creates resource
  3. update resource without id in resource doesn't fail

Check: Search by date using "greater or lower than" comparator includes boundary values

When doing the search query using strict =< or => comparators for dates FhirBase returns all dates that are before or after specified date (respectively) plus date that equals to specified date.
So currently =< or => comparators for dates works like =<= or =>= comparators.

According to specification:
[parameter]=>[date]" searches for all resources where the specified date is after [date]
and
For "[parameter]=>[date]", the requirement is that the interval of the time after [date] intersects (i.e. overlaps) with the interval of time in the relevant resource element.

Check: Searching Encounters for patients within a organization (or no middle join criteria)

The below search fails because patient table is not joined at all.
Apparently there is a TODO at this line
--TODO: what if no middle join present ie we have a.b.c.attr = x and no a.b.attr condition

fhirbase=# select fhir._search('Encounter','patient:Patient.organization:Organization.name=Lectus');

ERROR: missing FROM-clause entry for table "patient"
LINE 2: ...ganization ON fhirbase_idx_fns.index_as_reference(patient.co...
^
QUERY: SELECT encounter.version_id, encounter.logical_id, encounter.resource_type, encounter.updated, encounter.published, encounter.category, encounter.content FROM encounter
JOIN organization ON fhirbase_idx_fns.index_as_reference(patient.content, '{managingOrganization}') && ARRAY[organization.logical_id]::text[] AND
(fhirbase_idx_fns.index_as_string(organization.content, '{name}') ilike '%Lectus%')
WHERE true = true
LIMIT 100
OFFSET 0
CONTEXT: PL/pgSQL function fhirbase_search.search(text,text) line 4 at RETURN QUERY
SQL function "_search" statement 1

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.