Skip to content

Commit

Permalink
♻️ Refactor: Use FHIR_DATA_TYPES instead of hardcoded values of data …
Browse files Browse the repository at this point in the history
…types
  • Loading branch information
camemre49 authored and Dogukan Cavdaroglu committed Oct 23, 2024
1 parent c6f8deb commit 60635f2
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tofhir.common.util

import io.onfhir.api.FHIR_DATA_TYPES
import io.onfhir.path.annotation.FhirPathFunction
import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext
import io.onfhir.path.{AbstractFhirPathFunctionLibrary, FhirPathEnvironment, FhirPathException, FhirPathExpressionEvaluator, FhirPathResult, FhirPathString, IFhirPathFunctionLibraryFactory}
Expand All @@ -24,7 +25,7 @@ class CustomMappingFunctions(context: FhirPathEnvironment, current: Seq[FhirPath
* @return Space separated numbers concatenated in a string
*/
@FhirPathFunction(documentation = "\uD83D\uDCDC Decodes the given data and converts it to an array of space separated numbers. Returns the space separated numbers concatenated in a string.\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`dataExpr`** \nString data such that byte representation of each 2 consecutive characters represents a number.\n\n\uD83D\uDD19 <span style=\"color:#ff0000;\">_@return_</span> \n```\n'123 456 123'\n``` \n\uD83D\uDCA1 **E.g.** cst:createTimeSeriesData(%data)",
insertText = "cst:createTimeSeriesData(<dataExpr>)", detail = "cst", label = "cst:createTimeSeriesData", kind = "Method", returnType = Seq("string"), inputType = Seq("string"))
insertText = "cst:createTimeSeriesData(<dataExpr>)", detail = "cst", label = "cst:createTimeSeriesData", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING))
def createTimeSeriesData(dataExpr: ExpressionContext): Seq[FhirPathResult] = {
val dataResult = new FhirPathExpressionEvaluator(context, current).visit(dataExpr)
if (dataResult.length > 1 || !dataResult.head.isInstanceOf[FhirPathString]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tofhir.engine.mapping.fhirPath

import io.onfhir.api.FHIR_DATA_TYPES
import io.onfhir.api.util.FHIRUtil
import io.onfhir.path._
import io.onfhir.path.annotation.FhirPathFunction
Expand Down Expand Up @@ -30,7 +31,7 @@ class FhirPathMappingFunctions(context: FhirPathEnvironment, current: Seq[FhirPa
detail = "mpp",
label = "mpp:getHashedId",
kind = "Function",
returnType = Seq("string"),
returnType = Seq(FHIR_DATA_TYPES.STRING),
inputType = Seq()
)
def getHashedId(resourceTypeExp:ExpressionContext, inputExpr:ExpressionContext):Seq[FhirPathResult] = {
Expand Down Expand Up @@ -79,7 +80,7 @@ class FhirPathMappingFunctions(context: FhirPathEnvironment, current: Seq[FhirPa
*/
@FhirPathFunction(documentation = "\uD83D\uDCDC Creates a sequence of indices between from-to integers and concatenates them and prefix string to generate looped field names (i.e. prefix+from,...,prefix+to). After that, for each field, it checks whether it has a value or not and returns the list of field names which have values i.e the non-empty ones.\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`prefixExpr`** \nPrefix string to be used to generate field names.\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`fromExpr`** \nThe start index (inclusive).\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`toExpr`** \nThe end index (inclusive).\n\n\uD83D\uDD19 <span style=\"color:#ff0000;\">_@return_</span> \n```\n[\"child_1\", \"child_3\", \"child_4\"]\n``` \n\uD83D\uDCA1 **E.g.** mpp:nonEmptyLoopedFields('child_',1,5)",
insertText = "mpp:nonEmptyLoopedFields(<prefixExpr>, <fromExpr>, <toExpr>)",detail = "mpp", label = "mpp:nonEmptyLoopedFields", kind = "Function",
returnType = Seq("String"), inputType = Seq())
returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq())
def nonEmptyLoopedFields(prefixExpr: ExpressionContext, fromExpr: ExpressionContext, toExpr: ExpressionContext): Seq[FhirPathResult] = {
val prefix = new FhirPathExpressionEvaluator(context, current).visit(prefixExpr)
if (prefix.length != 1 || !prefix.forall(_.isInstanceOf[FhirPathString]))
Expand Down Expand Up @@ -175,7 +176,7 @@ class FhirPathMappingFunctions(context: FhirPathEnvironment, current: Seq[FhirPa
*/
@FhirPathFunction(documentation = "\uD83D\uDCDC Get corresponding value from the given concept map with the given key and column name. If there is no concept found with given key (code), return empty. It returns a list of string. \n⚠\uFE0F A mapping concept with specified reference **must** be registered to the mapping as a context to use this function.\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`conceptMap`** \nA reference to the concept map context e.g. %obsConceptMap\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`source_code`** \nSource code to perform lookup operation in the concept map e.g. code\n\n\uD83D\uDCDD <span style=\"color:#ff0000;\">_@param_</span> **`columnName`** \nFHIRPath string literal providing the name of the interested column from the concept map context.\n\n\uD83D\uDD19 <span style=\"color:#ff0000;\">_@return_</span> \n```json\n[\n \"target-column-value-1\",\n ...\n]\n``` \n\uD83D\uDCA1 **E.g.** mpp:getConcept(%obsConceptMap, code, 'target_code')",
insertText = "mpp:getConcept(<%conceptMap>, <source_code>, <columnName>)", detail = "mpp", label = "mpp:getConcept"
, kind = "Function", returnType = Seq("string"), inputType = Seq())
, kind = "Function", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq())
def getConcept(conceptMap: ExpressionContext, keyExpr: ExpressionContext, columnName: ExpressionContext): Seq[FhirPathResult] = {
val mapName = conceptMap.getText.substring(1) // skip the leading % character
val conceptMapContext = getConceptMap(mapName)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tofhir.rxnorm

import io.onfhir.api.FHIR_DATA_TYPES
import io.onfhir.api.util.FHIRUtil
import io.onfhir.path.annotation.FhirPathFunction
import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext
Expand Down Expand Up @@ -27,8 +28,8 @@ class RxNormApiFunctionLibrary(rxNormApiClient:RxNormApiClient, context: FhirPat
detail = "rxn",
label = "rxn:findRxConceptIdByNdc",
kind = "Function",
returnType = Seq("string"),
inputType = Seq("string")
returnType = Seq(FHIR_DATA_TYPES.STRING),
inputType = Seq(FHIR_DATA_TYPES.STRING)
)
def findRxConceptIdsByNdc(ndcExpr:ExpressionContext):Seq[FhirPathResult] = {
val ndc: Option[String] =
Expand Down Expand Up @@ -59,7 +60,7 @@ class RxNormApiFunctionLibrary(rxNormApiClient:RxNormApiClient, context: FhirPat
label = "rxn:getMedicationDetails",
kind = "Function",
returnType = Seq("complex"),
inputType = Seq("string")
inputType = Seq(FHIR_DATA_TYPES.STRING)
)
def getMedicationDetails(rxcuiExpr:ExpressionContext):Seq[FhirPathResult] = {
val conceptIds = evaluator.visit(rxcuiExpr)
Expand Down Expand Up @@ -136,7 +137,7 @@ class RxNormApiFunctionLibrary(rxNormApiClient:RxNormApiClient, context: FhirPat
label = "rxn:findIngredientsOfDrug",
kind = "Function",
returnType = Seq("complex"),
inputType = Seq("string")
inputType = Seq(FHIR_DATA_TYPES.STRING)
)
def findIngredientsOfDrug(rxcuiExpr:ExpressionContext):Seq[FhirPathResult] = {
val rxcui: Option[String] =
Expand All @@ -162,8 +163,8 @@ class RxNormApiFunctionLibrary(rxNormApiClient:RxNormApiClient, context: FhirPat
detail = "rxn",
label = "rxn:getATC",
kind = "Function",
returnType = Seq("string"),
inputType = Seq("string")
returnType = Seq(FHIR_DATA_TYPES.STRING),
inputType = Seq(FHIR_DATA_TYPES.STRING)
)
def getATC(rxcuiExpr:ExpressionContext): Seq[FhirPathResult] = {
val rxcui: Option[String] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tofhir.server.service.fhir

import io.onfhir.api.FHIR_DATA_TYPES
import io.onfhir.api.validation.{ConstraintKeys, ElementRestrictions, ProfileRestrictions}
import io.onfhir.config.BaseFhirConfig
import io.onfhir.validation._
Expand Down Expand Up @@ -431,7 +432,7 @@ class SimpleStructureDefinitionService(fhirConfig: BaseFhirConfig) {
SimpleStructureDefinition(
id = resourceType,
path = resourceType,
dataTypes = Some(Seq(DataTypeWithProfiles("Element", None))),
dataTypes = Some(Seq(DataTypeWithProfiles(FHIR_DATA_TYPES.ELEMENT, None))),
isPrimitive = false,
isChoiceRoot = false,
isArray = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.tofhir.server.endpoint

import akka.http.scaladsl.model.{ContentTypes, HttpEntity, StatusCodes}
import io.onfhir.api.FHIR_DATA_TYPES
import io.tofhir.OnFhirTestContainer
import io.tofhir.common.model.Json4sSupport.formats
import io.tofhir.common.model.{DataTypeWithProfiles, SchemaDefinition, SimpleStructureDefinition}
Expand Down Expand Up @@ -181,12 +182,12 @@ class FhirDefinitionsEndpointTest extends BaseEndpointTest with OnFhirTestContai
val schemaUrl: String = "https://example.com/fhir/StructureDefinition/schema"
val schema: SchemaDefinition = SchemaDefinition(url = schemaUrl, version = "1.4.2", `type` = "Ty", name = "name", description = Some("description"), rootDefinition = None, fieldDefinitions = Some(Seq(
SimpleStructureDefinition(id = "element-with-definition",
path = "Ty.element-with-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty.element-with-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = Some("element-with-definition"), definition = Some("element definition"), comment = None, elements = None),
SimpleStructureDefinition(id = "element-with-no-definition",
path = "Ty.element-with-no-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty.element-with-no-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = Some("element-with-no-definition"), definition = None, comment = None, elements = None)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import akka.actor.ActorSystem
import akka.http.scaladsl.model.{ContentType, ContentTypes, HttpEntity, MediaTypes, Multipart, StatusCodes}
import akka.http.scaladsl.testkit.RouteTestTimeout
import io.onfhir.api.client.FhirBatchTransactionRequestBuilder
import io.onfhir.api.{FHIR_FOUNDATION_RESOURCES, Resource}
import io.onfhir.api.{FHIR_DATA_TYPES, FHIR_FOUNDATION_RESOURCES, Resource}
import io.tofhir.OnFhirTestContainer
import io.tofhir.common.model.{DataTypeWithProfiles, SchemaDefinition, SimpleStructureDefinition}
import io.tofhir.engine.model._
Expand Down Expand Up @@ -51,12 +51,12 @@ class SchemaEndpointTest extends BaseEndpointTest with OnFhirTestContainer {
val schema3: SchemaDefinition = SchemaDefinition(url = "https://example.com/fhir/StructureDefinition/schema3", version = SchemaDefinition.VERSION_LATEST, `type` = "Ty3", name = "name3", description = Some("description3"), rootDefinition = None, fieldDefinitions = Some(
Seq(
SimpleStructureDefinition(id = "element-with-definition",
path = "Ty3.element-with-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty3.element-with-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = Some("element-with-definition"), definition = Some("element definition"), comment = None, elements = None),
SimpleStructureDefinition(id = "element-with-no-definition",
path = "Ty3.element-with-no-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty3.element-with-no-definition", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = Some("element-with-no-definition"), definition = None, comment = None, elements = None)
Expand All @@ -69,12 +69,12 @@ class SchemaEndpointTest extends BaseEndpointTest with OnFhirTestContainer {
val schema4: SchemaDefinition = SchemaDefinition(url = "https://example.com/fhir/StructureDefinition/schema4", version = SchemaDefinition.VERSION_LATEST, `type` = "Ty4", name = "name4", description = Some("description4"), rootDefinition = None, fieldDefinitions = Some(
Seq(
SimpleStructureDefinition(id = "element-with-short",
path = "Ty4.element-with-short", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty4.element-with-short", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = Some("element-with-short"), definition = None, comment = None, elements = None),
SimpleStructureDefinition(id = "element-with-no-short",
path = "Ty4.element-with-no-short", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = "canonical", profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
path = "Ty4.element-with-no-short", dataTypes = Some(Seq(DataTypeWithProfiles(dataType = FHIR_DATA_TYPES.CANONICAL, profiles = Some(Seq("http://hl7.org/fhir/StructureDefinition/canonical"))))), isPrimitive = true,
isChoiceRoot = false, isArray = false, minCardinality = 0, maxCardinality = None,
boundToValueSet = None, isValueSetBindingRequired = None, referencableProfiles = None, constraintDefinitions = None, sliceDefinition = None,
sliceName = None, fixedValue = None, patternValue = None, referringTo = None, short = None, definition = None, comment = None, elements = None)
Expand Down Expand Up @@ -244,10 +244,10 @@ class SchemaEndpointTest extends BaseEndpointTest with OnFhirTestContainer {
val schema: SchemaDefinition = JsonMethods.parse(responseAs[String]).extract[SchemaDefinition]
val fieldDefinitions = schema.fieldDefinitions.get
fieldDefinitions.size shouldEqual 4
fieldDefinitions.head.dataTypes.get.head.dataType shouldEqual "integer"
fieldDefinitions(1).dataTypes.get.head.dataType shouldEqual "date"
fieldDefinitions(2).dataTypes.get.head.dataType shouldEqual "dateTime"
fieldDefinitions(3).dataTypes.get.head.dataType shouldEqual "string"
fieldDefinitions.head.dataTypes.get.head.dataType shouldEqual FHIR_DATA_TYPES.INTEGER
fieldDefinitions(1).dataTypes.get.head.dataType shouldEqual FHIR_DATA_TYPES.DATE
fieldDefinitions(2).dataTypes.get.head.dataType shouldEqual FHIR_DATA_TYPES.DATETIME
fieldDefinitions(3).dataTypes.get.head.dataType shouldEqual FHIR_DATA_TYPES.STRING
}
}

Expand Down

0 comments on commit 60635f2

Please sign in to comment.