1

我有一大堆 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'。我可以将协议公开,但随后我得到另一个错误: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字段的协议呢?如何解决编译器错误?

4

1 回答 1

2

从 Swift 5.4 和 5.5 开始 - 你不能。协议中的属性包装器已经被提出,但它们没有实现并且不可能强制执行。在 Fluent 中尝试和解决这些限制已经付出了很多努力,但目前还不能做你正在尝试的事情。

于 2021-08-24T11:27:47.400 回答