soft_delete.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package localmixin
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "entgo.io/ent"
  7. "entgo.io/ent/dialect/entsql"
  8. "entgo.io/ent/dialect/sql"
  9. "entgo.io/ent/schema/field"
  10. "entgo.io/ent/schema/mixin"
  11. gen "wechat-api/ent"
  12. "wechat-api/ent/hook"
  13. "wechat-api/ent/intercept"
  14. )
  15. // SoftDeleteMixin implements the soft delete pattern for schemas.
  16. type SoftDeleteMixin struct {
  17. mixin.Schema
  18. }
  19. // Fields of the SoftDeleteMixin.
  20. func (SoftDeleteMixin) Fields() []ent.Field {
  21. return []ent.Field{
  22. field.Time("deleted_at").
  23. Optional().
  24. Comment("Delete Time | 删除日期").
  25. Annotations(entsql.WithComments(true)),
  26. }
  27. }
  28. type softDeleteKey struct{}
  29. // SkipSoftDelete returns a new context that skips the soft-delete interceptor/mutators.
  30. func SkipSoftDelete(parent context.Context) context.Context {
  31. return context.WithValue(parent, softDeleteKey{}, true)
  32. }
  33. // Interceptors of the SoftDeleteMixin.
  34. func (d SoftDeleteMixin) Interceptors() []gen.Interceptor {
  35. return []gen.Interceptor{
  36. intercept.TraverseFunc(func(ctx context.Context, q intercept.Query) error {
  37. // Skip soft-delete, means include soft-deleted entities.
  38. if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
  39. return nil
  40. }
  41. d.P(q)
  42. return nil
  43. }),
  44. }
  45. }
  46. // Hooks of the SoftDeleteMixin.
  47. func (d SoftDeleteMixin) Hooks() []gen.Hook {
  48. return []gen.Hook{
  49. hook.On(
  50. func(next gen.Mutator) gen.Mutator {
  51. return gen.MutateFunc(func(ctx context.Context, m gen.Mutation) (gen.Value, error) {
  52. // Skip soft-delete, means delete the entity permanently.
  53. if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
  54. return next.Mutate(ctx, m)
  55. }
  56. mx, ok := m.(interface {
  57. SetOp(gen.Op)
  58. Client() *gen.Client
  59. SetDeletedAt(time.Time)
  60. WhereP(...func(*sql.Selector))
  61. })
  62. if !ok {
  63. return nil, fmt.Errorf("unexpected mutation type %T", m)
  64. }
  65. d.P(mx)
  66. mx.SetOp(gen.OpUpdate)
  67. mx.SetDeletedAt(time.Now())
  68. return mx.Client().Mutate(ctx, m)
  69. })
  70. },
  71. gen.OpDeleteOne|gen.OpDelete,
  72. ),
  73. }
  74. }
  75. // P adds a storage-level predicate to the queries and mutations.
  76. func (d SoftDeleteMixin) P(w interface{ WhereP(...func(*sql.Selector)) }) {
  77. w.WhereP(
  78. sql.FieldIsNull(d.Fields()[0].Descriptor().Name),
  79. )
  80. }