I'm trying to save model to PostgreSQL DB. The problem is, I can't properly save submodels. When I save model, it saves only ID without any relation. What am I do wrong? Request body are properly set from as POST request. I don't know how to connect model field with another model/array of models.
Create method:
func create(req: Request) async throws -> CollectionResponse {
let todo = try req.content.decode(CollectionResponse.self)
try await todo.save(on: req.db)
return todo
}
Migrations
struct CreateCollection: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("collection")
.id()
.field("childrenArray", .custom([Object()]))
.create()
}
func revert(on database: Database) async throws {
try await database.schema("collection").delete()
}
}
struct CreateCollectionObject: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("collectionObject")
.id()
.field("personalID", .string, .required)
.field("title", .string)
.field("thumbnail", .string)
.field("model_a_id", .uuid, .required, .references(CollectionResponse.schema, .id))
.create()
}
func revert(on database: Database) async throws {
try await database.schema("collectionObject").delete()
}
}
Models:
final class CollectionResponse: Model, Content, Codable{
static var schema: String = "collection"
@ID(key: .id)
var id: UUID?
@Children(for: \.$modelA)
var childrenArray: [Object]
init() { }
init(id: UUID? = UUID(), childrenArray: [Object] = []) {
self.id = id
self.childrenArray = childrenArray
}
}
final class Object: Model, Content, Codable{
static var schema: String = "collectionObject"
@ID(key: .id)
var id: UUID?
@Field(key: "perosnalID")
var personalID: String?
@Field(key: "title")
var title: String?
@Field(key: "thumbnail")
var thumbnail: String?
@Parent(key: "model_a_id")
var modelA: CollectionResponse
init() { }
init(id: UUID? = UUID(), perosnalID: String?, title: String?, thumbnail: String?, modelA: UUID = UUID()) {
self.id = id
self.personalID = personalID
self.title = title
self.thumbnail = thumbnail
self.$modelA.id = modelA
}
}
CodePudding user response:
The save
in your create
route will not save any children objects in todo
. This is your responsibility. I haven't changed to async
methods yet, but the way to do it originally in vapor 4 is to save the parent first and then capture the id
and update the children objects so that they have the correct foreign key value. Something like:
func create(req: Request) async throws -> CollectionResponse {
let todo = try req.content.decode(CollectionResponse.self)
return todo.save(on: req.db).flatMap { _ in
// todo has been updated with the primary key field value
todo.childrenArray.map{ $0.$modelA.$id = todo.$id }
todo.childrenArray.save(on: req.db).flatMap { _ in
return todo
}
}
}
Following the guidelines in https://docs.vapor.codes/4.0/fluent/model/ for naming fields and properties consistently would be a good idea. See this page for details of how the array save works on the childrenArray
, it is essentially doing it as a single transaction.