ent icon indicating copy to clipboard operation
ent copied to clipboard

Feature Request: Soft Deletes

Open errorhandler opened this issue 6 years ago • 11 comments

Are there any plans to support "soft" deletes? That is, assuming the File schema has a deleted_at column, the code:

client.File.
	Delete().
	Where(file.UpdatedAtLT(date))
	Exec(ctx)

Would execute (approximately):

UPDATE files SET deleted_at = NOW() WHERE updated_at < ?

and

client.File.
	Query().
	All(ctx)

Would execute (approximately):

SELECT * FROM files WHERE deleted_at IS NULL

errorhandler avatar Dec 17 '19 23:12 errorhandler

This is good feature, but i see two ways how to implement it, with possibility to gain more flexibility:

  1. Create a some kind of flag in entity declaration, that will works as a stated above (not universal)
  2. Create a some kind of flexible Mixin, that can intercept queries and patch them to add custom logic.

The second is more flexible, but also more complicated. For example, we create a SoftDelete mixin.

type SoftDelete struct{}

func (SoftDelete) Fields() []ent.Field {
    return field.Time("deleted_at").Optional()
}

Now we add interceptors to Delete and Query query builders, that will entercepts and patch queries. It is important that DeleteQuery should be able to be patched into UpdateQuery, so that delete is basically not even happen.

func (SoftDelete) Delete() ent.Builder { 
    // here we return Update statement, that is extends delete with all the WHERE condtions, but providing a SET instruction to update single field
    return builder.Update().SetDeletedAt(time.Now())
}

func (SoftDelete) Query() ent.Builder {
    // here we return patched Query, that just add a ... deleted_at IS NULL
    return builder.Query().Where(
        softdelete.DeletedAt
    )
}

So basically query that was:

DELETE FROM pets WHERE id = 1

become

UPDATE pets SET deleted_at = ? WHERE id = ?

And query that was, for example:

SELECT * FROM pets WHERE name = ? AND age = ?

become

SELECT * FROM pets WHERE (name = ? AND age = ?) AND deleted_at IS NULL

Pros:

  • can create any kind of Mixin that can patch our requests
    • increment field on update to see how many times entity was updated
    • lazy migration, user updates fullname, we split it into first_name and last_name

Cons:

  • too complicated
  • queries can be patched wrong way so we get undefined behavior that difficult to debug
  • probably many others that did not come to my mind

danf0rth avatar Jan 20 '20 13:01 danf0rth

What about Default Fields? I.e. in most common cases, this is "Id", "CreatedAt", "UpdatedAt", "DeletedAt".

covrom avatar Feb 27 '20 10:02 covrom

At least we need multi-key unique constraints (some_key, deleted_by).

lixin9311 avatar Apr 24 '20 20:04 lixin9311

Any plan for this feature?

cgfork avatar Nov 09 '20 10:11 cgfork

May relatated with https://github.com/ent/ent/issues/833

goxiaoy avatar Mar 31 '21 10:03 goxiaoy

i'm now make template to do this https://github.com/ent/ent/issues/1474

godcong avatar May 08 '21 12:05 godcong

Any news about it ? Will be this available some time soon ?

daniel-safeup avatar Nov 18 '21 06:11 daniel-safeup

is there any news?

bingoIsCoder avatar May 29 '22 12:05 bingoIsCoder

@a8m, hey! This feature request still actual. ((

sashamelentyev avatar Jun 01 '22 14:06 sashamelentyev

This requirement is necessary because it is unlikely that any of the project's data will be completely erased. Preferably a globally configurable feature. @a8m Is there a plan?

gmars avatar Jun 16 '22 06:06 gmars

I'm trying the same thing, look at what I did as so far: https://github.com/ent/ent/issues/2850

mirusky avatar Aug 13 '22 21:08 mirusky

Checking on this, definitely high-priority

talglobus avatar Nov 18 '22 20:11 talglobus

Hey all! Interceptors were added to Ent, and you can implement something like soft-delete with a shared Mixin in your project. Please, check out https://entgo.io/docs/interceptors#soft-delete and feel free to join our Discord and ping me if you have any troubles with it.

a8m avatar Dec 19 '22 08:12 a8m