0

我正在使用Vapor 3开发 REST API 。此 API 使用另一个 API 创建稍后将由应用程序使用的内容。所以我创建了一个从这个 API(联赛和赛季)获取内容并将它们存储在我的 MySQL 数据库中的函数。API 的响应还包含我也想存储的嵌套对象,如果可能的话都在同一个请求中。这是 API 响应:

{
"data": [
         {
             "id": 271,
             "name": "Superliga",
             "current_season_id": 16020,
             "season": {
                 "data": {
                     "id": 16020,
                     "name": "2019/2020",
                     "league_id": 271,
                 }
             }
        }
    ]
}

这是模型:

final class League: MySQLModel {

    var id: League.ID?

    var name: String

    var current_season_id: Season.ID

    var currentSeason: Parent<League, Season> {
        return parent(\League.current_season_id)
    }
}

final class Season: MySQLModel {

    var id: Season.ID?

    var name: String

    var league_id: League.ID

    var league: Parent<Season, League> {
        return parent(\.league_id)
    }
}

这是执行请求并存储在数据库上的函数。

func getLeagues(using context: CommandContext) throws -> EventLoopFuture<Void> {
    guard let url = URL(string: "SOME_API_URL") else { return .done(on: context.container) }

    let client = try context.container.client()
    return client.get(url).flatMap({ (response) -> EventLoopFuture<Void> in // do the request
        let leagues = response.content.get([League].self, at: "data") // get the array of EventLoopFuture<[League]>

        return context.container.requestPooledConnection(to: .mysql).flatMap({ (connection) -> EventLoopFuture<Void> in // connecto to DB

            let savedLeagues = leagues.flatMap(to: [League].self, { (flattenLeagues) -> EventLoopFuture<[League]> in
                return flattenLeagues.map { (league) -> EventLoopFuture<League> in

                    return league.create(orUpdate: true, on: connection) // save on the DB

                }.flatten(on: context.container)
            })

            return savedLeagues.flatMap { (_) -> EventLoopFuture<Void> in
                return .done(on: context.container)
            }
        })
    })
}

问题是:可以保存父子关系吗?我必须使用解码/编码功能手动完成吗?我确实实现了编码/解码并创建了联赛,但不知道如何创建赛季以及如何在执行时保存所有内容league.create(orUpdate: true, on: connection)

任何帮助都将不胜感激。

4

1 回答 1

1

如我所见,您可以APIModel先解码,然后像这样将两个对象保存在 flatten 循环中

struct APILeague: Content {
    let id: League.ID
    let name: String
    let current_season_id: Season.ID
    struct _Season: Codable {
        let data: Season
    }
    let season: _Season
}
final class League: MySQLModel {
    var id: League.ID?
    var name: String
    var current_season_id: Season.ID

    var currentSeason: Parent<League, Season> {
        return parent(\League.current_season_id)
    }

    init (_ data: APILeague) {
        self.id = data.id
        self.name = data.name
        self.current_season_id = data.current_season_id
    }
}

func getLeagues(using context: CommandContext) throws -> Future<Void> {
    guard let url = URL(string: "SOME_API_URL") else { return .done(on: context.container) }

    let client = try context.container.client()
    return client.get(url).flatMap { response in // do the request
        return response.content.get([APILeague].self, at: "data").flatMap { leagues in
            return context.container.requestPooledConnection(to: .mysql).flatMap { connection in // connecto to DB
                let operations = leagues.map { league in
                    return League(league).create(orUpdate: true, on: connection).flatMap { _ in
                        return league.season.data.create(orUpdate: true, on: connection).transform(to: ()) // transforming to Void
                    } 
                }
                return operations.flatten(on: context.container)flatMap {
                    return .done(on: context.container)
                }
            }
        }
    }
}
于 2019-10-09T20:17:41.147 回答