Vapor 4:创建包含 Fluent ParentProperty 的协议会导致编译器错误

Vapor 4: creating a protocol that contains a Fluent ParentProperty results in compiler errors

我有一大堆 Fluent (Vapor 4) 模型,所有模型都有这样的父字段:

final class Location: Model, Content {
  // .. bunch of other properties

  @Parent(key: FieldKeys.campaign)
  var campaign: Campaign
}

现在,我想制定一个可以应用于所有这些模型的协议,如下所示:

protocol HasCampaignId: Model {
  var _campaign: ParentProperty<Self, Campaign> { get }
  func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self
}

extension HasCampaignId {
  func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self {
    if self._campaign.id != campaignID {
      throw Abort(.forbidden)
    }

    return self
  }
}

只是一个方便的小函数,我可以将其应用于 HasCampaignId 模型的任何实例,这就是我的想法。遗憾的是这没有编译,我收到错误 Property '_campaign' must be declared internal because it matches a requirement in internal protocol 'HasCampaignId'。我可以制定协议 public,但随后又出现另一个错误:Property '_campaign' must be as accessible as its enclosing type because it matches a requirement in protocol 'HasCampaignId'.

我可以这样更改协议:

protocol HasCampaignId: Model {
  var campaign: Campaign { get }
  func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self
}

extension HasCampaignId {
  func belongsToCampaign(_ campaignID: Campaign.IDValue) throws -> Self {
    if self.campaign.id != campaignID {
      throw Abort(.forbidden)
    }

    return self
  }
}

但这需要我加载竞选关系,这通常不是我想要的 - 否则它会崩溃并出现致命错误:Fatal error: Parent relation not eager loaded, use $ prefix to access: Parent<Loot, Campaign>(key: campaign_id)

我的协议中的 campaign 属性 也不能应用 属性 包装器。

那么我怎样才能有一个需要 ParentProperty 字段的协议呢?我该如何解决编译器错误?

从 Swift 5.4 和 5.5 开始 - 你不能。 属性 协议中的包装器已被推销,但尚未实施且无法强制执行。在 Fluent 中尝试和解决这些限制付出了很多努力,但目前无法完成您正在尝试的事情。