Skip to main content

Persistent Module

Local storage through Room KMP (SQLite database) and DataStore (key-value preferences).

implementation("com.github.wahidabd.miru-sdk:persistent:<version>")

Setup

Initialize in your Application.onCreate() (Android):

MiruPreferencesInitializer.init(applicationContext)
MiruDatabaseInitializer.init(applicationContext)

DataStore Preferences

MiruPreferences wraps DataStore with a convenient API:

val prefs: MiruPreferences = get() // via Koin

// Write
prefs.putString("user_name", "Wahid")
prefs.putBoolean("dark_mode", true)
prefs.putInt("login_count", 5)

// Read (one-shot suspend)
val name = prefs.getString("user_name", "Guest")

// Read (reactive Flow)
prefs.observeBoolean("dark_mode", false).collect { isDark ->
// react to changes
}

// Remove / Clear
prefs.remove("user_name")
prefs.clear()

Supported Types

MethodType
putString / getStringString
putInt / getIntInt
putLong / getLongLong
putFloat / getFloatFloat
putDouble / getDoubleDouble
putBoolean / getBooleanBoolean

Each type also has an observe* variant returning Flow<T>.

Room KMP Database

Define Entities & DAO

// commonMain
@Entity
data class UserEntity(
@PrimaryKey val id: Long,
val name: String,
val email: String
)

@Dao
interface UserDao {
@Query("SELECT * FROM UserEntity")
fun getAll(): Flow<List<UserEntity>>

@Query("SELECT * FROM UserEntity WHERE id = :id")
suspend fun getById(id: Long): UserEntity?

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: UserEntity)

@Delete
suspend fun delete(user: UserEntity)
}

Define Database

@Database(entities = [UserEntity::class], version = 1)
@ConstructedBy(AppDatabaseConstructor::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}

expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase>

Build Per Platform

// Android
val db = Room.databaseBuilder<AppDatabase>(context, databasePath("app.db"))
.miruBuild()

// iOS
val db = Room.databaseBuilder<AppDatabase>(databasePath("app.db"))
.miruBuild()

miruBuild() is an extension that pre-configures BundledSQLiteDriver and Dispatchers.IO.

tip

If you see expect/actual class warnings during compilation, add -Xexpect-actual-classes to your compiler options:

kotlin {
compilerOptions {
freeCompilerArgs.add("-Xexpect-actual-classes")
}
}

Components

ComponentDescription
MiruPreferencesDataStore wrapper with type-safe get/put/observe
MiruDatabaseRoom builder helper with pre-configured driver
databasePath()Platform-specific database file path resolver
persistentModuleKoin module providing MiruPreferences