LocalDataSource

interface LocalDataSource

Local data source for managing offline-first data persistence using Room database.

This interface defines the contract for local database operations, enabling:

  • Offline-first architecture: Data is always available locally

  • Sync management: Tracks which entities need synchronization with remote

  • Soft deletes: Marks items as deleted instead of removing immediately

  • Reactive queries: Returns Flow for real-time UI updates

Design Pattern

This follows the Repository Pattern with Local Data Source:

  • Abstracts Room DAO implementation details

  • Provides domain-agnostic data access

  • Handles sync metadata automatically

  • Executes queries on IO dispatcher (handled by Room)

Sync Strategy

The data source tracks sync state using:

  • lastUpdated: When the entity was last modified locally

  • lastSynced: When the entity was last synced with remote

  • needsSync: Flag indicating sync is required

  • syncAction: Action to perform during sync (UPSERT, DELETE, NONE)

Usage in Repositories

class JetpackRepository @Inject constructor(
private val localDataSource: LocalDataSource,
private val networkDataSource: NetworkDataSource
) {
// Reactive query for UI
fun observeJetpacks(userId: String): Flow<List<Jetpack>> =
localDataSource.getJetpacks(userId)
.map { entities -> entities.map { it.toDomain() } }

// Sync local changes to remote
suspend fun syncLocalChanges(userId: String): Result<Unit> = suspendRunCatching {
val unsyncedItems = localDataSource.getUnsyncedJetpacks(userId)
unsyncedItems.forEach { entity ->
when (entity.syncAction) {
SyncAction.UPSERT -> networkDataSource.upsert(entity.toNetwork())
SyncAction.DELETE -> networkDataSource.delete(entity.id)
SyncAction.NONE -> {}
}
localDataSource.markAsSynced(entity.id)
}
}

// Sync remote changes to local
suspend fun syncRemoteChanges(userId: String): Result<Unit> = suspendRunCatching {
val lastUpdate = localDataSource.getLatestUpdateTimestamp(userId)
val remoteChanges = networkDataSource.getChanges(since = lastUpdate)
localDataSource.upsertJetpacks(remoteChanges.map { it.toEntity() })
}
}

See also

Functions

Link copied to clipboard
abstract suspend fun deleteJetpackPermanently(id: String)

Permanently deletes a jetpack from the database.

Link copied to clipboard
abstract fun getJetpack(id: String): Flow<JetpackEntity>

Retrieves a specific jetpack by its ID.

Link copied to clipboard
abstract fun getJetpacks(userId: String): Flow<List<JetpackEntity>>

Retrieves a list of jetpacks for a specific user.

Link copied to clipboard
abstract suspend fun getLatestUpdateTimestamp(userId: String): Long

Gets the most recent lastUpdated timestamp for a specific user's jetpacks.

Link copied to clipboard
abstract suspend fun getUnsyncedJetpacks(userId: String): List<JetpackEntity>

Retrieves a list of jetpacks for a specific user that need to be synced.

Link copied to clipboard
abstract suspend fun insertJetpack(jetpackEntity: JetpackEntity)

Inserts a new jetpack into the database.

Link copied to clipboard
abstract suspend fun markAsSynced(id: String, timestamp: Long = System.currentTimeMillis())

Marks a jetpack as synced.

Link copied to clipboard
abstract suspend fun markJetpackAsDeleted(id: String)

Marks a jetpack as deleted.

Link copied to clipboard
abstract suspend fun updateJetpack(jetpackEntity: JetpackEntity)

Updates an existing jetpack in the database.

Link copied to clipboard
abstract suspend fun upsertJetpack(jetpackEntity: JetpackEntity)

Inserts or updates a jetpack in the database.

Link copied to clipboard
abstract suspend fun upsertJetpacks(remoteJetpacks: List<JetpackEntity>)

Upserts (insert or update) jetpacks from a remote source.