Skip to content

Commit

Permalink
Only allow FHIREngine CRUD api for withTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
LZRS committed May 26, 2024
1 parent 5f2e163 commit 72be126
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 70 deletions.
136 changes: 69 additions & 67 deletions engine/src/main/java/com/google/android/fhir/FhirEngine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,64 +58,7 @@ import org.hl7.fhir.r4.model.ResourceType
* val fhirEngine = FhirEngineProvider.getInstance(this)
* ```
*/
interface FhirEngine {
/**
* Creates one or more FHIR [Resource]s in the local storage. FHIR Engine requires all stored
* resources to have a logical [Resource.id]. If the `id` is specified in the resource passed to
* [create], the resource created in `FhirEngine` will have the same `id`. If no `id` is
* specified, `FhirEngine` will generate a UUID as that resource's `id` and include it in the
* returned list of IDs.
*
* @param resource The FHIR resources to create.
* @return A list of logical IDs of the newly created resources.
*/
suspend fun create(vararg resource: Resource): List<String>

/**
* Loads a FHIR resource given its [ResourceType] and logical ID.
*
* @param type The type of the resource to load.
* @param id The logical ID of the resource.
* @return The requested FHIR resource.
* @throws ResourceNotFoundException if the resource is not found.
*/
@Throws(ResourceNotFoundException::class)
suspend fun get(type: ResourceType, id: String): Resource

/**
* Updates one or more FHIR [Resource]s in the local storage.
*
* @param resource The FHIR resources to update.
*/
suspend fun update(vararg resource: Resource)

/**
* Removes a FHIR resource given its [ResourceType] and logical ID.
*
* @param type The type of the resource to delete.
* @param id The logical ID of the resource.
*/
suspend fun delete(type: ResourceType, id: String)

/**
* Searches the database and returns a list of resources matching the [Search] specifications.
*
* Example:
* ```
* fhirEngine.search<Patient> {
* filter(Patient.GIVEN, {
* value = "Kiran"
* modifier = StringFilterModifier.MATCHES_EXACTLY
* })
* }
* ```
*
* @param search The search criteria to apply.
* @return A list of [SearchResult] objects containing the matching resources and any included
* references.
*/
suspend fun <R : Resource> search(search: Search): List<SearchResult<R>>

interface FhirEngine : BaseFHIREngine {
/**
* Synchronizes upload results with the database.
*
Expand Down Expand Up @@ -151,14 +94,6 @@ interface FhirEngine {
download: suspend () -> Flow<List<Resource>>,
)

/**
* Returns the total count of entities available for the given [Search].
*
* @param search The search criteria to apply.
* @return The total number of matching resources.
*/
suspend fun count(search: Search): Long

/**
* Returns the timestamp when data was last synchronized, or `null` if no synchronization has
* occurred yet.
Expand Down Expand Up @@ -212,12 +147,79 @@ interface FhirEngine {
* back and no record is purged.
*/
suspend fun purge(type: ResourceType, ids: Set<String>, forcePurge: Boolean = false)
}

interface BaseFHIREngine {
/**
* Creates one or more FHIR [Resource]s in the local storage. FHIR Engine requires all stored
* resources to have a logical [Resource.id]. If the `id` is specified in the resource passed to
* [create], the resource created in `FhirEngine` will have the same `id`. If no `id` is
* specified, `FhirEngine` will generate a UUID as that resource's `id` and include it in the
* returned list of IDs.
*
* @param resource The FHIR resources to create.
* @return A list of logical IDs of the newly created resources.
*/
suspend fun create(vararg resource: Resource): List<String>

/**
* Loads a FHIR resource given its [ResourceType] and logical ID.
*
* @param type The type of the resource to load.
* @param id The logical ID of the resource.
* @return The requested FHIR resource.
* @throws ResourceNotFoundException if the resource is not found.
*/
@Throws(ResourceNotFoundException::class)
suspend fun get(type: ResourceType, id: String): Resource

/**
* Updates one or more FHIR [Resource]s in the local storage.
*
* @param resource The FHIR resources to update.
*/
suspend fun update(vararg resource: Resource)

/**
* Removes a FHIR resource given its [ResourceType] and logical ID.
*
* @param type The type of the resource to delete.
* @param id The logical ID of the resource.
*/
suspend fun delete(type: ResourceType, id: String)

/**
* Searches the database and returns a list of resources matching the [Search] specifications.
*
* Example:
* ```
* fhirEngine.search<Patient> {
* filter(Patient.GIVEN, {
* value = "Kiran"
* modifier = StringFilterModifier.MATCHES_EXACTLY
* })
* }
* ```
*
* @param search The search criteria to apply.
* @return A list of [SearchResult] objects containing the matching resources and any included
* references.
*/
suspend fun <R : Resource> search(search: Search): List<SearchResult<R>>

/**
* Returns the total count of entities available for the given [Search].
*
* @param search The search criteria to apply.
* @return The total number of matching resources.
*/
suspend fun count(search: Search): Long

/**
* Adds support for performing actions on `FhirEngine` as a single atomic transaction where the
* entire set of changes succeed or fail as a single entity
*/
suspend fun withTransaction(block: suspend FhirEngine.() -> Unit)
suspend fun withTransaction(block: suspend BaseFHIREngine.() -> Unit)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.android.fhir.impl

import android.content.Context
import com.google.android.fhir.BaseFHIREngine
import com.google.android.fhir.FhirEngine
import com.google.android.fhir.FhirEngineProvider
import com.google.android.fhir.LocalChange
Expand Down Expand Up @@ -106,7 +107,7 @@ internal class FhirEngineImpl(private val database: Database, private val contex
}
}

override suspend fun withTransaction(block: suspend FhirEngine.() -> Unit) {
override suspend fun withTransaction(block: suspend BaseFHIREngine.() -> Unit) {
database.withTransaction { block.invoke(this@FhirEngineImpl) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.work.Data
import ca.uhn.fhir.context.FhirContext
import ca.uhn.fhir.context.FhirVersionEnum
import ca.uhn.fhir.parser.IParser
import com.google.android.fhir.BaseFHIREngine
import com.google.android.fhir.FhirEngine
import com.google.android.fhir.LocalChange
import com.google.android.fhir.LocalChangeToken
Expand Down Expand Up @@ -176,7 +177,7 @@ object TestFhirEngineImpl : FhirEngine {
download().collect()
}

override suspend fun withTransaction(block: suspend FhirEngine.() -> Unit) {}
override suspend fun withTransaction(block: suspend BaseFHIREngine.() -> Unit) {}

override suspend fun count(search: Search): Long {
return 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,8 @@ class FhirEngineImplTest {
this.create(patient01)
this.create(patient02)
this.update(patient03Updated)
this.get<Patient>("non_existent_patient_id") // Force ResourceNotFoundException
this.get(ResourceType.Patient, "non_existent_patient_id")
as Patient // Force ResourceNotFoundException
}
} catch (_: ResourceNotFoundException) {}

Expand Down

0 comments on commit 72be126

Please sign in to comment.