Как сохранить отношение родитель-потомок из ответа JSON в Vapor 3
Я разрабатываю REST API с использованием Vapor 3. Этот 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)
Любая помощь будет принята.
1 ответ
Насколько я понимаю, вы можете расшифровать APIModel
сначала, затем сохраните два объекта внутри плоского цикла, как это
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)
}
}
}
}
}