swift - 使用 Vapor 4 中的协议(protocol)进行通用流畅查询

标签 swift fluent vapor

我有几个模型有一个同名的日期字段,如下所示:

final class ModelA: Model {

static let schema = "model_a"

@Timestamp(key: "modification_date", on: .update, format: .unix)
var modificationDate: Date?

}

final class ModelB: Model {

static let schema = "model_b"

@Timestamp(key: "modification_date", on: .update, format: .unix)
var modificationDate: Date?

}

final class ModelC: Model {

static let schema = "model_c"

@Timestamp(key: "modification_date", on: .update, format: .unix)
var modificationDate: Date?

}

在我的代码中的某个时刻,我想要获取最近更改的模型。所以我可以这样写:

func getRecentlyChangedModelAs(on db: Database) async throws -> [ModelA] {
   return try await ModelA.query(on: db)
                          .group(.and) { group in
                             group.filter(\.$modificationDate != nil)
                             group.filter(\.$modificationDate > Date.now.addingTimeInterval(TimeInterval(-3600)))
                          }
                          .all()
}

func getRecentlyChangedModelBs(on db: Database) async throws -> [ModelB] {
   return try await ModelB.query(on: db)
                          .group(.and) { group in
                             group.filter(\.$modificationDate != nil)
                             group.filter(\.$modificationDate > Date.now.addingTimeInterval(TimeInterval(-3600)))
                          }
                          .all()
}

func getRecentlyChangedModelCs(on db: Database) async throws -> [ModelC] {
   return try await ModelC.query(on: db)
                          .group(.and) { group in
                             group.filter(\.$modificationDate != nil)
                             group.filter(\.$modificationDate > Date.now.addingTimeInterval(TimeInterval(-3600)))
                          }
                          .all()
}

如您所见,有很多代码重复。为了避免这种情况,我尝试改用协议(protocol)和通用查询:

protocol ModifiableModel: Model, Content {
    var modificationDate: Date? { set get }
}

final class ModelA: ModifiableModel {

static let schema = "model_a"

@Timestamp(key: "modification_date", on: .update, format: .unix)
var modificationDate: Date?

}

etc...

func getRecentlyChangedModel<T: ModifiableModel>(on db: Database) async throws -> [T] {
   return try await T.query(on: db)
                     .group(.and) { group in
                        group.filter(\.$modificationDate != nil) // Errors: 'nil' is not compatible with expected argument type 'KeyPath<Right, RightField>', Generic parameter 'RightField' could not be inferred
                        group.filter(\.$modificationDate > Date.now.addingTimeInterval(TimeInterval(-3600))) // Errors: Cannot convert value of type 'Date' to expected argument type 'KeyPath<Right, RightField>', No exact matches in call to instance method 'filter'
                      }
                      .all()

不幸的是,这会导致查询过滤器出错。我不太明白这些错误,但我发现如果没有过滤器,一切都可以正常编译。我最好的猜测是这些错误与我尝试在过滤器中使用的关键路径有关。

有谁知道问题出在哪里或如何解决?或者我可以使用另一种方法来避免这种代码重复吗?任何帮助将不胜感激!

最佳答案

我认为这种方法行不通。线索在您通过将 T 放入过滤器中得到的错误消息中,如下所示:

group.filter(\T.$modificationDate != nil)

给出错误:

Generic parameter 'Field' could not be inferred and Value of type 'T' has no member '$modificationDate'

问题是由于 filter 需要一个用字段包装器定义的属性(在本例中为 @Timestamp)。但是,正如您可能发现的那样:

protocol ModifiableModel {
    @Timestamp(key: "modification_date", on: .update, format: .unix)
var modificationDate: Date?
}

导致错误消息,您不能在协议(protocol)中使用包装器定义变量。由于您的方法取决于这种情况,我认为它无法发挥作用。

编辑:

我忘了补充一点,您应该能够简化您的代码以仅过滤值。不应该首先测试非零。尝试:

func getRecentlyChangedModelAs(on db: Database) async throws -> [ModelA] {
   return try await ModelA.query(on: db)
                          .filter(\.$modificationDate > Date.now.addingTimeInterval(TimeInterval(-3600)))
                          .all()
}

如果您得到错误的结果,请检查您的迁移以确保此处没有任何错误。

关于swift - 使用 Vapor 4 中的协议(protocol)进行通用流畅查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73679644/

相关文章:

swift - Vapor 3 - 如何在保存对象之前检查类似的电子邮件

ios - 类的解析列值始终为零

ios - 为什么在使用分段控件时 UITableView contentOffset 会发生变化?

ios - 将新单元格添加到 Collection View 时,我不断收到布局错误

java - AssertJ - 检查类后继续流畅的断言

mongodb - 在 Vapor 和 Fluent 中使用 Mongodb

Swift Vapor unsupported_grant_type 无效的签名/OAuth 访问 token

ios - 设置 UIImageView 图片影响布局约束

java - 在构建器模式中使用抽象类?

swift - 如何在 FluentProvider for Vapor 中使用字符串化 UUID 作为主键 - Swift