Skip to content

Commit

Permalink
Merge pull request #217 from lifeomic/fhir-sql
Browse files Browse the repository at this point in the history
feat: adds new feature Fhir.es_sql()
  • Loading branch information
Shawn Zhu authored Mar 13, 2024
2 parents eae170a + 4620bf0 commit f616345
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 3 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

_(NOTE: All examples use fictitious data or freely available data sets.)_

## [0.34.0] - 2024-03-13

### Added

- A New function `es_sql()` to `phc.services.Fhir` class to execute OpenSearch SQL.

Example:

```python
df = Fhir(session).es_sql(
project_id='xxx',
statement='SELECT id, subject.reference FROM diagnostic_report WHERE identifier.system = ? LIMIT 10',
params=[{
"type": "string",
"value": "example-identifier-system"
}]
).get_as_dataframe('datarows')
```

## [0.33.4] - 2023-11-02

### Fixed
Expand Down
5 changes: 5 additions & 0 deletions phc/api_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ def get_as_dataframe(
mapped = list(map(mapFunc, self.data.get(key)))
return _pd.DataFrame(mapped)

# support OpenSearch sql response
if key == "datarows" and self.data.get("schema") is not None:
column_names = [col["name"] for col in self.data.get("schema")]
return _pd.DataFrame(self.data.get(key), columns=column_names)

return _pd.DataFrame(self.data.get(key))

def validate(self):
Expand Down
37 changes: 35 additions & 2 deletions phc/services/fhir.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from phc.base_client import BaseClient
from phc import ApiResponse
from typing import List, Dict


class Fhir(BaseClient):
Expand Down Expand Up @@ -64,7 +65,7 @@ def sql(self, project: str, statement: str, scroll="") -> ApiResponse:
def execute_sql(
self, project_id: str, statement: str, scroll=""
) -> ApiResponse:
"""Executes an SQL query against fhir-searh-service
"""Executes an SQL query against fhir-search-service
Parameters
----------
Expand Down Expand Up @@ -106,7 +107,7 @@ def execute_sql(
def execute_es(
self, project_id: str, query: dict, scroll=""
) -> ApiResponse:
"""Executes an elasticsearch query against fhir-searh-service
"""Executes an elasticsearch query against fhir-search-service
Parameters
----------
Expand All @@ -127,3 +128,35 @@ def execute_es(
json=query,
params={"scroll": scroll},
)

def es_sql(
self,
project_id: str,
statement: str,
params: List[Dict],
subject_id="",
) -> ApiResponse:
"""Executes an OpenSearch SQL against fhir-search-service
Parameters
----------
project_id : str
The project ID
statement : str
The prepared OpenSearch SQL statement
params: List[Dict]
Returns
-------
phc.ApiResponse
The query response
"""
api_path = f"fhir-search/sql/projects/{project_id}"
if subject_id is not None and subject_id != "":
api_path = f"{api_path}/patients/{subject_id}"

return self._api_call(
api_path=api_path,
http_verb="POST",
json={"query": statement, "parameters": params},
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "phc"
version = "0.33.4"
version = "0.34.0"
description = "Python SDK for the LifeOmic platform"
authors = ["LifeOmic <[email protected]>"]
license = "MIT"
Expand Down
32 changes: 32 additions & 0 deletions tests/test_fhir_opensearch_sql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from phc import Session
import os
from phc.services import Fhir
from unittest.mock import patch
from test_session import jwt, sample


@patch("phc.base_client.BaseClient._api_call")
def test_es_sql(mock_api_call):
session = Session(token=jwt.encode(sample, "secret"), account="bar")
fhir = Fhir(session)
project_id = "bar"
query = "SELECT id, subject FROM diagnostic_report WHERE identifier.system = ? LIMIT 10"
params = [
{
"type": "string",
"value": "lrn:lo:dev:fountainlife:ehr:fountainlife:d22c690b-fb45-4ff2-8cb3-eed9f665cb30/DiagnosticReport",
}
]

res = fhir.es_sql(
project_id=project_id,
statement=query,
params=params,
)

mock_api_call.assert_called_once()
args, kwargs = mock_api_call.call_args

assert kwargs["api_path"] == f"fhir-search/sql/projects/{project_id}"
assert kwargs["json"]["query"] == query
assert kwargs["json"]["parameters"] == params

0 comments on commit f616345

Please sign in to comment.