Родительские отношения с паром 4 - PullRequest
1 голос
/ 16 июня 2020

Я хочу установить отношения родитель-потомок между League и Team в Vapor 4. Я могу создать League отлично, но когда я пытаюсь создать новую команду, например:

{
    "name": "Chicago Bulls",
    "league_id": "C21827C2-8FAD-4A89-B8D3-A3E62E421258"
}

Я получаю эту ошибку:

{
    "error": true,
    "reason": "Value of type 'League' required for key 'league'."
}

Я просто хочу инициализировать Team с помощью league_id, который ссылается на League из таблицы Leagues. У меня это работало в Vapor 3, но, похоже, не могу понять это правильно в Vapor 4.

См. Модели и миграции ниже.

League модель:

final class League: Model, Content {

    init() {}
    static let schema = "Leagues"

    @ID(key: .id) var id: UUID?
    @Field(key: .name) var name: String
    @Field(key: .sport) var sport: String

    @Children(for: \.$league) var teams: [Team]

    init(name: String, sport: String) {
        self.name = name
        self.sport = sport
    }

}

Team модель:

final class Team: Model, Content {

    init() {}
    static let schema = "Teams"

    @ID(key: .id) var id: UUID?
    @Field(key: .name) var name: String

    @Parent(key: .leagueId) var league: League

    init(id: UUID? = nil, name: String, leagueId: UUID) throws {
        self.id = id
        self.name = name
        self.$league.id = leagueId
    }

}

CreateLeague миграция:

struct CreateLeague: Migration {

    func prepare(on database: Database) -> EventLoopFuture<Void> {
        return database.schema(League.schema)
            .id()
            .field(.name, .string, .required)
            .field(.sport, .string, .required)
            .create()
    }

    func revert(on database: Database) -> EventLoopFuture<Void> {
        return database.schema(League.schema).delete()
    }

}

CreateTeam миграция:

struct CreateTeam: Migration {

    func prepare(on database: Database) -> EventLoopFuture<Void> {
        return database.schema(Team.schema)
            .id()
            .field(.name, .string, .required)
            .field(.leagueId, .uuid, .required, .references(League.schema, .id))
            .create()
    }

    func revert(on database: Database) -> EventLoopFuture<Void> {
        return database.schema(Team.schema).delete()
    }

}

TeamsController:

class TeamsController: RouteCollection {

    func boot(routes: RoutesBuilder) throws {
        let teamsRoute = routes.grouped("teams")
        teamsRoute.post(use: createTeam)
    }

    func createTeam(req: Request) throws -> EventLoopFuture<Team> {
        let team = try req.content.decode(Team.self)
        return team.save(on: req.db).map { team }
    }

}

Ответы [ 2 ]

3 голосов
/ 16 июня 2020

Это не удается из-за способа, которым оболочки свойств переопределяют декодирование JSON для моделей. У вас есть два варианта. Вы можете отправить JSON Fluent ожидает:

{
    "name": "Chicago Bulls",
    "league": {
        "id": "C21827C2-8FAD-4A89-B8D3-A3E62E421258"
    }
}

Или вы можете создать новый тип CreateTeamData, который соответствует JSON, который вы ожидаете отправить, и вручную создать Team из этого. Я предпочитаю второй маршрут:

struct CreateTeamData: Content {
  let name: String
  let leagueID: UUID
}

func createTeam(req: Request) throws -> EventLoopFuture<Team> {
    let data = try req.content.decode(Team.self)
    let team = Team(name: data.name, leagueID: data.leagueID)
    return team.save(on: req.db).map { team }
}
0 голосов
/ 16 июня 2020

Мне кажется, что ваши миграции в порядке. Попробуйте изменить инициализацию модели Team на:

init(id: UUID? = nil, name: String, leagueId: League.IDValue) throws {
    self.id = id
    self.name = name
    self.$league.id = leagueId
}
...