Skip to content
This repository has been archived by the owner on Sep 2, 2022. It is now read-only.

Discussion: Cascading Deletes #47

Closed
sorenbs opened this issue Dec 12, 2016 · 19 comments
Closed

Discussion: Cascading Deletes #47

sorenbs opened this issue Dec 12, 2016 · 19 comments

Comments

@sorenbs
Copy link
Member

sorenbs commented Dec 12, 2016

It should be possible to configure cascading deletes on relations.

If a user has many posts, it should be possible to specify that if a a user is deleted all associated posts should also be deleted.

We need to consider what should happen if a user is not delete, but all posts are removed from the relation. In traditional relational databases this scenario is not relevant as you can only have cascading deletes in association with foreign key constraints.

Related to but not a duplicate of #42

@emolr
Copy link

emolr commented Mar 15, 2017

Would it make sense to also make it possible with cascading update?
I have posts on a Campaign, and i do "soft deletion". Like i'm not deleting the content if the user regrets later on, so i have a field called deleted on the Post model.

It might be me overcomplicating it myself. So if you anyone has a tip on how to properly handle soft deletion, feedback on my approach would also be nice :)

@marktani
Copy link
Contributor

@emolr how is the cascading update coming in here? Wouldn't your use case be handled by simply updating the delete field of a post?

@emolr
Copy link

emolr commented Mar 15, 2017

@marktani It's coming when i'm "soft deleting" a campaign, and all related posts should then be too :)

@sorenbs
Copy link
Member Author

sorenbs commented Mar 16, 2017

We should consider what happens if a DELETE mutation callback is set up for the related model where many nodes are being deleted. Performing the actual deletion is fast, but performing potentially millions of mutation callbacks is expensive

@jvbianchi
Copy link

You could create a new type of mutation callback for this kind of operation.

@mkozhukharenko
Copy link

what is a solution for now? E.g. I have Course and it have, e.g. 50 Steps. When I'm deleting the course I dont want to make 51 request (deleting 50 Steps).

I propose to just t construct a dynamic query with all 50 mutations instead:

const client = new Lokka(...);
var allStepsIds = ['1', '2', '3', '4']
client.mutate(`{
    deleteStep: ${allStepsIds.map(id) => "deleteStep(id:" + id + "){ id }") }
}`).then(response => {
    console.log(response);
});

It seems that neither Apollo not batchql does not support mutation batching.

@danmkent
Copy link

danmkent commented Jul 19, 2017

My ideal way for this to be implemented would be:

  • Enable us to mark a one-one or one-many relation as a 'belongs to' relation where the second entity is dependent on the first

  • When the first entity (parent) in the relation is deleted, automatically delete the second entity (child) also following any further 'belongs to' relations and deleting further child entities if required

  • If a child entity is removed from its relationship with the parent entity, delete it

  • If a child entity is added to a relationship with a new parent, it can continue to exist

  • do not fire functions attached to the delete mutation of entities as this is an internal action rather than a mutation through the API

@sorenbs
Copy link
Member Author

sorenbs commented Jul 19, 2017

This sounds very reasonable to me @danmkent

Would you fire the attached function on the "parent" entity - the one being explicitly deleted?
If so, would you provide extra information about deleted "child" entities?

@davidjpetersen
Copy link

+1 for creating the cascading delete feature.

@kbrandwijk
Copy link
Contributor

kbrandwijk commented Jul 21, 2017

Cascading functionality requires triggering an action. If the bugs/features for triggering SSS and/or RP on relation updates are implemented, then you're free to deal with this yourself.
Deleting a parent should trigger an update SSS for the children (not RP, because SSS is async, see performance comment from @sorenbs above), because the relation field is updated. UpdatedFields tells you what was changed, so it's very easy to create a cascase soft-delete/delete/update mutation for any use case imaginable.
You wouldn't declaratively be able to specify cascade behavior, but at least it would give you the triggers to easily handle anything based on it.
I'm not saying it wouldn't be nice to get this out of the box, but I'd rather get the building blocks, than a black box implementation that might or might not fit everyone's use cases...

@danmkent
Copy link

I think there is a good argument for providing two things:

  • A simple 'belongs to' semantic in the schema that manages the basic use case of having objects that should only live as long as their parent does

  • More options for server side subscriptions that can react to relationship changes (e.g. a child losing its relationship with a parent because it has been deleted) and can be used to implement specific requirements

I can understand that the simple use case may not fit everyone's use case but at the same time, having to add a server side subscription for every type and potentially triggering a cascade of thousands (or even more!) of separate server side subscriptions for a common use case that could be dealt with more efficiently seems like a bad idea.

@danmkent
Copy link

@sorenbs Yes, I would expect functions attached to the parent entity to be triggered as normal.

Personally, I would only use a cascading delete for child entities that don't have any existence beyond being part of the parent, so I can't think of a circumstance in which I would need details about them being deleted. If a child type was important enough to need a function attaching to it, I wouldn't be deleting it automatically in this way.

@typeofgraphic
Copy link

There appears to be a need to differentiate the enforcement of a relation for data entry (e.g. a required one-to-many relation from User to Posts) from delete mutations. I've come across an use case with an app I'm building where there is a chain of relations across 3-4 Types.

For instance, if deleting a User deletes all his/her Posts in a cascading delete, what about when each Post has Comments, and those Comments have Votes? If these are all required, then would a cascading delete rip out everything in the relation chain?

In an app where multiple types are tied together in a chain of relations, having more specific semantic relation 'types' such as "belongs to" could dictate the depth of the deletion cascade. Developers need to feel confident that deleting a User won't rip out a trail of content or data.

It may be the case, for example, that a user is deleted, but that their Posts remain (e.g. archived).

The way around this is to make the relation optional (which is what I have done at this point) so as to make deletions far simpler. However, there are obvious drawbacks to this.

@kbrandwijk
Copy link
Contributor

Look at how SQL Server (or another database) implements cascade functionality. This kind of thing has been thought of, a lot, already...

@nickluger
Copy link

This is the only thing that prevents me to switching to (the otherwise terrific !) graphcool currently. I assumed that Object Composition would be an extremly common concept in almost any product. If a "Book" has 50 "Chapters" how can in expect the client to delete them beforehand. Also i think this whole cascade should be (optionally) opaque to the client. Any news on this? How are you writing your apps currently when you need composition?

@kbrandwijk
Copy link
Contributor

You can implement your own cascade delete functionality using resolver functions. It's a bit of a stretch, but at least you have full control if you want to orphan/delete child nodes n levels deep.

@danstepanov
Copy link

Any idea on when this might be implemented?

@sorenbs sorenbs changed the title Cascading Deletes Discussion: Cascading Deletes Nov 12, 2017
@sorenbs
Copy link
Member Author

sorenbs commented Nov 12, 2017

@emolr I think the ability to update multiple nodes in a single mutation is what you want. See https://github.com/graphcool/framework/issues/81 :-)

@sorenbs
Copy link
Member Author

sorenbs commented Nov 12, 2017

Thanks for the input everyone! I have written up a proposal here: https://github.com/graphcool/framework/issues/1262

It is a traditional approach inspired by cascading referential integrity constraints from SQL servers. Specifically it does not specify a belongs to relationship with all the If a child entity is removed from its relationship with the parent entity, delete it property described by @danmkent in https://github.com/graphcool/framework/issues/47#issuecomment-316421924 as I think this particular case is better handled by https://github.com/graphcool/framework/issues/1160

Please have a look and add comments in the new issue

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests