Describe the bug
no such table error when creating a pivot object by attach
To Reproduce
final class Branch: Model, Content {
static let schema = "t_branch"
@ID(key: .id)
var id: UUID?
@Field(key: "name")
var name: String
@Siblings(through: BranchPerson.self, from: \.$branch, to: \.$person)
var persons: [Person]
init() { }
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
}
final class Person: Model, Content {
static let schema = "t_person"
@ID(key: .id)
var id: UUID?
@Field(key: "name")
var name: String
@Siblings(through: BranchPerson.self, from: \.$person, to: \.$branch)
var branches: [Branch]
init() { }
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
}
final class BranchPerson: Model, Content {
static let schema = "t_branch_person"
@ID(key: .id)
var id: UUID?
@Parent(key: "branchId")
var branch: Branch
@Parent(key: "personId")
var person: Person
init() { }
init(id: UUID? = nil, branch: Branch, person: Person) throws {
self.id = id
self.$branch.id = try branch.requireID()
self.$person.id = try person.requireID()
}
}
struct CreateBranchPerson: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("t_branch_person")
.id()
.field("branchId", .uuid, .required, .references("branch", "id", onDelete: .cascade))
.field("personId", .uuid, .required, .references("person", "id", onDelete: .cascade))
.unique(on: "branchId", "personId") // 不允许重复的关系
.create()
}
func revert(on database: Database) async throws {
try await database.schema("t_branch_person").delete()
}
}
public func configure(_ app: Application) throws {
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
app.views.use(.leaf)
app.databases.use(.sqlite(.file("db.sqlite")), as: .sqlite)
app.migrations.add(CreateBranch())
app.migrations.add(CreatePerson())
app.migrations.add(CreateBranchPerson())
try routes(app)
}
struct PersonWatchOnBranchController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.post("person", ":personId", "watchOn", ":branchId", use: createPersonWatchOnBranchHandler)
}
func createPersonWatchOnBranchHandler(req: Request) async throws -> HTTPStatus {
guard let person = try await Person.find(req.parameters.get("personId"), on: req.db),
let branch = try await Branch.find(req.parameters.get("branchId"), on: req.db)
else {
throw Abort(.notFound)
}
// 只有当关系不存在时才附加
try await person.$branches.attach(branch, method: .ifNotExists, on: req.db)
//try await branch.$persons.attach(person, method: .ifNotExists, on: req.db)
return .ok
}
}
Steps to reproduce the behavior:
- Add package with configuration '...'
let package = Package(
name: "ipas",
platforms: [
.macOS(.v12)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.67.1"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.5.0"),
.package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.2.0"),
.package(url: "https://github.com/m-barthelemy/vapor-queues-fluent-driver.git", from: "3.0.0-beta1"),
.package(url: "https://github.com/vapor/leaf.git", from: "4.2.2"),
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
.product(name: "QueuesFluentDriver", package: "vapor-queues-fluent-driver"),
.product(name: "Leaf", package: "leaf"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides/blob/main/docs/building.md#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
.executableTarget(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
- Send request with options '...'
POST http://127.0.0.1:8080/person/D9B06675-532F-45A8-BD93-CA10241DDA7B/watchOn/8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7
- See error
[ INFO ] POST /person/D9B06675-532F-45A8-BD93-CA10241DDA7B/watchOn/8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7 [request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (Vapor/RouteLoggingMiddleware.swift:13)
[ DEBUG ] query read t_person filters=[t_person[id] = D9B06675-532F-45A8-BD93-CA10241DDA7B] limits=[count(1)] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (FluentKit/QueryBuilder.swift:293)
[ DEBUG ] No available connections on this event loop, creating a new one (AsyncKit/EventLoopConnectionPool.swift:202)
[ DEBUG ] Connected to sqlite db: db.sqlite (SQLiteNIO/SQLiteConnection.swift:112)
[ DEBUG ] PRAGMA foreign_keys = ON [] (SQLiteNIO/SQLiteConnection.swift:161)
[ DEBUG ] SELECT "t_person"."id" AS "t_person_id", "t_person"."name" AS "t_person_name", "t_person"."email" AS "t_person_email", "t_person"."telephone" AS "t_person_telephone", "t_person"."dingTalkId" AS "t_person_dingTalkId" FROM "t_person" WHERE "t_person"."id" = ? LIMIT 1 ["D9B06675-532F-45A8-BD93-CA10241DDA7B"] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (SQLiteNIO/SQLiteConnection.swift:161)
[ DEBUG ] query read t_branch filters=[t_branch[id] = 8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7] limits=[count(1)] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (FluentKit/QueryBuilder.swift:293)
[ DEBUG ] SELECT "t_branch"."id" AS "t_branch_id", "t_branch"."name" AS "t_branch_name" FROM "t_branch" WHERE "t_branch"."id" = ? LIMIT 1 ["8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7"] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (SQLiteNIO/SQLiteConnection.swift:161)
[ DEBUG ] query read t_branch_person filters=[t_branch_person[personId] = D9B06675-532F-45A8-BD93-CA10241DDA7B, t_branch_person[branchId] = 8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7] limits=[count(1)] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (FluentKit/QueryBuilder.swift:293)
[ DEBUG ] SELECT "t_branch_person"."id" AS "t_branch_person_id", "t_branch_person"."branchId" AS "t_branch_person_branchId", "t_branch_person"."personId" AS "t_branch_person_personId" FROM "t_branch_person" WHERE "t_branch_person"."personId" = ? AND "t_branch_person"."branchId" = ? LIMIT 1 ["D9B06675-532F-45A8-BD93-CA10241DDA7B", "8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7"] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (SQLiteNIO/SQLiteConnection.swift:161)
[ DEBUG ] query create t_branch_person input=[[branchId: 8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7, personId: D9B06675-532F-45A8-BD93-CA10241DDA7B, id: 265A29D6-8205-48B1-B225-E838BCDA3E63]] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (FluentKit/QueryBuilder.swift:293)
[ DEBUG ] INSERT INTO "t_branch_person" ("branchId", "personId", "id") VALUES (?, ?, ?) ["8F25A197-1BC8-4679-BC28-E4AC3F1CDAF7", "D9B06675-532F-45A8-BD93-CA10241DDA7B", "265A29D6-8205-48B1-B225-E838BCDA3E63"] [database-id: sqlite, request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (SQLiteNIO/SQLiteConnection.swift:161)
[ WARNING ] error: no such table: main.person [request-id: EF168AC8-6511-4E7B-9F59-11C40A1176DA] (Vapor/Middleware/ErrorMiddleware.swift:42)
Expected behavior
create a pivot (BranchPerson) successfully without any error.
Environment
{
"identity" : "vapor",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/vapor.git",
"state" : {
"revision" : "0eacdf3c7eab6df493ce328f2e97c2873b3e1c1e",
"version" : "4.67.1"
}
}
- Vapor Toolbox version: toolbox: 18.6.0
- OS version: 12.6 (21G115)