From 0184b3024dd08da3d7756f6d753d2bca5eda1270 Mon Sep 17 00:00:00 2001 From: jingtang10 Date: Fri, 5 Mar 2021 00:04:59 +0000 Subject: [PATCH 1/5] Use HAPI's FHIRPathEngine for indexing resources. --- core/build.gradle | 3 + .../android/fhir/index/ResourceIndexer.kt | 453 +++++++----------- .../android/fhir/index/entities/TokenIndex.kt | 2 +- .../main/java/org/fhir/ucum/UcumException.kt | 27 ++ .../index/{impl => }/ResourceIndexerTest.kt | 3 +- deps.gradle | 2 + 6 files changed, 194 insertions(+), 296 deletions(-) create mode 100644 core/src/main/java/org/fhir/ucum/UcumException.kt rename core/src/test/java/com/google/android/fhir/index/{impl => }/ResourceIndexerTest.kt (99%) diff --git a/core/build.gradle b/core/build.gradle index 77dcbf6c75..dd77694d0b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -81,6 +81,9 @@ dependencies { coreLibraryDesugaring deps.desugar + // Needed for use of HAPI's FHIRPathEngine. + // See https://github.com/hapifhir/hapi-fhir/issues/2444. + implementation deps.caffeine implementation deps.cql_engine.fhir implementation deps.guava implementation deps.kotlin.stdlib diff --git a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt index 502dc42552..bcdec9bf49 100644 --- a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt +++ b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt @@ -16,7 +16,8 @@ package com.google.android.fhir.index -import android.util.Log +import ca.uhn.fhir.context.FhirContext +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport import ca.uhn.fhir.model.api.annotation.SearchParamDefinition import com.google.android.fhir.index.entities.DateIndex import com.google.android.fhir.index.entities.NumberIndex @@ -26,353 +27,219 @@ import com.google.android.fhir.index.entities.StringIndex import com.google.android.fhir.index.entities.TokenIndex import com.google.android.fhir.index.entities.UriIndex import java.math.BigDecimal -import java.util.Locale -import org.hl7.fhir.instance.model.api.IBaseDatatype -import org.hl7.fhir.r4.model.BaseDateTimeType +import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext +import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.CodeableConcept -import org.hl7.fhir.r4.model.Coding +import org.hl7.fhir.r4.model.DateType +import org.hl7.fhir.r4.model.DecimalType +import org.hl7.fhir.r4.model.Identifier +import org.hl7.fhir.r4.model.InstantType +import org.hl7.fhir.r4.model.IntegerType import org.hl7.fhir.r4.model.Money import org.hl7.fhir.r4.model.Quantity -import org.hl7.fhir.r4.model.Range -import org.hl7.fhir.r4.model.Ratio import org.hl7.fhir.r4.model.Reference import org.hl7.fhir.r4.model.Resource -import org.hl7.fhir.r4.model.StringType import org.hl7.fhir.r4.model.UriType +import org.hl7.fhir.r4.model.codesystems.SearchParamType +import org.hl7.fhir.r4.utils.FHIRPathEngine +/** + * Indexes a FHIR resource according to the [search parameters](https://www.hl7.org/fhir/searchparameter-registry.html). + */ internal object ResourceIndexer { + private val context = FhirContext.forR4() + private val fhirPathEngine = FHIRPathEngine( + HapiWorkerContext(context, DefaultProfileValidationSupport(context)) + ) + fun index(resource: R) = extractIndexValues(resource) - /** Extracts the values to be indexed for `resource`. */ private fun extractIndexValues(resource: R): ResourceIndices { val indexBuilder = ResourceIndices.Builder(resource.resourceType, resource.id) resource.javaClass.fields.asSequence().mapNotNull { it.getAnnotation(SearchParamDefinition::class.java) }.filter { - it.path.hasDotNotationOnly() - }.forEach { searchParamDefinition -> - when (searchParamDefinition.type) { - SEARCH_PARAM_DEFINITION_TYPE_STRING -> { - resource.valuesForPath(searchParamDefinition).stringValues().forEach { value -> - indexBuilder.addStringIndex( - StringIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - value = value - )) - } + it.path.isNotEmpty() + }.map { + it to fhirPathEngine.evaluate(resource, it.path) + }.flatMap { pair -> + pair.second.map { pair.first to it } + }.forEach { pair -> + val (searchParam, value) = pair + when (SearchParamType.fromCode(pair.first.type)) { + SearchParamType.NUMBER -> numberIndex(searchParam, value)?.also { + indexBuilder.addNumberIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_REFERENCE -> { - resource.valuesForPath(searchParamDefinition) - .referenceValues() - .forEach { reference -> - if (reference.reference?.isNotEmpty() == true) { - indexBuilder.addReferenceIndex( - ReferenceIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - value = reference.reference - )) - } - } + SearchParamType.DATE -> dateIndex(searchParam, value)?.also { + indexBuilder.addDateIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_CODE -> { - resource.valuesForPath(searchParamDefinition).codeValues().forEach { code -> - val system = code.system - val value = code.code - if (system?.isNotEmpty() == true && value?.isNotEmpty() == true) { - indexBuilder.addTokenIndex( - TokenIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - system = system, - value = value - )) - } - } + SearchParamType.STRING -> stringIndex(searchParam, value)?.also { + indexBuilder.addStringIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_QUANTITY -> { - resource.valuesForPath(searchParamDefinition) - .quantityValues() - .forEach { quantity -> - - val system: String - val unit: String - val value: BigDecimal - - if (quantity is Quantity) { - system = quantity.system - unit = quantity.unit - value = quantity.value - } else if (quantity is Money) { - system = FHIR_CURRENCY_SYSTEM - unit = quantity.currency - value = quantity.value - } else { - throw IllegalArgumentException( - "$quantity is of unknown type ${quantity.javaClass.simpleName}") - } - - indexBuilder.addQuantityIndex( - QuantityIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - system = system, - unit = unit, - value = value - )) - } + SearchParamType.TOKEN -> tokenIndex(searchParam, value).forEach { + indexBuilder.addTokenIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_URI -> { - resource.valuesForPath(searchParamDefinition) - .uriValues() - .forEach { uri -> - indexBuilder.addUriIndex( - UriIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - uri = uri - )) - } + SearchParamType.REFERENCE -> referenceIndex(searchParam, value)?.also { + indexBuilder.addReferenceIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_DATE -> { - resource.valuesForPath(searchParamDefinition).dateValues().forEach { date -> - indexBuilder.addDateIndex( - DateIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - tsHigh = date.value.time, - tsLow = date.value.time, - temporalPrecision = date.precision)) - } + SearchParamType.QUANTITY -> quantityIndex(searchParam, value)?.also { + indexBuilder.addQuantityIndex(it) } - SEARCH_PARAM_DEFINITION_TYPE_NUMBER -> { - resource.valuesForPath(searchParamDefinition).numberValues().forEach { number -> - indexBuilder.addNumberIndex( - NumberIndex( - name = searchParamDefinition.name, - path = searchParamDefinition.path, - value = number)) - } + SearchParamType.URI -> uriIndex(searchParam, value)?.also { + indexBuilder.addUriIndex(it) } - - // TODO: Implement token, composite and special search parameter types. } } - // For all resources, - // add 'last updated' timestamp to date index + + // Add 'lastUpdated' index to all resources. if (resource.meta.hasLastUpdated()) { val lastUpdatedElement = resource.meta.lastUpdatedElement indexBuilder.addDateIndex( DateIndex( - name = "lastUpdated", - path = arrayOf(resource.fhirType(), "meta", "lastUpdated") - .joinToString(separator = "."), + name = "_lastUpdated", + path = arrayOf( + resource.fhirType(), + "meta", + "lastUpdated" + ).joinToString(separator = "."), tsHigh = lastUpdatedElement.value.time, tsLow = lastUpdatedElement.value.time, temporalPrecision = lastUpdatedElement.precision - )) + ) + ) } + return indexBuilder.build() } - /** - * Returns the representative string values for the list of `objects`. - * - * If an object in the list is a Java [String], the returned list will contain the value of - * the Java [String]. If an object in the list is a FHIR [StringType], the returned - * list will contain the value of the FHIR [StringType]. If an object in the list matches a - * server defined search type (HumanName, Address, etc), the returned list will contain the - * string value representative of the type. - */ - private fun Sequence.stringValues(): Sequence { - return mapNotNull { - when (it) { - is String -> { - it - } - is StringType -> { - it.value - } - else -> { - // TODO: Implement the server defined search parameters. According to - // https://www.hl7.org/fhir/searchparameter-registry.html, name, device name, - // and address are defined by the server - // (the FHIR Engine library in this case). - null - } - } + private fun numberIndex(searchParam: SearchParamDefinition, value: Base): NumberIndex? = + when (value.fhirType()) { + "integer" -> NumberIndex( + searchParam.name, + searchParam.path, + BigDecimal((value as IntegerType).value) + ) + "decimal" -> NumberIndex( + searchParam.name, + searchParam.path, + (value as DecimalType).value + ) + else -> null } - } - /** Returns the reference values for the list of `objects`. */ - private fun Sequence.referenceValues(): Sequence { - return filterIsInstance(Reference::class.java) - } - - /** Returns the code values for the list of `objects`. */ - private fun Sequence.codeValues(): Sequence { - return flatMap { - if (it is CodeableConcept) { - it.coding.asSequence() - } else { - emptySequence() + private fun dateIndex(searchParam: SearchParamDefinition, value: Base): DateIndex? = + when (value.fhirType()) { + "date" -> { + val date = value as DateType + DateIndex( + searchParam.name, + searchParam.path, + date.value.time, + date.value.time, + date.precision + ) } - } - } - - /** Returns the quantity values for the list of `objects`. */ - private fun Sequence.quantityValues(): Sequence { - return flatMap { - when (it) { - is Money -> sequenceOf(it).filter { it.hasCurrency() } - is Quantity -> sequenceOf(it).filter { it.hasSystem() && it.hasCode() } - is Range -> sequenceOf(it.low, it.high).filter { it.hasSystem() && it.hasCode() } - is Ratio -> sequenceOf(it.numerator, it.denominator) - .filter { it.hasSystem() && it.hasCode() } - // TODO: Find other FHIR datatypes types the "quantity" type maps to. - // See: http://hl7.org/fhir/datatypes.html#quantity - // TODO: Add tests for Range and Ratio types - else -> emptySequence() + "instant" -> { + val instant = value as InstantType + DateIndex( + searchParam.name, + searchParam.path, + instant.value.time, + instant.value.time, + instant.precision + ) } + else -> null } - } - /** Returns the uri values for the list of `objects`. */ - private fun Sequence.uriValues(): Sequence { - return flatMap { - when (it) { - is UriType -> sequenceOf(it.value) - is String -> sequenceOf(it) - else -> emptySequence() - } + private fun stringIndex(searchParam: SearchParamDefinition, value: Base): StringIndex? = + if (!value.isEmpty) { + StringIndex(searchParam.name, searchParam.path, value.toString()) + } else { + null } - } - /** Returns the Date values for a list of `objects`. */ - private fun Sequence.dateValues(): Sequence { - return flatMap { - /** BaseDateTimeType wraps around [java.util.Date] which is what we use to extract the - * timestamp. Some implementations return the timestamp in local (device) timezone. - * Additionally, time zones are likely to be missing from health data. Date indexing - * is a work in progress. - */ - if (it is BaseDateTimeType) { - sequenceOf(it) - } else { - emptySequence() + private fun tokenIndex(searchParam: SearchParamDefinition, value: Base): List = + when (value.fhirType()) { + "boolean" -> + listOf(TokenIndex( + searchParam.name, + searchParam.path, + null, + value.primitiveValue() + ) + ) + "Identifier" -> { + val identifier = value as Identifier + if (identifier.value != null) { + listOf( + TokenIndex( + searchParam.name, + searchParam.path, + identifier.system, + identifier.value + ) + ) + } else { + listOf() + } } - }.filter { it.value != null } - } - - /** Returns the number values for a list of `objects`. */ - private fun Sequence.numberValues(): Sequence { - return flatMap { - when { - it is Integer -> sequenceOf(it.toInt().toBigDecimal()) - it is BigDecimal -> sequenceOf(it) - else -> emptySequence() + "CodeableConcept" -> { + val codeableConcept = value as CodeableConcept + codeableConcept.coding.filter { + it.code != null && it.code!!.isNotEmpty() + }.map { + TokenIndex(searchParam.name, searchParam.path, it.system ?: "", it.code) + } } - }.filterNotNull() - } - - /** Returns the list of values corresponding to the `path` in the `resource`. */ - private fun Resource.valuesForPath(definition: SearchParamDefinition): Sequence { - val paths = definition.path.split(SEPARATOR_REGEX) - if (paths.size <= 1) { - return emptySequence() + else -> listOf() } - return paths.asSequence().drop(1).fold(sequenceOf(this)) { acc, next -> - getFieldValues(acc, next, definition.type) + + private fun referenceIndex(searchParam: SearchParamDefinition, value: Base?): ReferenceIndex? { + val reference = (value as Reference)?.reference + return reference?.let { + ReferenceIndex(searchParam.name, searchParam.path, it) } } - /** - * Returns the list of field values for `fieldName` in each of the `objects`. - * - * If the field is a [Collection], it will be expanded and each element of the [Collection] - * will be added to the returned value. - */ - private fun getFieldValues( - objects: Sequence, - fieldName: String, - type: String - ): Sequence { - return objects.asSequence().flatMap { - val value = try { - /* TODO - * Upstream HAPI FHIR returns FHIR date* types from getxxDate methods as - * java.util.Date. For HAPI FHIR BaseDateTimeTypes, which support TimeZones - * we need to invoke() getxxDateElement. Hence we need to pass in search parameter - * type to getGetterName below. - */ - it.javaClass.getMethod(getGetterName(fieldName, type)).invoke(it) - } catch (error: Throwable) { - Log.w(TAG, error) - null + private fun quantityIndex(searchParam: SearchParamDefinition, value: Base): QuantityIndex? = + when (value.fhirType()) { + "Money" -> { + val money = value as Money + QuantityIndex( + searchParam.name, + searchParam.path, + FHIR_CURRENCY_CODE_SYSTEM, + money.currency, + money.value + ) } - if (value is Collection<*>) { - value.asSequence() - } else { - sequenceOf(value) + "Quantity" -> { + val quantity = value as Quantity + QuantityIndex( + searchParam.name, + searchParam.path, + quantity.system ?: "", + quantity.unit ?: "", + quantity.value + ) } - }.filterNotNull() - } + else -> null + } - /** Returns the name of the method to retrieve the field `fieldName`. */ - private fun getGetterName(fieldName: String, type: String): String { - val baseGetter = GETTER_PREFIX + - fieldName.substring(0, 1).toUpperCase(Locale.US) + - fieldName.substring(1) - when (type) { - "date" -> return baseGetter + GETTER_SUFFIX_DATE - else -> return baseGetter + private fun uriIndex(searchParam: SearchParamDefinition, value: Base?): UriIndex? { + val uri = (value as UriType).value + return if (uri.isNotEmpty()) { + UriIndex(searchParam.name, searchParam.path, uri) + } else { + null } } /** - * Returns whether the given path only uses a dot notation with no additional expressions such - * as where() or exists(). + * The FHIR currency code system. + * See: https://bit.ly/30YB3ML. + * See: https://www.hl7.org/fhir/valueset-currencies.html. */ - @Suppress("NOTHING_TO_INLINE") - private inline fun String.hasDotNotationOnly() = matches(DOT_NOTATION_REGEX) - - /** The prefix of getter methods for retrieving field values. */ - private const val GETTER_PREFIX = "get" - - /** The suffix of getter methods for retrieving a date 'Element'. */ - private const val GETTER_SUFFIX_DATE = "Element" - - /** The regular expression for the separator */ - private val SEPARATOR_REGEX = "\\.".toRegex() - - /** The string representing the string search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_STRING = "string" - - /** The string representing the reference search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_REFERENCE = "reference" - - /** The string representing the code search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_CODE = "token" - - /** The string representing the quantity search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_QUANTITY = "quantity" - - /** The string representing the uri search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_URI = "uri" - - /** The string representing the date search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_DATE = "date" - - /** The string representing the number search parameter type. */ - private const val SEARCH_PARAM_DEFINITION_TYPE_NUMBER = "number" - - /** The string for FHIR currency system */ - // See: https://bit.ly/30YB3ML - // See: https://www.hl7.org/fhir/valueset-currencies.html - private const val FHIR_CURRENCY_SYSTEM = "urn:iso:std:iso:4217" - - /** Tag for logging. */ - private const val TAG = "FhirIndexerImpl" - private val DOT_NOTATION_REGEX = "^[a-zA-Z0-9.]+$".toRegex() + private const val FHIR_CURRENCY_CODE_SYSTEM = "urn:iso:std:iso:4217" } diff --git a/core/src/main/java/com/google/android/fhir/index/entities/TokenIndex.kt b/core/src/main/java/com/google/android/fhir/index/entities/TokenIndex.kt index a7452ee5bc..4dabfd7dff 100644 --- a/core/src/main/java/com/google/android/fhir/index/entities/TokenIndex.kt +++ b/core/src/main/java/com/google/android/fhir/index/entities/TokenIndex.kt @@ -27,7 +27,7 @@ internal data class TokenIndex( /** The path of the code index, e.g. "Observation.code". */ val path: String, /** The system of the code index, e.g. "http://openmrs.org/concepts". */ - val system: String, + val system: String?, /** The value of the code index, e.g. "1427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA". */ val value: String ) diff --git a/core/src/main/java/org/fhir/ucum/UcumException.kt b/core/src/main/java/org/fhir/ucum/UcumException.kt new file mode 100644 index 0000000000..9380e6727b --- /dev/null +++ b/core/src/main/java/org/fhir/ucum/UcumException.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.fhir.ucum + +import org.hl7.fhir.exceptions.FHIRException + +/** Needed for HAPI's FHIRPathEngine. See https://github.com/hapifhir/hapi-fhir/issues/2443. */ +class UcumException : FHIRException { + constructor() {} + constructor(message: String?, cause: Throwable?) : super(message, cause) {} + constructor(message: String?) : super(message) {} + constructor(cause: Throwable?) : super(cause) {} +} diff --git a/core/src/test/java/com/google/android/fhir/index/impl/ResourceIndexerTest.kt b/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt similarity index 99% rename from core/src/test/java/com/google/android/fhir/index/impl/ResourceIndexerTest.kt rename to core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt index 934fe40ccf..daed8b64b8 100644 --- a/core/src/test/java/com/google/android/fhir/index/impl/ResourceIndexerTest.kt +++ b/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt @@ -14,11 +14,10 @@ * limitations under the License. */ -package com.google.android.fhir.index.impl +package com.google.android.fhir.index import android.os.Build import ca.uhn.fhir.context.FhirContext -import com.google.android.fhir.index.ResourceIndexer import com.google.android.fhir.index.entities.DateIndex import com.google.android.fhir.index.entities.NumberIndex import com.google.android.fhir.index.entities.QuantityIndex diff --git a/deps.gradle b/deps.gradle index 82075962ef..6b8edf3fcd 100644 --- a/deps.gradle +++ b/deps.gradle @@ -19,6 +19,7 @@ versions.atsl_expresso = '3.3.0' versions.atsl_junit = '1.1.2' versions.atsl_rules = '1.1.0' versions.atsl_runner = '1.1.0' +versions.caffeine = '2.9.0' versions.constraint_layout = '1.1.3' versions.coroutines = '1.4.2' versions.core = '1.2.0' @@ -54,6 +55,7 @@ atsl.ext_junit_ktx = "androidx.test.ext:junit-ktx:$versions.atsl_junit" atsl.rules = "androidx.test:rules:$versions.atsl_rules" atsl.runner = "androidx.test:runner:$versions.atsl_runner" deps.atsl = atsl +deps.caffeine = "com.github.ben-manes.caffeine:$versions.caffeine" deps.constraint_layout = "androidx.constraintlayout:constraintlayout:$versions.constraint_layout" deps.core = "androidx.core:core-ktx:$versions.core" def coroutines = [:] From 2bf77f6cb5e088a3af6ad8de7bbe38a119ead496 Mon Sep 17 00:00:00 2001 From: jingtang10 Date: Fri, 5 Mar 2021 00:13:16 +0000 Subject: [PATCH 2/5] Reformat code (indentation) --- .../google/android/fhir/index/ResourceIndexer.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt index bcdec9bf49..9e28b49a42 100644 --- a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt +++ b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt @@ -162,12 +162,13 @@ internal object ResourceIndexer { private fun tokenIndex(searchParam: SearchParamDefinition, value: Base): List = when (value.fhirType()) { "boolean" -> - listOf(TokenIndex( - searchParam.name, - searchParam.path, - null, - value.primitiveValue() - ) + listOf( + TokenIndex( + searchParam.name, + searchParam.path, + system = null, + value.primitiveValue() + ) ) "Identifier" -> { val identifier = value as Identifier From 7552f95a8c8eb899fbc6b3530ed297d5b84441a7 Mon Sep 17 00:00:00 2001 From: jingtang10 Date: Fri, 5 Mar 2021 00:47:48 +0000 Subject: [PATCH 3/5] Correct caffeine dependency string --- deps.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps.gradle b/deps.gradle index 6b8edf3fcd..52828ce34a 100644 --- a/deps.gradle +++ b/deps.gradle @@ -55,7 +55,7 @@ atsl.ext_junit_ktx = "androidx.test.ext:junit-ktx:$versions.atsl_junit" atsl.rules = "androidx.test:rules:$versions.atsl_rules" atsl.runner = "androidx.test:runner:$versions.atsl_runner" deps.atsl = atsl -deps.caffeine = "com.github.ben-manes.caffeine:$versions.caffeine" +deps.caffeine = "com.github.ben-manes.caffeine:caffeine:$versions.caffeine" deps.constraint_layout = "androidx.constraintlayout:constraintlayout:$versions.constraint_layout" deps.core = "androidx.core:core-ktx:$versions.core" def coroutines = [:] From f2176d37ade67e04e48856fcd0db6283a832f2de Mon Sep 17 00:00:00 2001 From: jingtang10 Date: Fri, 5 Mar 2021 01:18:52 +0000 Subject: [PATCH 4/5] Update failing test --- .../java/com/google/android/fhir/index/ResourceIndexerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt b/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt index daed8b64b8..9a9a9e40a1 100644 --- a/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt +++ b/core/src/test/java/com/google/android/fhir/index/ResourceIndexerTest.kt @@ -276,7 +276,7 @@ class ResourceIndexerTest { assertThat(resourceIndices.dateIndices) .contains( DateIndex( - "lastUpdated", + "_lastUpdated", "Patient.meta.lastUpdated", lastUpdatedElement.getValue().getTime(), lastUpdatedElement.getValue().getTime(), From ee0d3dbcadfd66a5d50f50f950e26faa42ee57d2 Mon Sep 17 00:00:00 2001 From: jingtang10 Date: Tue, 9 Mar 2021 14:01:17 +0000 Subject: [PATCH 5/5] Add TODOs to handle 2 missing search parameter types --- .../java/com/google/android/fhir/index/ResourceIndexer.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt index 9e28b49a42..ed180d974d 100644 --- a/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt +++ b/core/src/main/java/com/google/android/fhir/index/ResourceIndexer.kt @@ -88,6 +88,8 @@ internal object ResourceIndexer { SearchParamType.URI -> uriIndex(searchParam, value)?.also { indexBuilder.addUriIndex(it) } + // TODO: Handle composite type https://github.com/google/android-fhir/issues/292. + // TODO: Handle special type https://github.com/google/android-fhir/issues/293. } } @@ -196,8 +198,8 @@ internal object ResourceIndexer { else -> listOf() } - private fun referenceIndex(searchParam: SearchParamDefinition, value: Base?): ReferenceIndex? { - val reference = (value as Reference)?.reference + private fun referenceIndex(searchParam: SearchParamDefinition, value: Base): ReferenceIndex? { + val reference = (value as Reference).reference return reference?.let { ReferenceIndex(searchParam.name, searchParam.path, it) }