From 3f897704510eb9020cf59174b9d62e606a7e717e Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Tue, 9 Nov 2021 14:09:22 +0200 Subject: [PATCH 1/4] Add Database.replaceLocalWithRemote * In order to support peer to peer synchronization local resource are changes are required to be overwritten. Conflict resolution will be handled upstream through an implementation of ConflictResolutionStrategy. --- .../main/java/com/google/android/fhir/db/Database.kt | 8 ++++++++ .../com/google/android/fhir/db/impl/DatabaseImpl.kt | 11 +++++++++++ .../android/fhir/db/impl/dao/LocalChangeDao.kt | 12 ++++++++++++ 3 files changed, 31 insertions(+) diff --git a/engine/src/main/java/com/google/android/fhir/db/Database.kt b/engine/src/main/java/com/google/android/fhir/db/Database.kt index 7635b87cd7..248c739100 100644 --- a/engine/src/main/java/com/google/android/fhir/db/Database.kt +++ b/engine/src/main/java/com/google/android/fhir/db/Database.kt @@ -42,6 +42,14 @@ internal interface Database { */ suspend fun insertRemote(vararg resource: R) + /** + * Replaces the resource and local changes in the FHIR resource database. + * + * @param resource The [Resource] + * @param changes The [List] of [LocalChangeEntity] which have not yet been synced to the server + */ + suspend fun replaceLocalWithRemote(resource: R, changes: List) + /** * Updates the `resource` in the FHIR resource database. If the resource does not already exist, * then it will not be created. diff --git a/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt b/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt index 69a95a47dc..7344cf0834 100644 --- a/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt +++ b/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt @@ -76,6 +76,17 @@ internal class DatabaseImpl(context: Context, private val iParser: IParser, inMe } } + override suspend fun replaceLocalWithRemote( + resource: R, + changes: List + ) { + db.withTransaction { + resourceDao.update(resource) + localChangeDao.discardLocalChangesForResource(resource.logicalId, resource.resourceType) + changes.forEach { localChangeDao.addLocalChange(it) } + } + } + override suspend fun select(clazz: Class, id: String): R { return db.withTransaction { val type = getResourceType(clazz) diff --git a/engine/src/main/java/com/google/android/fhir/db/impl/dao/LocalChangeDao.kt b/engine/src/main/java/com/google/android/fhir/db/impl/dao/LocalChangeDao.kt index 923fd0b1bc..99abee3918 100644 --- a/engine/src/main/java/com/google/android/fhir/db/impl/dao/LocalChangeDao.kt +++ b/engine/src/main/java/com/google/android/fhir/db/impl/dao/LocalChangeDao.kt @@ -155,6 +155,18 @@ internal abstract class LocalChangeDao { ) abstract suspend fun discardLocalChanges(id: Long) + @Query( + """ + DELETE FROM LocalChangeEntity + WHERE LocalChangeEntity.resourceId = :resourceId + AND LocalChangeEntity.type = :resourceType + """ + ) + abstract suspend fun discardLocalChangesForResource( + resourceId: String, + resourceType: ResourceType + ) + suspend fun discardLocalChanges(token: LocalChangeToken) { token.ids.forEach { discardLocalChanges(it) } } From d595f6b422e1041197c89690ad146c158535ccef Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Wed, 10 Nov 2021 13:54:34 +0200 Subject: [PATCH 2/4] Add Database.withTransaction * Support the wrapping of multiple operations at the service level in a transaction. * In the context of peer to peer sync, resources need to be looked up and it determined whether they should be inserted into or updated in the database. In order to continue to follow the pattern of the existing Database functions which perform a single operation, transaction management needs to be exposed to the service level. --- engine/src/main/java/com/google/android/fhir/db/Database.kt | 6 ++++++ .../java/com/google/android/fhir/db/impl/DatabaseImpl.kt | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/engine/src/main/java/com/google/android/fhir/db/Database.kt b/engine/src/main/java/com/google/android/fhir/db/Database.kt index 248c739100..17b058e422 100644 --- a/engine/src/main/java/com/google/android/fhir/db/Database.kt +++ b/engine/src/main/java/com/google/android/fhir/db/Database.kt @@ -16,6 +16,7 @@ package com.google.android.fhir.db +import androidx.room.RoomDatabase 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.LocalChangeEntity @@ -104,4 +105,9 @@ internal interface Database { /** Remove the [LocalChangeEntity] s with given ids. Call this after a successful sync. */ suspend fun deleteUpdates(token: LocalChangeToken) + + /** + * @see RoomDatabase + */ + suspend fun withTransaction(block: suspend () -> R): R } diff --git a/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt b/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt index 7344cf0834..d6d229044e 100644 --- a/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt +++ b/engine/src/main/java/com/google/android/fhir/db/impl/DatabaseImpl.kt @@ -150,6 +150,10 @@ internal class DatabaseImpl(context: Context, private val iParser: IParser, inMe db.withTransaction { localChangeDao.discardLocalChanges(token) } } + override suspend fun withTransaction(block: suspend () -> R): R { + return db.withTransaction(block) + } + companion object { private const val DEFAULT_DATABASE_NAME = "fhirEngine" } From 6602698c74934b49220fbeead3104e750bf037af Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Wed, 10 Nov 2021 14:09:35 +0200 Subject: [PATCH 3/4] Add ConflictResolutionStrategy interface to p2p * Enable conflicts to be resolved using the specified ConflictResolutionStategy implementation. --- .../google/android/fhir/p2p/ConflictResolutionStrategy.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 p2p/src/main/java/com/google/android/fhir/p2p/ConflictResolutionStrategy.kt diff --git a/p2p/src/main/java/com/google/android/fhir/p2p/ConflictResolutionStrategy.kt b/p2p/src/main/java/com/google/android/fhir/p2p/ConflictResolutionStrategy.kt new file mode 100644 index 0000000000..826ea8e25d --- /dev/null +++ b/p2p/src/main/java/com/google/android/fhir/p2p/ConflictResolutionStrategy.kt @@ -0,0 +1,6 @@ +package com.google.android.fhir.p2p + +interface ConflictResolutionStrategy { + + fun resolveConflict(theirs: SyncPayload, ours: SyncPayload): SyncPayload +} From 7b535f3fdae1be240c1c77c92f9767b99f9a1508 Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Wed, 10 Nov 2021 14:21:15 +0200 Subject: [PATCH 4/4] Publicize Database * In order to support peer to peer synchronization a lower level of control is required than was originally intended for FhirEngine. --- engine/src/main/java/com/google/android/fhir/db/Database.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/com/google/android/fhir/db/Database.kt b/engine/src/main/java/com/google/android/fhir/db/Database.kt index 17b058e422..ab8cffada6 100644 --- a/engine/src/main/java/com/google/android/fhir/db/Database.kt +++ b/engine/src/main/java/com/google/android/fhir/db/Database.kt @@ -26,7 +26,7 @@ import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceType /** The interface for the FHIR resource database. */ -internal interface Database { +interface Database { /** * Inserts a list of local `resources` into the FHIR resource database. If any of the resources * already exists, it will be overwritten.