kotlin - 使用流时 SQLDelight 转换查询返回类型

标签 kotlin kotlin-coroutines sqldelight kotlinx.coroutines.flow

我想使用 SQLDelight 作为我的应用程序中的缓存层,并使用协程扩展来从 SQL 查询返回流,并在本地数据库中的条目发生更改时收到通知。
但是因为 SQLDelight 为存储的实体生成它自己的类并在流中发出它们,所以我在将存储的类转换为在我的应用程序的其余部分中使用的类时遇到了麻烦。

下面您可以找到我的 FriendEntity SQL 类型和查询函数的摘录,SQLDelight 使用它来生成 FriendEntity 数据类和 kotlin 函数(生成的输出位于问题底部)

// 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;
);

下面我想创建一个缓存服务,它也发出 flow 但类型为 Friend 而不是 FriendEntity 所以我必须以某种方式进行转换将 FriendEntity 类添加到我的 Friend 类,同时仍返回流。
如果不先收集流量,这是否可能?


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,
)

由 SQLDelight 生成:

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()
}

最佳答案

我在他们的 Github 讨论中提出了这个问题,并得到了一个不依赖扩展的很好答案。您可以在调用查询时使用自定义映射器参数:

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
  }
}

抄送:亚历克·斯特朗
https://github.com/cashapp/sqldelight/discussions/2782

关于kotlin - 使用流时 SQLDelight 转换查询返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70717634/

相关文章:

android - 如何查看/更新数据库版本?有类似 "fallbackToDestructiveMigration"的东西吗?

android - SQLDelight 关系

android - 使用 sqldelight 为 getter 和 setter 添加前缀

annotations - 从属性中注释 getter

rest - JAX-RS如何在Kotlin中读取列表的实体响应

java - 让 Hibernate 创建 TIMESTAMP 列

android - 如何等待所有异步完成?

java - 在使用 Kotlin 的方法中抛出异常

android - 使用 Coroutine runblock 和 Authenticator 来处理来自改造的 401 响应

kotlin - 尝试调用运行阻塞时,带有协同程序的Kotlin Vertx阻塞