You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When calling detach or detachAll on a SiblingsProperty, the related pivot model doesn't trigger its delete lifecycle events.
Works fine with create events using attach.
I tried and successfully reproduced the bug on SQLite and PostgreSQL, but it may be present in other drivers too.
To Reproduce
Steps to reproduce the behavior:
Create the following models:
finalclassTodo:Model,Content{staticletschema="todo"@ID(key:.id)varid:UUID?@Field(key:"title")vartitle:String@Siblings(through:TodoTagPivot.self, from: \.$todo, to: \.$tag)vartags:[Tag]init(){}init(id:UUID?=nil, title:String){self.id = id
self.title = title
}}finalclassTag:Model,Content{staticletschema="tag"@ID(key:.id)varid:UUID?@Field(key:"name")varname:String@Siblings(through:TodoTagPivot.self, from: \.$tag, to: \.$todo)vartodos:[Todo]init(){}init(id:UUID?=nil, name:String){self.id = id
self.name = name
}}finalclassTodoTagPivot:Model,Content{staticletschema="todo_tag"@ID(key:.id)varid:UUID?@Parent(key:"todo_id")vartodo:Todo@Parent(key:"tag_id")vartag:Taginit(){}init(id:UUID?=nil){self.id = id
}}
And the following lifecycle middleware:
structTodoTagLifecycle:AsyncModelMiddleware{func softDelete(model:TodoTagPivot, on db:Database, next:AnyAsyncModelResponder)asyncthrows{tryawait model.$todo.load(on: db)tryawait model.$tag.load(on: db)print("Soft-deleting the pivot between \(model.todo.title) and \(model.tag.name)")tryawait next.softDelete(model, on: db)}func delete(model:TodoTagPivot, force:Bool, on db:Database, next:AnyAsyncModelResponder)asyncthrows{tryawait model.$todo.load(on: db)tryawait model.$tag.load(on: db)print("Deleting the pivot between \(model.todo.title) and \(model.tag.name)")tryawait next.delete(model, force: force, on: db)}func create(model:TodoTagPivot, on db:Database, next:AnyAsyncModelResponder)asyncthrows{tryawait model.$todo.load(on: db)tryawait model.$tag.load(on: db)print("Creating the pivot between \(model.todo.title) and \(model.tag.name)")tryawait next.create(model, on: db)}}
Add the lifecycle middleware to the database middlewares (SQLite example):
func boot(routes:RoutesBuilder)throws{lettodos= routes.grouped("todos")...
todos.group(":todoID"){ todo in
todo.patch(use: update)...}}extensionTodo{structUpdate:Content{lettagIDs:[UUID]}}func update(req:Request)asyncthrows->Todo{lettodoID=try req.parameters.require("todoID", as:UUID.self)letdto=try req.content.decode(Todo.Update.self)
guard let todo =try?awaitTodo.find(todoID, on: req.db)else{throwAbort(.notFound)}lettags=tryawaitTag.query(on: req.db).filter(\.$id ~~ dto.tagIDs).all()tryawait todo.$tags.detachAll(on: req.db)// TodoTagPivot rows get deleted.tryawait todo.$tags.attach(tags, on: req.db)tryawait todo.update(on: req.db)return todo
}
See how TodoTagPivot create events get emitted, but no delete event is.
Expected behavior
Calling detach or detachAll deletes the corresponding rows in the related pivot table, so lifecycle delete events should be emitted.
Describe the bug
When calling
detach
ordetachAll
on a SiblingsProperty, the related pivot model doesn't trigger its delete lifecycle events.Works fine with create events using
attach
.I tried and successfully reproduced the bug on SQLite and PostgreSQL, but it may be present in other drivers too.
To Reproduce
Steps to reproduce the behavior:
And the following lifecycle middleware:
Expected behavior
Calling
detach
ordetachAll
deletes the corresponding rows in the related pivot table, so lifecycle delete events should be emitted.Environment
Note: same issue as vapor/fluent#747
May be better to close it.
The text was updated successfully, but these errors were encountered: