Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to request referenced resources along with the searched via inline params. #1978

Merged
merged 46 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f33cc64
Inital changes to support inline resources via revInclude
aditya-07 Apr 13, 2023
54e4cbc
Merge branch 'master' into ak/revinclude
aditya-07 Apr 18, 2023
b0cd819
Merge branch 'master' into ak/revinclude
aditya-07 Apr 24, 2023
df863ac
Updated test and added doc
aditya-07 Apr 24, 2023
4239de9
Merge branch 'master' into ak/revinclude
aditya-07 Apr 27, 2023
e0f3c0f
RevInclude to return mapped response
aditya-07 Apr 28, 2023
1ccf108
Test code for forward include
aditya-07 May 4, 2023
d14e52a
Merge branch 'master' into ak/revinclude
aditya-07 May 5, 2023
543478c
Fixed include query
aditya-07 May 5, 2023
1818b80
Merge branch 'master' into ak/revinclude
aditya-07 Jun 6, 2023
724fb9d
Merge branch 'master' into ak/revinclude
aditya-07 Jun 28, 2023
379ed16
Unify search api to include include and revInclude functionality
aditya-07 Jun 29, 2023
c6f3682
Merge branch 'master' into ak/revinclude
aditya-07 Jun 29, 2023
75fac23
Workflow library: Incorporated changes related to FhirEngine.search
aditya-07 Jun 29, 2023
8ceb736
Merge branch 'ak/revinclude' of github.com:aditya-07/android-fhir int…
aditya-07 Jun 29, 2023
8756138
Merge branch 'master' into ak/revinclude
aditya-07 Jun 30, 2023
30d48a6
Merge branch 'master' into ak/revinclude
aditya-07 Jul 4, 2023
7acc7bb
Merge branch 'master' into ak/revinclude
aditya-07 Jul 5, 2023
4e50b9e
Merge branch 'master' into ak/revinclude
aditya-07 Jul 11, 2023
ced4b08
Merge branch 'master' into ak/revinclude
aditya-07 Jul 19, 2023
fe10fa0
Review comments: Changed the search result type to include the search…
aditya-07 Jul 20, 2023
5dcb352
Merge branch 'master' into ak/revinclude
aditya-07 Jul 20, 2023
7b55c7e
Updated docs
aditya-07 Jul 20, 2023
3db1d92
Added spotless toggle to skip indentation for specific code portions
aditya-07 Jul 20, 2023
e28c098
Merge branch 'master' into ak/revinclude
aditya-07 Jul 21, 2023
f74707e
Merge branch 'master' into ak/revinclude
aditya-07 Jul 24, 2023
35bf026
Added individual tests for include and revInclude
aditya-07 Jul 25, 2023
48df351
Merge branch 'master' into ak/revinclude
aditya-07 Jul 25, 2023
41d090c
Merge branch 'master' into ak/revinclude
aditya-07 Jul 26, 2023
b79bb28
Merge branch 'master' into ak/revinclude
aditya-07 Jul 26, 2023
a5ef271
Merge branch 'master' into ak/revinclude
aditya-07 Jul 27, 2023
286b58a
Merge branch 'master' into ak/revinclude
aditya-07 Jul 27, 2023
8efbdc2
Review Comments: Updated kdocs and refactored function name
aditya-07 Jul 27, 2023
af7768e
Merge branch 'master' into ak/revinclude
aditya-07 Jul 31, 2023
cfe459f
Review comments: refactored type of revInclude
aditya-07 Aug 1, 2023
31834c6
Fixed failing workflow compilation as workflow doesn't depends on eng…
aditya-07 Aug 1, 2023
9f169f3
Resolved compilation errors
aditya-07 Aug 1, 2023
fd22291
Merge branch 'master' into ak/revinclude
aditya-07 Aug 3, 2023
d5d0fe0
Merge branch 'master' into ak/revinclude
aditya-07 Aug 3, 2023
ed8a645
Merge branch 'master' into ak/revinclude
aditya-07 Aug 4, 2023
1228211
Merge branch 'master' into ak/revinclude
aditya-07 Aug 10, 2023
14ffa49
Merge branch 'master' into ak/revinclude
aditya-07 Aug 11, 2023
1dbe6be
Reverted the engine changes
aditya-07 Aug 11, 2023
530a5e1
Merge branch 'master' into ak/revinclude
aditya-07 Aug 11, 2023
8740ff4
Merge branch 'master' into ak/revinclude
omarismail94 Aug 21, 2023
00b1956
Merge branch 'master' into ak/revinclude
omarismail94 Aug 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Inital changes to support inline resources via revInclude
  • Loading branch information
aditya-07 committed Apr 13, 2023
commit f33cc649a49017e4646c76cbd4299f081fa775c8
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import org.hl7.fhir.r4.model.Condition
import org.hl7.fhir.r4.model.DateTimeType
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.DecimalType
import org.hl7.fhir.r4.model.Encounter
import org.hl7.fhir.r4.model.Enumerations
import org.hl7.fhir.r4.model.Extension
import org.hl7.fhir.r4.model.HumanName
Expand All @@ -65,6 +66,7 @@ import org.hl7.fhir.r4.model.Patient
import org.hl7.fhir.r4.model.Practitioner
import org.hl7.fhir.r4.model.Quantity
import org.hl7.fhir.r4.model.Reference
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
import org.hl7.fhir.r4.model.RiskAssessment
import org.hl7.fhir.r4.model.SearchParameter
Expand Down Expand Up @@ -3075,6 +3077,147 @@ class DatabaseImplTest {
assertThat(result.map { it.nameFirstRep.nameAsSingleString }).contains("Darcy Smith")
}

@Test
fun search_revInclude(): Unit = runBlocking {
val resources =
listOf(
Patient().apply { id = "pa-01" },
Patient().apply { id = "pa-02" },
Patient().apply { id = "pa-04" },
Encounter().apply {
id = "en-01"
subject = Reference("Patient/pa-01")
},
Encounter().apply {
id = "en-02"
subject = Reference("Patient/pa-02")
},
Encounter().apply {
id = "en-03"
subject = Reference("Patient/pa-03")
}
)
database.insertRemote(*resources.toTypedArray())

val result =
database.search<Resource>(
Search(ResourceType.Patient)
.apply { revInclude(ResourceType.Encounter, Encounter.SUBJECT) }
.getQuery()
)
assertThat(result.map { it.logicalId })
.containsExactly("pa-01", "pa-02", "pa-04", "en-01", "en-02", "test_patient_1")
}

@Test
fun search_patient_revInclude(): Unit = runBlocking {
val resources =
listOf(
Patient().apply {
id = "pa-01"
addName(
HumanName().apply {
addGiven("James")
family = "Gorden"
}
)
},
Patient().apply { id = "pa-02" },
Patient().apply { id = "pa-04" },
Encounter().apply {
id = "en-01"
subject = Reference("Patient/pa-01")
},
Encounter().apply {
id = "en-02"
subject = Reference("Patient/pa-02")
},
Encounter().apply {
id = "en-03"
subject = Reference("Patient/pa-01")
}
)
database.insertRemote(*resources.toTypedArray())

val result =
database.search<Resource>(
Search(ResourceType.Patient)
.apply {
filter(Patient.GIVEN, { value = "James" })
revInclude(ResourceType.Encounter, Encounter.SUBJECT)
}
.getQuery()
)
assertThat(result.map { it.logicalId }).containsExactly("pa-01", "en-01", "en-03")
}

@Test
fun search_patient_has_revInclude(): Unit = runBlocking {
val diabetesCodeableConcept =
CodeableConcept(Coding("http:https://snomed.info/sct", "44054006", "Diabetes"))
val hyperTensionCodeableConcept =
CodeableConcept(Coding("http:https://snomed.info/sct", "827069000", "Hypertension stage 1"))
val resources =
listOf(
Patient().apply {
id = "pa-01"
addName(
HumanName().apply {
addGiven("James")
family = "Gorden"
}
)
},
Patient().apply {
id = "pa-02"
addName(
HumanName().apply {
addGiven("James")
family = "Bond"
}
)
},
Patient().apply { id = "pa-04" },
Encounter().apply {
id = "en-01"
subject = Reference("Patient/pa-01")
},
Encounter().apply {
id = "en-02"
subject = Reference("Patient/pa-02")
},
Encounter().apply {
id = "en-03"
subject = Reference("Patient/pa-01")
},
Condition().apply {
id = "con-01"
code = diabetesCodeableConcept
subject = Reference("Patient/pa-01")
},
Condition().apply {
id = "con-02"
code = hyperTensionCodeableConcept
subject = Reference("Patient/pa-02")
}
)
database.insertRemote(*resources.toTypedArray())

val result =
database.search<Resource>(
Search(ResourceType.Patient)
.apply {
filter(Patient.GIVEN, { value = "James" })
has<Condition>(Condition.SUBJECT) {
filter(Condition.CODE, { value = of(diabetesCodeableConcept) })
}
revInclude(ResourceType.Encounter, Encounter.SUBJECT)
}
.getQuery()
)
assertThat(result.map { it.logicalId }).containsExactly("pa-01", "en-01", "en-03")
}

private companion object {
const val mockEpochTimeStamp = 1628516301000
const val TEST_PATIENT_1_ID = "test_patient_1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.google.android.fhir.search

import ca.uhn.fhir.rest.gclient.DateClientParam
import ca.uhn.fhir.rest.gclient.NumberClientParam
import ca.uhn.fhir.rest.gclient.ReferenceClientParam
import ca.uhn.fhir.rest.gclient.StringClientParam
import ca.uhn.fhir.rest.param.ParamPrefixEnum
import com.google.android.fhir.ConverterException
Expand All @@ -34,6 +35,7 @@ import kotlin.math.roundToLong
import org.hl7.fhir.r4.model.DateTimeType
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType

/**
* The multiplier used to determine the range for the `ap` search prefix. See
Expand Down Expand Up @@ -166,6 +168,21 @@ internal fun Search.getQuery(
$limitStatement)
"""
}
revIncludeMap.isNotEmpty() -> {
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
"""
select serializedResource from ResourceEntity where resourceUuid in (
with UUIDS as ( select '${type.name}/' || a.resourceId from ResourceEntity a
$sortJoinStatement
WHERE a.resourceType = ?
$filterStatement
$sortOrderStatement
$limitStatement
)
Select resourceUuid from ResourceEntity where '${type.name}/' || resourceId in UUIDS
${revIncludeMap.toSQLQuery()}
)
""".trimIndent()
}
else ->
"""
SELECT a.serializedResource
Expand Down Expand Up @@ -295,7 +312,8 @@ internal fun getConditionParamPair(
(prefix != ParamPrefixEnum.STARTS_AFTER && prefix != ParamPrefixEnum.ENDS_BEFORE)
) { "Prefix $prefix not allowed for Integer type" }
return when (prefix) {
ParamPrefixEnum.EQUAL, null -> {
ParamPrefixEnum.EQUAL,
null -> {
val precision = value.getRange()
ConditionParam(
"index_value >= ? AND index_value < ?",
Expand Down Expand Up @@ -441,3 +459,12 @@ private fun getApproximateDateRange(
}

private data class ApproximateDateRange(val start: Long, val end: Long)

private fun Map<ResourceType, List<ReferenceClientParam>>.toSQLQuery() =
map { it ->
val indexes = it.value.joinToString { "\'${it.paramName}\'" }
"""
SELECT DISTINCT resourceUuid from ReferenceIndexEntity WHERE resourceType = '${it.key}' AND index_name IN ($indexes) AND index_value IN UUIDS
""".trimIndent()
}
.joinToString(prefix = "\nUNION\n", separator = " \nUNION\n")
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google LLC
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -53,6 +53,7 @@ data class Search(val type: ResourceType, var count: Int? = null, var from: Int?
internal val uriFilterCriteria = mutableListOf<UriFilterCriteria>()
internal var sort: IParam? = null
internal var order: Order? = null
internal val revIncludeMap = mutableMapOf<ResourceType, MutableList<ReferenceClientParam>>()
MJ1998 marked this conversation as resolved.
Show resolved Hide resolved
@PublishedApi internal var nestedSearches = mutableListOf<NestedSearch>()
var operation = Operation.AND

Expand Down Expand Up @@ -142,6 +143,10 @@ data class Search(val type: ResourceType, var count: Int? = null, var from: Int?
sort = parameter
this.order = order
}

fun revInclude(resourceType: ResourceType, vararg clientParam: ReferenceClientParam) {
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
revIncludeMap.computeIfAbsent(resourceType) { mutableListOf() }.addAll(clientParam)
}
}

enum class Order {
Expand Down
Loading