- This is for Adonis v4.x
- I'll try to recreate this package for Adonis v5 as well
- It is needed to define .withTrashed()/.onlyTrashed() before using .restore()
- Every query has been changed to use tableName.fieldName format instead of just fieldName due to ambiguous field errors
- Package now works with manyThrough relations
- Due to core Adonis changes 2 tests are failing but are still working as intended
This package allows you to soft delete entries in the DB meaning that they will still be there but will have 'deleted_at' set to some value and as such 'deleted'
Make sure to install it using npm
or yarn
.
# npm
npm i @ksgl/adonis4-soft-deletes
# yarn
yarn add @ksgl/adonis4-soft-deletes
Make sure to register the provider inside start/app.js
file.
const providers = [
...
'@ksgl/adonis4-soft-deletes/providers/SoftDeletesProvider',
...
]
Inside your boot()
method in model
const Model = use('Model')
class Post extends Model {
static boot () {
super.boot()
this.addTrait('@provider:SoftDeletes')
}
}
tableName
Type: string
Description: If you need to define table name before a field name
Default: Whatever the table name is
fieldName
Type: string
Description: If you need to define field name to use when deleting
Default: "deleted_at"
const Model = use('Model')
class Post extends Model {
static boot () {
super.boot()
this.addTrait('@provider:SoftDeletes', { fieldName: "deleted_at", hideSoftDeletedRows: true })
}
}
NOTE: Make sure that your model table has
deleted_at
datetime column (or whatever your fieldName name is)
NOTE: By default it hide any deleted rows, to show deleted rows by default use
hideSoftDeletedRows
= false to disable filtering
NOTE: If the model has this trait, upon delete() we will soft delete, if you want to delete then call forceDelete()
Depending on where you called .delete, .forceDelete(), .restore() you will get either one instance (on Model) or multiple instances (on query) as "someCustomName"
This is a model hook fired before/after .delete()
this.addHook('beforeSoftDelete', async (someCustomName) => {
// Do something
})
this.addHook('afterSoftDelete', async (someCustomName) => {
// Do something
})
This is a default adonis hook fired before/after real delete or in this case .forceDelete()
this.addHook('beforeDelete', async (someCustomName) => {
// Do something
})
this.addHook('afterDelete', async (someCustomName) => {
// Do something
})
This is a default adonis hook but I couldn't find any place where it is used so I've decided to use it for restore()
this.addHook('beforeRestore', async (someCustomName) => {
// Do something
})
this.addHook('afterRestore', async (someCustomName) => {
// Do something
})
NOTE: Upon soft delete/restore we change the $frozen property.
When we want to soft delete a model instance
...
let user = await User.find(1)
await user.delete()
...
When we want to restore a model instance
...
let user = await User.query().withTrashed().where("id",1).first()
await user.restore()
...
When we want to force delete a model instance
...
let user = await User.find(1)
await user.forceDelete()
...
Check if model instance is soft deleted
...
let user = await User.query().withTrashed().where("id",1).first()
let isSoftDeleted = await user.isSoftDeleted()
...
NOTE: Upon delete/restore we DO NOT change the $frozen property since it is not possible
When we want to soft delete using query
...
await User.query()
.where('country_id', 4)
.delete()
...
When we want to restore using query
...
await User.query()
.where('country_id', 4)
.onlyTrashed()
.restore()
...
When we want to force delete using query
...
await User.query()
.where('country_id', 4)
.forceDelete()
...
When we want to fetch non trashed users
...
// We will automatically get only non trashed users
await User.query().fetch()
...
When we want to fetch with trashed users
...
await User.query().withTrashed().fetch()
...
When we want to fetch only trashed users
...
await User.query().onlyTrashed().fetch()
...
When we want to soft delete relations
...
await ownerUser.cars().delete();
...
When we want to restore relations
...
await ownerUser.cars().onlyTrashed().restore();
...
When we want to get non trashed relations
...
await ownerUser.cars().fetch();
...
When we want to get all relations
...
await ownerUser.cars().withTrashed().fetch();
...
When we want to get onlyTrashed relations
...
await ownerUser.cars().onlyTrashed().fetch();
...
There are some additional things required for use with manyThrough
If you have updated_at timestamp available for Model then you need to redefine updatedAtColumn to be tableName.fieldName
...
class User extends Model {
static boot() {
super.boot()
this.addTrait('@provider:SoftDeletes')
}
static get updatedAtColumn() {
return 'users.updated_at'
}
}
...
Special thanks to the creator(s) of AdonisJS for creating such a great framework.