SQLDelight 在使用流时转换查询 return 类型

SQLDelight convert query return type when using flows

我想在我的应用程序中使用 SQLDelight 作为缓存层,协程扩展到 return 来自我的 SQL 查询的流,并在本地数据库更改。
但是因为 SQLDelight 为存储的实体生成它自己的 class 并在流中发出它们,所以我无法将存储的 class 转换为整个其余部分使用的 class我的应用程序。

您可以在下面找到我的 FriendEntity SQL 类型和查询函数的摘录,SQLDelight 使用它来生成 FriendEntity 数据 class 和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 class 我的 Friend class 仍然 return 流。
如果不先收集流量,这是否可能?


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

生成者SQL喜悦:

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

您必须在源集中使用此扩展实现。

kotlin {
  sourceSets.commonMain.dependencies {
    implementation "com.squareup.sqldelight:coroutines-extensions:1.5.3"
  }
}

现在你可以得到这样的数据

val data: Flow<List<//YourDataClass>> = 
  query.selectAll()
    .asFlow()
    .mapToList()

参考:SQLDelight with flow

我在他们的 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