Skip to content

Commit

Permalink
Add test for condition params chunking and wrapping in brackets
Browse files Browse the repository at this point in the history
  • Loading branch information
LZRS committed Jun 24, 2024
1 parent 8c720e2 commit c73037d
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ internal sealed class FilterCriteria(
* intended.
*/
private fun List<ConditionParam<*>>.toQueryString(operation: Operation) =
this.chunked(50) { conditionParams ->
this.chunked(CONDITION_PARAMS_CHUNK_SIZE) { conditionParams ->
conditionParams.joinToString(
separator = " ${operation.logicalOperator} ",
prefix = if (size > 1) "(" else "",
Expand All @@ -100,4 +100,14 @@ internal sealed class FilterCriteria(
}
}
.joinToString(separator = " ${operation.logicalOperator} ")

companion object {
/**
* Represents the number of [ConditionParam]s that can be wrapped within a bracket
*
* This is to prevent SQLite expression tree exceeding max depth of 1000 See
* https://www.sqlite.org/limits.html for Maximum Depth Of An Expression Tree
*/
const val CONDITION_PARAMS_CHUNK_SIZE = 50
}
}
48 changes: 48 additions & 0 deletions engine/src/test/java/com/google/android/fhir/search/SearchTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum
import ca.uhn.fhir.rest.param.ParamPrefixEnum
import com.google.android.fhir.DateProvider
import com.google.android.fhir.epochDay
import com.google.android.fhir.search.filter.FilterCriteria
import com.google.android.fhir.search.filter.ReferenceParamFilterCriterion
import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
import java.math.BigDecimal
Expand All @@ -31,6 +33,7 @@ import java.util.UUID
import kotlin.math.absoluteValue
import kotlin.math.roundToLong
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.CarePlan
import org.hl7.fhir.r4.model.CodeType
import org.hl7.fhir.r4.model.CodeableConcept
import org.hl7.fhir.r4.model.Coding
Expand Down Expand Up @@ -2728,6 +2731,51 @@ class SearchTest {
.inOrder()
}

@Test
fun `search CarePlan filter with large list of patient reference`() {
val patientIdReferenceList = (1..500).map { "Patient/patient-$it" }
val patientIdList =
patientIdReferenceList.map<String, ReferenceParamFilterCriterion.() -> Unit> {
{ value = it }
}
val query =
Search(ResourceType.CarePlan)
.apply { filter(CarePlan.SUBJECT, *patientIdList.toTypedArray()) }
.getQuery()

val queryString = query.query
assertThat(queryString)
.isEqualTo(
"""
SELECT a.resourceUuid, a.serializedResource
FROM ResourceEntity a
WHERE a.resourceType = ?
AND a.resourceUuid IN (
SELECT resourceUuid FROM ReferenceIndexEntity
WHERE resourceType = ? AND index_name = ? AND (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?) OR (index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ? OR index_value = ?)
)
"""
.trimIndent(),
)
val paramConditionListsSubstring = queryString.substring(queryString.indexOf("(index_value"))
val extractTextInBracketsRegex = Regex("\\((.*?)\\)")
assertThat(
extractTextInBracketsRegex.findAll(paramConditionListsSubstring).all {
it.value.split("OR").size <= FilterCriteria.CONDITION_PARAMS_CHUNK_SIZE
},
)
.isTrue()

assertThat(query.args)
.containsExactly(
"CarePlan",
"CarePlan",
"subject",
*patientIdReferenceList.toTypedArray(),
)
.inOrder()
}

private companion object {
const val mockEpochTimeStamp = 1628516301000
const val APPROXIMATION_COEFFICIENT = 0.1
Expand Down

0 comments on commit c73037d

Please sign in to comment.