Skip to content

Commit

Permalink
add activity suggestions database
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Dec 30, 2024
1 parent b301eac commit f9bc72b
Show file tree
Hide file tree
Showing 21 changed files with 287 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.util.simpletimetracker.data_local.activitySuggestion

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "activitySuggestion")
data class ActivitySuggestionDBO(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long,

@ColumnInfo(name = "forTypeId")
val forTypeId: Long,

// Longs stored in string comma separated
@ColumnInfo(name = "suggestionIds")
val suggestionIds: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.util.simpletimetracker.data_local.activitySuggestion

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction

@Dao
interface ActivitySuggestionDao {

@Transaction
@Query("SELECT * FROM activitySuggestion")
suspend fun getAll(): List<ActivitySuggestionDBO>

@Transaction
@Query("SELECT * FROM activitySuggestion WHERE id = :id LIMIT 1")
suspend fun get(id: Long): ActivitySuggestionDBO?

@Transaction
@Query("SELECT * FROM activitySuggestion WHERE :typeId in (forTypeId)")
suspend fun getByTypeId(typeId: Long): List<ActivitySuggestionDBO>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(activityFilters: List<ActivitySuggestionDBO>)

@Query("DELETE FROM activitySuggestion WHERE id = :id")
suspend fun delete(id: Long)

@Query("DELETE FROM activitySuggestion")
suspend fun clear()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.util.simpletimetracker.data_local.activitySuggestion

import com.example.util.simpletimetracker.domain.activitySuggestion.model.ActivitySuggestion
import javax.inject.Inject

class ActivitySuggestionDataLocalMapper @Inject constructor() {

fun map(dbo: ActivitySuggestionDBO): ActivitySuggestion {
return ActivitySuggestion(
id = dbo.id,
forTypeId = dbo.forTypeId,
suggestionIds = dbo.suggestionIds.split(',').mapNotNull(String::toLongOrNull),
)
}

fun map(domain: ActivitySuggestion): ActivitySuggestionDBO {
return ActivitySuggestionDBO(
id = domain.id,
forTypeId = domain.forTypeId,
suggestionIds = domain.suggestionIds.joinToString(separator = ","),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.example.util.simpletimetracker.data_local.activitySuggestion

import com.example.util.simpletimetracker.data_local.base.removeIf
import com.example.util.simpletimetracker.data_local.base.withLockedCache
import com.example.util.simpletimetracker.domain.activitySuggestion.model.ActivitySuggestion
import com.example.util.simpletimetracker.domain.activitySuggestion.repo.ActivitySuggestionRepo
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ActivitySuggestionRepoImpl @Inject constructor(
private val dao: ActivitySuggestionDao,
private val mapper: ActivitySuggestionDataLocalMapper,
) : ActivitySuggestionRepo {

private var cache: List<ActivitySuggestion>? = null
private val mutex: Mutex = Mutex()

override suspend fun getAll(): List<ActivitySuggestion> = mutex.withLockedCache(
logMessage = "getAll",
accessCache = { cache },
accessSource = { dao.getAll().map(mapper::map) },
afterSourceAccess = { cache = it },
)

override suspend fun get(id: Long): ActivitySuggestion? = mutex.withLockedCache(
logMessage = "get",
accessCache = { cache?.firstOrNull { it.id == id } },
accessSource = { dao.get(id)?.let(mapper::map) },
)

override suspend fun getByTypeId(typeId: Long): List<ActivitySuggestion> = mutex.withLockedCache(
logMessage = "getByTypeId",
accessCache = { cache?.filter { it.forTypeId == typeId } },
accessSource = { dao.getByTypeId(typeId).map(mapper::map) },
)

override suspend fun add(activityFilters: List<ActivitySuggestion>) = mutex.withLockedCache(
logMessage = "add",
accessSource = { dao.insert(activityFilters.map(mapper::map)) },
afterSourceAccess = { cache = null },
)

override suspend fun remove(id: Long) = mutex.withLockedCache(
logMessage = "remove",
accessSource = { dao.delete(id) },
afterSourceAccess = { cache = cache?.removeIf { it.id == id } },
)

override suspend fun clear() = mutex.withLockedCache(
logMessage = "clear",
accessSource = { dao.clear() },
afterSourceAccess = { cache = null },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import com.example.util.simpletimetracker.domain.recordTag.model.RecordTypeToTag
import com.example.util.simpletimetracker.domain.backup.model.getExistingValues
import com.example.util.simpletimetracker.domain.backup.model.getNotExistingValues
import com.example.util.simpletimetracker.domain.activityFilter.repo.ActivityFilterRepo
import com.example.util.simpletimetracker.domain.activitySuggestion.model.ActivitySuggestion
import com.example.util.simpletimetracker.domain.activitySuggestion.repo.ActivitySuggestionRepo
import com.example.util.simpletimetracker.domain.category.repo.CategoryRepo
import com.example.util.simpletimetracker.domain.complexRule.repo.ComplexRuleRepo
import com.example.util.simpletimetracker.domain.favourite.repo.FavouriteColorRepo
Expand Down Expand Up @@ -54,6 +56,7 @@ class BackupPartialRepoImpl @Inject constructor(
private val recordToRecordTagRepo: RecordToRecordTagRepo,
private val recordTagRepo: RecordTagRepo,
private val activityFilterRepo: ActivityFilterRepo,
private val activitySuggestionRepo: ActivitySuggestionRepo,
private val favouriteCommentRepo: FavouriteCommentRepo,
private val favouriteColorRepo: FavouriteColorRepo,
private val favouriteIconRepo: FavouriteIconRepo,
Expand Down Expand Up @@ -242,6 +245,8 @@ class BackupPartialRepoImpl @Inject constructor(
val goalsCurrent: List<RecordTypeGoal> = recordTypeGoalRepo.getAllTypeGoals()
val rules: MutableList<ComplexRule> = mutableListOf()
val rulesCurrent: List<ComplexRule> = complexRuleRepo.getAll()
val activitySuggestions: MutableList<ActivitySuggestion> = mutableListOf()
val activitySuggestionsCurrent: List<ActivitySuggestion> = activitySuggestionRepo.getAll()
val settings: MutableList<List<String>> = mutableListOf()

val result = backupRepo.readBackup(
Expand Down Expand Up @@ -270,6 +275,7 @@ class BackupPartialRepoImpl @Inject constructor(
favouriteIcon = favouriteIcon::add,
goals = goals::add,
rules = rules::add,
activitySuggestion = activitySuggestions::addAll,
settings = settings::add,
),
)
Expand Down Expand Up @@ -411,6 +417,20 @@ class BackupPartialRepoImpl @Inject constructor(
mapToHolder(it, rulesCurrent)
}.list

val newActivitySuggestions = activitySuggestions.mapNotNull { item ->
val newForTypeId = originalTypeIdToExistingId[item.forTypeId]
?: return@mapNotNull null
val newSuggestionIds = item.suggestionIds.mapNotNull {
originalTypeIdToExistingId[it]
}
item.copy(
forTypeId = newForTypeId,
suggestionIds = newSuggestionIds,
)
}.let {
mapToHolder(it, activitySuggestionsCurrent)
}.list

// Fill tags after all data processed, with actual tagIds.
val newRecordToTagMap = newRecordToTag.groupBy {
it.data.recordId
Expand All @@ -436,6 +456,7 @@ class BackupPartialRepoImpl @Inject constructor(
favouriteIcon = newFavouriteIcon.associateBy { it.data.id },
goals = newGoals.associateBy { it.data.id },
rules = newRules.associateBy { it.data.id },
activitySuggestions = newActivitySuggestions.associateBy { it.data.id },
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import com.example.util.simpletimetracker.domain.recordType.model.RecordTypeGoal
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTypeToDefaultTag
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTypeToTag
import com.example.util.simpletimetracker.domain.activityFilter.repo.ActivityFilterRepo
import com.example.util.simpletimetracker.domain.activitySuggestion.model.ActivitySuggestion
import com.example.util.simpletimetracker.domain.activitySuggestion.repo.ActivitySuggestionRepo
import com.example.util.simpletimetracker.domain.category.repo.CategoryRepo
import com.example.util.simpletimetracker.domain.complexRule.repo.ComplexRuleRepo
import com.example.util.simpletimetracker.domain.favourite.repo.FavouriteColorRepo
Expand Down Expand Up @@ -71,6 +73,7 @@ class BackupRepoImpl @Inject constructor(
private val recordToRecordTagRepo: RecordToRecordTagRepo,
private val recordTagRepo: RecordTagRepo,
private val activityFilterRepo: ActivityFilterRepo,
private val activitySuggestionRepo: ActivitySuggestionRepo,
private val favouriteCommentRepo: FavouriteCommentRepo,
private val favouriteColorRepo: FavouriteColorRepo,
private val favouriteIconRepo: FavouriteIconRepo,
Expand Down Expand Up @@ -152,6 +155,9 @@ class BackupRepoImpl @Inject constructor(
complexRuleRepo.getAll().forEach {
fileOutputStream?.write(it.let(::toBackupString).toByteArray())
}
activitySuggestionRepo.getAll().forEach {
fileOutputStream?.write(it.let(::toBackupString).toByteArray())
}
backupPrefsRepo.saveToBackupString().let {
fileOutputStream?.write(it.toByteArray())
}
Expand Down Expand Up @@ -210,6 +216,7 @@ class BackupRepoImpl @Inject constructor(
favouriteIcon = favouriteIconRepo::add,
goals = recordTypeGoalRepo::add,
rules = complexRuleRepo::add,
activitySuggestion = activitySuggestionRepo::add,
settings = { if (restoreSettings) backupPrefsRepo.restoreFromBackupString(it) },
),
)
Expand Down Expand Up @@ -344,6 +351,12 @@ class BackupRepoImpl @Inject constructor(
}
}

ROW_ACTIVITY_SUGGESTION -> {
activitySuggestionFromBackupString(parts).let {
dataHandler.activitySuggestion.invoke(listOf(it))
}
}

BackupPrefsRepo.PREFS_KEY -> {
dataHandler.settings.invoke(parts)
}
Expand Down Expand Up @@ -546,6 +559,15 @@ class BackupRepoImpl @Inject constructor(
)
}

private fun toBackupString(activitySuggestion: ActivitySuggestion): String {
return String.format(
"$ROW_ACTIVITY_SUGGESTION\t%s\t%s\t%s\n",
activitySuggestion.id.toString(),
activitySuggestion.forTypeId.toString(),
activitySuggestion.suggestionIds.joinToString(separator = ","),
)
}

private fun recordTypeFromBackupString(parts: List<String>): Pair<RecordType, List<RecordTypeGoal>> {
val typeId = parts.getOrNull(1)?.toLongOrNull().orZero()

Expand Down Expand Up @@ -798,6 +820,15 @@ class BackupRepoImpl @Inject constructor(
)
}

private fun activitySuggestionFromBackupString(parts: List<String>): ActivitySuggestion {
return ActivitySuggestion(
id = parts.getOrNull(1)?.toLongOrNull().orZero(),
forTypeId = parts.getOrNull(2)?.toLongOrNull().orZero(),
suggestionIds = parts.getOrNull(3)?.split(",")
?.mapNotNull { it.toLongOrNull() }.orEmpty(),
)
}

fun migrateTags(
types: List<RecordType>,
data: List<Pair<RecordTag, Long>>,
Expand Down Expand Up @@ -845,6 +876,7 @@ class BackupRepoImpl @Inject constructor(
val favouriteIcon: suspend (FavouriteIcon) -> Unit,
val goals: suspend (RecordTypeGoal) -> Unit,
val rules: suspend (ComplexRule) -> Unit,
val activitySuggestion: suspend (List<ActivitySuggestion>) -> Unit,
val settings: suspend (List<String>) -> Unit,
)

Expand All @@ -859,6 +891,7 @@ class BackupRepoImpl @Inject constructor(
private const val ROW_TYPE_TO_RECORD_TAG = "typeToRecordTag"
private const val ROW_TYPE_TO_DEFAULT_TAG = "typeToDefaultTag"
private const val ROW_ACTIVITY_FILTER = "activityFilter"
private const val ROW_ACTIVITY_SUGGESTION = "activitySuggestion"
private const val ROW_FAVOURITE_COMMENT = "favouriteComment"
private const val ROW_FAVOURITE_COLOR = "favouriteColor"
private const val ROW_FAVOURITE_ICON = "favouriteIcon"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.util.simpletimetracker.data_local.activityFilter.ActivityFilterDao
import com.example.util.simpletimetracker.data_local.activityFilter.ActivityFilterDBO
import com.example.util.simpletimetracker.data_local.activitySuggestion.ActivitySuggestionDBO
import com.example.util.simpletimetracker.data_local.activitySuggestion.ActivitySuggestionDao
import com.example.util.simpletimetracker.data_local.category.CategoryDao
import com.example.util.simpletimetracker.data_local.category.CategoryDBO
import com.example.util.simpletimetracker.data_local.category.RecordTypeCategoryDao
Expand Down Expand Up @@ -53,8 +55,9 @@ import com.example.util.simpletimetracker.data_local.recordType.RecordTypeGoalDa
FavouriteIconDBO::class,
ComplexRuleDBO::class,
FavouriteColorDBO::class,
ActivitySuggestionDBO::class,
],
version = 24,
version = 25,
exportSchema = true,
)
abstract class AppDatabase : RoomDatabase() {
Expand All @@ -81,6 +84,8 @@ abstract class AppDatabase : RoomDatabase() {

abstract fun activityFilterDao(): ActivityFilterDao

abstract fun activitySuggestionDao(): ActivitySuggestionDao

abstract fun favouriteCommentDao(): FavouriteCommentDao

abstract fun recordTypeGoalDao(): RecordTypeGoalDao
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AppDatabaseMigrations {
migration_21_22,
migration_22_23,
migration_23_24,
migration_24_25,
)

private val migration_1_2 = object : Migration(1, 2) {
Expand Down Expand Up @@ -307,5 +308,13 @@ class AppDatabaseMigrations {
)
}
}

private val migration_24_25 = object : Migration(24, 25) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"CREATE TABLE IF NOT EXISTS `activitySuggestion` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `forTypeId` INTEGER NOT NULL, `suggestionIds` TEXT NOT NULL)"
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.SharedPreferences
import androidx.room.Room
import com.example.util.simpletimetracker.core.extension.allowDiskWrite
import com.example.util.simpletimetracker.data_local.activityFilter.ActivityFilterDao
import com.example.util.simpletimetracker.data_local.activitySuggestion.ActivitySuggestionDao
import com.example.util.simpletimetracker.data_local.database.AppDatabase
import com.example.util.simpletimetracker.data_local.database.AppDatabaseMigrations
import com.example.util.simpletimetracker.data_local.category.CategoryDao
Expand Down Expand Up @@ -125,6 +126,12 @@ class DataLocalModule {
return database.activityFilterDao()
}

@Provides
@Singleton
fun getActivitySuggestionDao(database: AppDatabase): ActivitySuggestionDao {
return database.activitySuggestionDao()
}

@Provides
@Singleton
fun getFavouriteCommentDao(database: AppDatabase): FavouriteCommentDao {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.util.simpletimetracker.data_local.di

import com.example.util.simpletimetracker.data_local.activityFilter.ActivityFilterRepoImpl
import com.example.util.simpletimetracker.data_local.activitySuggestion.ActivitySuggestionRepoImpl
import com.example.util.simpletimetracker.data_local.category.CategoryRepoImpl
import com.example.util.simpletimetracker.data_local.category.RecordTypeCategoryRepoImpl
import com.example.util.simpletimetracker.data_local.complexRule.ComplexRuleRepoImpl
Expand All @@ -23,6 +24,7 @@ import com.example.util.simpletimetracker.data_local.file.CsvRepoImpl
import com.example.util.simpletimetracker.data_local.file.IcsRepoImpl
import com.example.util.simpletimetracker.data_local.sharing.SharingRepoImpl
import com.example.util.simpletimetracker.domain.activityFilter.repo.ActivityFilterRepo
import com.example.util.simpletimetracker.domain.activitySuggestion.repo.ActivitySuggestionRepo
import com.example.util.simpletimetracker.domain.category.repo.CategoryRepo
import com.example.util.simpletimetracker.domain.complexRule.repo.ComplexRuleRepo
import com.example.util.simpletimetracker.domain.favourite.repo.FavouriteColorRepo
Expand Down Expand Up @@ -122,6 +124,10 @@ interface DataLocalModuleBinds {
@Singleton
fun bindActivityFilterRepo(impl: ActivityFilterRepoImpl): ActivityFilterRepo

@Binds
@Singleton
fun bindActivitySuggestionRepo(impl: ActivitySuggestionRepoImpl): ActivitySuggestionRepo

@Binds
@Singleton
fun bindFavouriteCommentRepo(impl: FavouriteCommentRepoImpl): FavouriteCommentRepo
Expand Down
Loading

0 comments on commit f9bc72b

Please sign in to comment.