I want to use SQLDelight as a caching layer in my App with the coroutines extension to return a flow from my SQL queries and get notified when the entry in the local Database changes.
But because SQLDelight generates it's own class for the stored entity and emits them in a flow I'm having trouble converting the stored class to the class used throughout the rest of my app.
Below you can find an extract of my FriendEntity
SQL type and query function which SQLDelight uses to generate the FriendEntity
data class and kotlin functions (Generated outputs at bottom of Question)
// SQLDelight queries
CREATE TABLE FriendEntity (
id TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
firstname TEXT NOT NULL,
lastname TEXT,
phone TEXT,
picture TEXT,
accepted INTEGER AS Boolean DEFAULT 0 NOT NULL
getFriendById:
SELECT * FROM FriendEntity
WHERE id = :id;
);
Below I want to create a caching service which also emits a flow
but of type Friend
and not FriendEntity
so I somehow have to convert the FriendEntity
class to my Friend
class while still returning a flow.
Is that even possible without collecting the flow first?
override fun get(id: String): Flow<Friend>? {
return try {
return queries.getFriendById(id = id).asFlow() //returns Flow<Query<FriendEntity>>
} catch (e: NullPointerException) {
null
}
}
data class Friend(
var profile: Profile,
var accepted: Boolean
)
data class Profile(
var id: String,
var username: String,
var firstname: String,
var lastname: String?,
var phone: String? = null,
var picture: String? = null,
)
public fun <T : Any> getFriendById(id: String, mapper: (
id: String,
username: String,
firstname: String,
lastname: String?,
phone: String?,
picture: String?,
accepted: Boolean
) -> T): Query<T>
public fun getFriendById(id: String): Query<FriendEntity>
public data class FriendEntity(
public val id: String,
public val username: String,
public val firstname: String,
public val lastname: String?,
public val phone: String?,
public val picture: String?,
public val accepted: Boolean
) {
public override fun toString(): String = """
|FriendEntity [
| id: $id
| username: $username
| firstname: $firstname
| lastname: $lastname
| phone: $phone
| picture: $picture
| accepted: $accepted
|]
""".trimMargin()
}
I asked this question in their Github discussion and got a great answer that doesn't depend on an extension. You can use a custom mapper parameter when calling the query:
override fun get(id: Long): Flow<Query<Friend>>? {
return try {
return queries.getFriendById(
id = id,
mapper = { friendId, username, firstname, lastname, phone, picture, accepted ->
Friend(
Profile(friendId, username, firstname, lastname, phone, picture),
accepted
)
}).asFlow()
} catch (e: NullPointerException) {
null
}
}
CC: Alec Strong
https://github.com/cashapp/sqldelight/discussions/2782