【问题标题】:Vapor 3: when returning a model, how to easily also return child objectsVapor 3:返回模型时,如何轻松也返回子对象
【发布时间】:2019-08-01 01:27:06
【问题描述】:

我有一个模型广告系列,它有多个月份:

final class Campaign: Content, SQLiteModel {
  var id: Int?
  var name: String
  var months: Children<Campaign, Month> {
    return children(\.campaignID)
  }
}

当我想以最基本的方式返回一个活动时,它不包括月份,因为据我所知,计算属性不是可编码的。

func getOneHandler(_ req: Request) throws -> Future<Campaign> {
  return try req.parameters.next(Campaign.self)
}

所以,我创建了一个新结构来保存我想要返回的完整对象

struct FullCampaignData: Content {
  let id: Int
  let name: String
  var months: [Month]?
}

然后像这样修改我的路由处理程序:

func getOneHandler(_ req: Request) throws -> Future<FullCampaignData> {
  return try req.parameters.next(Campaign.self).flatMap(to: FullCampaignData.self) { campaign in
    return try campaign.months.query(on: req).all().map(to: FullCampaignData.self) { months in
      return try FullCampaignData(id: campaign.requireID(), name: campaign.name, months: months)
    }
  }
}

这确实有效。但是,这样做似乎需要做很多工作和大量样板文件。处理子对象或其他一般计算对象的正常 Swifty“Vapory”方式是什么?现在它似乎归结为你的模型的一堆不同版本(用于创建,用于返回,实际的完整内部模型),然后在它们之间进行转换,但我希望我在这里缺少一些东西?因为很容易忘记将新添加的模型属性也添加到该特殊的公共模型中。

或者至少,如果确实以推荐的方式在模型之间进行转换,有没有一种方法不需要路由处理程序中的所有这些嵌套地图/平面地图?

【问题讨论】:

  • 手动连接或子查询是 Fluent 3 的最佳方式。Fluent 4 将支持预先加载以自动执行此操作。
  • Vapor 4 突然听起来很有趣! :) 下面 imike 的连接/子查询示例与我自己所做的相比看起来并没有那么好或更容易(见上文):(

标签: swift vapor vapor-fluent


【解决方案1】:

您可以使用SwifQL lib 进行复杂查询

我不确定使用 SQLite 是否可以子查询 Months,但使用 PostgreSQL 真的很容易,因为它支持 JSON

所以对于 PostgreSQL,您的查询可能看起来像

func getOneHandler(_ req: Request) throws -> Future<FullCampaignData> {
    let monthsSubquery = SwifQL.select(Fn.array_agg(Fn.to_jsonb(Month.table)))
    let query = SwifQL.select(Campaign.table.*, |monthsSubquery| => "months")
        .from(Campaign.table)
        .join(.leftOuter, Month.table, on: \Month.campaignID == \Campaign.id)
        .execute(on: req, as: .psql)
        .all(decoding: FullCampaignData.self)
}

func getOneHandler(_ req: Request) throws -> Future<FullCampaignData> {
    let monthsSubquery = SwifQL.select(Fn.array_agg(Fn.to_jsonb(Month.table)))
        .from(Month.table)
        .where(\Month.campaignID == \Campaign.id)
    let query = SwifQL.select(Campaign.table.*, |monthsSubquery| => "months")
        .from(Campaign.table)
        .execute(on: req, as: .psql)
        .all(decoding: FullCampaignData.self)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 1970-01-01
    相关资源
    最近更新 更多