LocalDb in KMM (SQLDelight) Part-4

LocalDb in KMM (SQLDelight) Part-4

Anuj Sachan's photo
Anuj Sachan
·Aug 20, 2021·

4 min read

Subscribe to my newsletter and never miss my upcoming articles

In this blog, I will share how we did cache in KMM Kotlin and how we replaced it, (SQLDelight->Rooms). So if you followed my part 1, part 2, and part 3 till now I have described how to merge your existing iOS and Android project and move DTO to the KMM folder and implement networking using KTOR Client.

If you have landed here directly and haven’t read the previous parts, here are the links to it.

IS KMM production-ready? How we migrated our code to Kotlin Multiplatform Mobile! Part 1
I will discuss my thoughts about KMM as we have worked with the production-ready app in
mounty.co!medium.com

Move android code to KMM Shared Module| How we migrated our code to Kotlin Multiplatform Mobile!
Earlier, I wrote a blog about merging the existing iOS and Android App with KMM and share the code between iOS and…
medium.com

Networking in KMM (KTOR) Part-3
In this blog, I will share how we did the networking part in the KMM Platform and how we replaced (Retrofit to Ktor)…
medium.com

Let’s start with SQLDelight on the KMM project. SQLDelight is used for LocalDB, it manages data in SQLite, it is an alternative to Rooms Library, One thing to keep a note of is that SQLDelight saves data in the form of structured data. if you want to save JSON(NoSQL) data you can use Realm library the approach remains the same.

You can refer to the official documentation if you need it. Let’s Start! You have to add some dependencies on the shared build.gradle file

In Common main-

implementation("com.squareup.sqldelight:runtime:$sqlDelight..")

In Android main-

implementation("com.squareup.sqldelight:android-driver:$sql..")

In iOS main-

implementation("com.squareup.sqldelight:native-driver:$sqlD..")

Now dependencies are set to go but there is one more thing to do. In Android, the SQL driver differs from the iOS SQL driver, and also in android, we have the context to get the state of activity wherein iOS there is no context.

We have to write some actual and expect functions that will resolve all platform conflicts in iOS and Android. What it does is it calls different SQL driver functions in respective platforms which you can define platform specific.

In commanMain Platform class create an Expect function :

expect class DatabaseDriverFactory {
fun createDriver(): SqlDriver
}

In androidMain Platform class create an Actual function :

actual class DatabaseDriverFactory(private val context: Context) {
actual fun createDriver(): SqlDriver {
return AndroidSqliteDriver(MyAppDb.Schema, context, "app.db")
}
}

In the iosMain Platform class create an Actual function :

actual class DatabaseDriverFactory {
actual fun createDriver(): SqlDriver {
return NativeSqliteDriver(MyAppDb.Schema, "app.db")
}
}

To create a DB query to create delete commands we have to make a MyAppDb.sq file you can download the sqldelight plugin to beautify the query file

So we have created package in commanMain and write .sq file sqldelight>com>mounty>camper>cache>MyAppDb.sq

Now in CommanMain build.gradle add SqlDelight database creation generation file .sq provider

sqldelight { database("MyAppDb") { packageName = "com.mounty.camper.cache"
sourceFolders = listOf("sqldelight")

**}  

}**

Now we can create a common AppDao to save Db

class AppDao(databaseDriverFactory: DatabaseDriverFactory) {
private val database = MyAppDb(databaseDriverFactory.createDriver())
private val dbQuery = database.myAppDbQueries

fun insertRecent(it: String) {  
    dbQuery.insertSearch(title = it)  
}  

fun deleteAllViewed() {  
    database.myAppDbQueries.deleteAllViewed()  
}  
fun getRecentSearched(): List<String> {  
    return LinkedHashSet(dbQuery.selectAll().executeAsList()).*toList*()  
}  

fun getSimilar(searched: String): List<String> {  
    return LinkedHashSet(dbQuery.selectSimilar(searched).executeAsList()).*toList*()  
}  

fun insertViewed(  
    id: Long?**,** type: String**,** image: String**,** name: String**,** location: String**,** ratings: String**,** link: String**,** price: String**,** discount: String  
) {  
    dbQuery.insertViewed(id**,** type**,** image**,** name**,** location**,** ratings**,** link**,** price**,** discount)  
}  


fun getRecentViewed(): List<SelectAllViewed> {  
    return LinkedHashSet(dbQuery.selectAllViewed().executeAsList()).*toList*()  
}  


fun getCount(): Long {  
    return dbQuery.countViewed().executeAsOne()  
}  

}

call Dao function from Android to save Db-

val sharedDb = AppDao(DatabaseDriverFactory(this@CampActivity))
sharedDb.insertViewed(
id = null, type = "camp", image = media.images[0].url.toString(), name = displayName, location = location!!.name, ratings = rating, link = "/camps/${slug}", price = price.toInt().toString(), discount = discount.toString()
)

call Dao function from iOS-

let sharedDb= AppDao(databaseDriverFactory: DatabaseDriverFactory())
sharedDb.insertViewed(
id = null, type = "camp", image = media.images[0].url.toString(), name = displayName, location = location.name, ratings = rating, link = "/camps/${slug}", price = price.toInt().toString(), discount = discount.toString()
)

That is how you can implement a common Database Service in both Android and iOS App. If you have difficulty in getting this. My Sample App code is provided for beginners.

JetBrains is actively pushing multiple updates and seems to be very rapidly fixing issues.

Follow me:
Blog: http://www.maddeveloper.in
Twitter: https://twitter.com/AnujSachan72

About Mounty

Mounty is an online discovery and booking platform for camps, adventure activities & trips anchored by the largest network of privately owned campsites, adventures, and trips providers. We aim to make the travel experience fun and seamless. We do this through an amazing team of passionate travelers with years of experience and exceptional capabilities.

 
Share this