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

Start saving local lastUpdated to resources for search operations. #2030

Merged
merged 17 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
Added tests
  • Loading branch information
aditya-07 committed Jun 29, 2023
commit 682d1c9fadc70fbd7ef3ebc898d7441496ea9d55
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.db.impl.dao.toLocalChange
import com.google.android.fhir.db.impl.entities.LocalChangeEntity
import com.google.android.fhir.logicalId
import com.google.android.fhir.search.LOCAL_LAST_UPDATED_PARAM
import com.google.android.fhir.search.Operation
import com.google.android.fhir.search.Order
import com.google.android.fhir.search.Search
Expand Down Expand Up @@ -3075,6 +3076,33 @@ class DatabaseImplTest {
assertThat(result.map { it.nameFirstRep.nameAsSingleString }).contains("Darcy Smith")
}

@Test
fun search_patient_with_local_lastUpdated() = runBlocking {
database.insert(
Patient().apply { id = "patient-test-001" },
Patient().apply { id = "patient-test-002" },
Patient().apply { id = "patient-test-003" }
)

database.update(
Patient().apply {
id = "patient-test-002"
gender = Enumerations.AdministrativeGender.FEMALE
}
)

val result =
database.search<Patient>(
Search(ResourceType.Patient)
.apply { sort(LOCAL_LAST_UPDATED_PARAM, Order.DESCENDING) }
.getQuery()
)

assertThat(result.map { it.logicalId })
.containsAtLeast("patient-test-002", "patient-test-003", "patient-test-001")
.inOrder()
}

private companion object {
const val mockEpochTimeStamp = 1628516301000
const val TEST_PATIENT_1_ID = "test_patient_1"
Expand Down
9 changes: 9 additions & 0 deletions engine/src/main/java/com/google/android/fhir/db/Database.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package com.google.android.fhir.db

import androidx.annotation.VisibleForTesting
import com.google.android.fhir.db.impl.dao.LocalChangeToken
import com.google.android.fhir.db.impl.dao.SquashedLocalChange
import com.google.android.fhir.db.impl.entities.DateTimeIndexEntity
import com.google.android.fhir.db.impl.entities.LocalChangeEntity
import com.google.android.fhir.db.impl.entities.ResourceEntity
import com.google.android.fhir.search.SearchQuery
Expand Down Expand Up @@ -145,4 +147,11 @@ internal interface Database {
* delete resource entry from LocalChangeEntity table.
*/
suspend fun purge(type: ResourceType, id: String, forcePurge: Boolean = false)

/** @return DateTimeIndexEntities for the resource. */
@VisibleForTesting
suspend fun getDateTimeIndexEntities(
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
resourceId: String,
resourceType: ResourceType
): List<DateTimeIndexEntity>
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,13 @@ internal class DatabaseImpl(
override suspend fun <R : Resource> insert(vararg resource: R): List<String> {
val logicalIds = mutableListOf<String>()
db.withTransaction {
val timeOfLocalChange = Instant.now()
logicalIds.addAll(resourceDao.insertAllLocal(resource.toList(), timeOfLocalChange))
localChangeDao.addInsertAll(resource.toList(), timeOfLocalChange)
logicalIds.addAll(
resource.map {
val timeOfLocalChange = Instant.now()
localChangeDao.addInsert(it, timeOfLocalChange)
resourceDao.insertResourceLocal(it, timeOfLocalChange)
}
)
}
return logicalIds
}
Expand Down Expand Up @@ -293,6 +297,12 @@ internal class DatabaseImpl(
}
}

override suspend fun getDateTimeIndexEntities(resourceId: String, resourceType: ResourceType) =
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
resourceDao.getResourceEntity(resourceId, resourceType)?.let {
resourceDao.getDateTimeIndexes(it.resourceUuid)
}
?: emptyList()

companion object {
/**
* The name for unencrypted database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ internal abstract class LocalChangeDao {
@Insert abstract suspend fun addLocalChange(localChangeEntity: LocalChangeEntity)

@Transaction
open suspend fun addInsertAll(resources: List<Resource>, timeOfChange: Instant) {
resources.forEach { resource -> addInsert(resource, timeOfChange) }
}

suspend fun addInsert(resource: Resource, timeOfChange: Instant?) {
open suspend fun addInsert(resource: Resource, timeOfChange: Instant?) {
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
val resourceId = resource.logicalId
val resourceType = resource.resourceType
val timestamp = Date.from(timeOfChange).toTimeZoneString()
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,6 @@ internal abstract class ResourceDao {
?: throw ResourceNotFoundException(resource.resourceType.name, resource.id)
}

open suspend fun insertAllLocal(
resources: List<Resource>,
timeOfLocalChange: Instant
): List<String> {
return resources.map { resource -> insertResourceLocal(resource, timeOfLocalChange) }
}

open suspend fun insertAllRemote(resources: List<Resource>): List<String> {
return resources.map { resource -> insertResourceRemote(resource) }
}
Expand Down Expand Up @@ -132,6 +125,9 @@ internal abstract class ResourceDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun insertPositionIndex(positionIndexEntity: PositionIndexEntity)

@Query("select * from DateTimeIndexEntity where resourceUuid = :resourceUuid ")
abstract suspend fun getDateTimeIndexes(resourceUuid: UUID): List<DateTimeIndexEntity>

@Query(
"""
UPDATE ResourceEntity
Expand Down Expand Up @@ -179,7 +175,7 @@ internal abstract class ResourceDao {

@RawQuery abstract suspend fun countResources(query: SupportSQLiteQuery): Long

private suspend fun insertResourceLocal(resource: Resource, timeOfChange: Instant) =
suspend fun insertResourceLocal(resource: Resource, timeOfChange: Instant) =
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
insertResource(resource, timeOfChange)

// Since the insert removes any old indexes and lastUpdatedLocal (data not contained in resource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.db.impl.dao.LocalChangeToken
import com.google.android.fhir.get
import com.google.android.fhir.logicalId
import com.google.android.fhir.search.LOCAL_LAST_UPDATED
import com.google.android.fhir.search.search
import com.google.android.fhir.sync.AcceptLocalConflictResolver
import com.google.android.fhir.sync.AcceptRemoteConflictResolver
Expand Down Expand Up @@ -495,6 +496,41 @@ class FhirEngineImplTest {
assertResourceEquals(fhirEngine.get<Patient>("original-002"), localChange)
}

@Test
fun create_should_save_lastUpdated_Indexes(): Unit = runBlocking {
val patient = Patient().apply { id = "patient-id-create" }
fhirEngine.create(patient)
val indexes =
services.database.getDateTimeIndexEntities("patient-id-create", ResourceType.Patient)
assertThat(indexes.map { it.index.name }).contains(LOCAL_LAST_UPDATED)
}

@Test
fun update_should_save_lastUpdated_Indexes() = runBlocking {
val patient = Patient().apply { id = "patient-id-update" }
fhirEngine.create(patient)
val indexesWhenCreated =
services.database.getDateTimeIndexEntities("patient-id-update", ResourceType.Patient)
val patientUpdate =
Patient().apply {
id = "patient-id-update"
addName(
HumanName().apply {
addGiven("John")
family = "Doe"
}
)
}

fhirEngine.update(patientUpdate)
val indexesWhenUpdated =
services.database.getDateTimeIndexEntities("patient-id-update", ResourceType.Patient)

assertThat(indexesWhenUpdated.map { it.index.name }).contains(LOCAL_LAST_UPDATED)
assertThat(indexesWhenUpdated.first { it.index.name == LOCAL_LAST_UPDATED }.index.from)
.isGreaterThan(indexesWhenCreated.first { it.index.name == LOCAL_LAST_UPDATED }.index.from)
}

companion object {
private const val TEST_PATIENT_1_ID = "test_patient_1"
private var TEST_PATIENT_1 =
Expand Down
Loading