Skip to content

Commit

Permalink
Clean persistence layer
Browse files Browse the repository at this point in the history
  • Loading branch information
Tetr4 committed Aug 20, 2023
1 parent 824a55a commit bd27084
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class EditViewModel(
id = UUID.randomUUID(),
start = data.start,
diveTime = data.diveTime,
number = diveRepo.getCurrentDiveNumber() + 1,
number = diveRepo.getNextDiveNumber(),
location = null,
maxDepthMeters = null,
minTemperatureCelsius = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ImportViewModel(
try {
transferState.update { TransferState.Transfering(progress = null) }
val dives = connection.fetchDives(
currentDiveNumber = diveRepo.getCurrentDiveNumber(),
initialDiveNumber = diveRepo.getNextDiveNumber(),
isAlreadyImported = { timestamp -> diveRepo.containsDiveAt(timestamp) },
onProgress = { progress -> transferState.update { TransferState.Transfering(progress) } },
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ class DiveRepository(
private val divesDao: DivesDao,
) {

fun getDiveStream(id: UUID): Flow<Dive?> = divesDao.loadDiveStream(id).map { it?.toEntity() }
fun getDiveStream(id: UUID): Flow<Dive?> = divesDao.getDiveStream(id).map { it?.toEntity() }

fun getDivesPages(query: String): Flow<PagingData<Dive>> {
val pager = Pager(
config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
pagingSourceFactory = { divesDao.loadDivesPages(query) },
pagingSourceFactory = { divesDao.getDivesPages(query) },
)
return pager.flow.map { diveDtos -> diveDtos.map { it.toEntity() } }
}

suspend fun deleteDive(dive: Dive) = divesDao.deleteDive(dive.toDto().dive)
suspend fun addDive(dive: Dive) = addDives(listOf(dive))
suspend fun addDives(dives: List<Dive>) = divesDao.insertDives(dives.map { it.toDto() })
suspend fun updateDive(dive: Dive) = divesDao.updateDive(dive.toDto().dive)
suspend fun addDives(dives: List<Dive>) = divesDao.upsertDives(dives.map(Dive::toDto))
suspend fun updateDive(dive: Dive) = divesDao.upsertDive(dive.toDto())
suspend fun deleteDive(dive: Dive) = divesDao.deleteDive(dive.toDto().dive)

suspend fun getCurrentDiveNumber(): Int = divesDao.loadMaxDiveNumber() ?: 0
suspend fun getNextDiveNumber(): Int = (divesDao.getMaxDiveNumber() ?: 0) + 1
suspend fun containsDiveAt(timestamp: LocalDateTime): Boolean = divesDao.diveExists(timestamp)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.time.LocalDateTime

interface ImportConnection {
suspend fun fetchDives(
currentDiveNumber: Int,
initialDiveNumber: Int,
isAlreadyImported: suspend (LocalDateTime) -> Boolean,
onProgress: suspend (Float) -> Unit,
): List<Dive>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ internal class OstcConnection(
* 4. [exitCommunication]
*/
override suspend fun fetchDives(
currentDiveNumber: Int,
initialDiveNumber: Int,
isAlreadyImported: suspend (LocalDateTime) -> Boolean,
onProgress: suspend (Float) -> Unit,
): List<Dive> {
Expand All @@ -61,7 +61,7 @@ internal class OstcConnection(
fetchDiveProfile(header)
}
val dives = profiles.mapIndexed { index, profile ->
profile.toDive(currentDiveNumber + index + 1)
profile.toDive(initialDiveNumber + index)
}
exitCommunication()
return dives
Expand Down
10 changes: 8 additions & 2 deletions persistence/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ android {
kotlin {
jvmToolchain(17)
}

@Suppress("UnstableApiUsage")
testOptions {
unitTests {
// Required by Robolectric (https://robolectric.org/getting-started/)
isIncludeAndroidResources = true
}
}
}

dependencies {
Expand All @@ -32,8 +40,6 @@ dependencies {
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
ksp("androidx.room:room-compiler:$roomVersion")

// Paging
implementation("androidx.room:room-paging:$roomVersion")

// Testing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ package cloud.mike.divelog.persistence.dives
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
import java.time.LocalDateTime
import java.util.UUID

@Dao
interface DivesDao {

@Transaction
@Query("SELECT * FROM dives WHERE id=:id")
fun getDiveStream(id: UUID): Flow<DiveWithLocationAndProfile?>

@Transaction
@Query(
"""
Expand All @@ -27,37 +29,33 @@ interface DivesDao {
ORDER BY start DESC
""",
)
fun loadDivesPages(query: String): PagingSource<Int, DiveWithLocationAndProfile>
fun getDivesPages(query: String): PagingSource<Int, DiveWithLocationAndProfile>

@Transaction
@Query("SELECT * FROM dives WHERE id=:id")
fun loadDiveStream(id: UUID): Flow<DiveWithLocationAndProfile?>
@Query("SELECT EXISTS(SELECT * FROM dives WHERE start = :timestamp)")
suspend fun diveExists(timestamp: LocalDateTime): Boolean

@Update
suspend fun updateDive(dive: DiveDto)
@Query("SELECT MAX(number) FROM dives")
suspend fun getMaxDiveNumber(): Int?

@Delete
suspend fun deleteDive(id: DiveDto)

@Query("SELECT MAX(number) FROM dives")
suspend fun loadMaxDiveNumber(): Int?
suspend fun deleteDive(dive: DiveDto)

@Query("SELECT EXISTS(SELECT * FROM dives WHERE start = :timestamp)")
suspend fun diveExists(timestamp: LocalDateTime): Boolean
@Upsert
suspend fun upsertDiveHeader(dive: DiveDto)

@Insert
suspend fun insertDive(dive: DiveDto)
@Upsert
suspend fun upsertProfile(profile: DepthProfileDto)

@Insert
suspend fun insertProfile(profile: DepthProfileDto)
@Upsert
suspend fun upsertLocation(location: DiveSpotDto)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLocation(location: DiveSpotDto)
@Transaction
suspend fun upsertDives(dives: List<DiveWithLocationAndProfile>) = dives.forEach { upsertDive(it) }

@Transaction
suspend fun insertDives(dives: List<DiveWithLocationAndProfile>) = dives.forEach {
if (it.location != null) insertLocation(it.location)
insertDive(it.dive)
if (it.depthProfile != null) insertProfile(it.depthProfile)
suspend fun upsertDive(data: DiveWithLocationAndProfile) {
if (data.location != null) upsertLocation(data.location)
upsertDiveHeader(data.dive)
if (data.depthProfile != null) upsertProfile(data.depthProfile)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,32 @@ class DivesDaoTest {
fun `write and read dive`() = runTest {
// given
val dao = database.divesDao()
val dive = DiveDto(
id = UUID.randomUUID(),
number = 1,
locationId = null,
start = LocalDateTime.now(),
diveTime = 30.minutes,
maxDepthMeters = null,
minTemperatureCelsius = null,
notes = null,
val locationId = UUID.randomUUID()
val expected = DiveWithLocationAndProfile(
dive = DiveDto(
id = UUID.randomUUID(),
number = 1,
locationId = locationId,
start = LocalDateTime.now(),
diveTime = 30.minutes,
maxDepthMeters = null,
minTemperatureCelsius = null,
notes = null,
),
location = DiveSpotDto(
id = locationId,
name = "Test",
latitude = 24.262363202339,
longitude = 35.51645954667073,
),
depthProfile = null,
)

// when
dao.insertDive(dive)
val diveWithLocationAndProfile = dao.loadDiveStream(dive.id).first()
dao.upsertDive(expected)
val actual = dao.getDiveStream(expected.dive.id).first()

// then
assertEquals(dive, diveWithLocationAndProfile?.dive)
assertEquals(expected, actual)
}
}

0 comments on commit bd27084

Please sign in to comment.