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 中尝试和解决这些限制付出了很多努力,但目前无法完成您正在尝试的事情。
我有一大堆 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 中尝试和解决这些限制付出了很多努力,但目前无法完成您正在尝试的事情。