Awesome
Adonis Lucid Soft Deletes
Works with AdonisJS v6
Docs for AdonisJS v5
This addon adds the functionality to soft deletes Lucid Models through the deleted_at
flag
Works with
@adonisjs/lucid@^21.1.*
Sometimes use the deleted_at
flag for soft deletes could be not good way. More about it
Introduction
Sometimes you may wish to "no-delete" a model from database.
When models are soft deleted, they are not actually removed from your database.
Instead, a deleted_at
attribute is set on the model indicating the date
and time at which the model was "deleted".
:point_right: The SoftDeletes mixin will automatically add the deleted_at
attribute
as Luxon / DateTime instance.
Installation
Install it using npm
, yarn
or pnpm
.
# npm
npm i adonis-lucid-soft-deletes
# yarn
yarn add adonis-lucid-soft-deletes
# pnpm
pnpm add adonis-lucid-soft-deletes
After install call configure
:
node ace configure adonis-lucid-soft-deletes
Usage
Make sure to register the provider inside adonisrc.ts
file.
providers: [
// ...
() => import('adonis-lucid-soft-deletes/provider'),
]
You should add the deleted_at
column to your database tables for models with soft deletes.
// migrations/1234566666_users.ts
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class Users extends BaseSchema {
protected tableName = 'users'
async up() {
this.schema.createTable(this.tableName, (table) => {
// ...
table.timestamp('deleted_at').nullable()
})
}
// ...
}
Applying Soft Deletes to a Model
import { compose } from '@adonisjs/core/helpers'
import { SoftDeletes } from 'adonis-lucid-soft-deletes'
export default class User extends compose(BaseModel, SoftDeletes) {
// ...columns and props
}
Now, when you call the .delete()
method on the model, the deleted_at
(customDeletedAtColumn
) column
will be set to the current date and time. However, the model's database record will be left in the table.
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class UsersController {
/**
* Delete user by id
* DELETE /users/:id
*/
async destroy({ params, response }: HttpContext) {
const user = await User.findOrFail(params.id)
await user.delete()
return user // or response.noContent()
}
}
:boom: Soft delete only works for model instances.
await User.query().delete()
as before will delete models from database
:point_right: When querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results.
To determine if a given model instance has been soft deleted, you may use the .trashed
getter:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class UsersController {
/**
* Get user by id
* GET /users/:id
*/
async show({ params }: HttpContext) {
const user = await User.withTrashed().where('id', params.id).firstOrFail()
if (user.trashed) {
return response.forbidden()
}
return user
}
}
Set custom column name for deletedAt
import { compose } from '@adonisjs/core/helpers'
import { SoftDeletes } from 'adonis-lucid-soft-deletes'
export default class User extends compose(BaseModel, SoftDeletes) {
// ...columns and props
@column.dateTime({ columnName: 'customDeletedAtColumn' })
declare deletedAt: DateTime | null
}
Restoring Soft Deleted Models
To restore a soft deleted model, you may call the .restore()
method on a model instance.
Also, method .restore()
exists after methods .withTrashed()
and .onlyTrashed()
The restore
method will set the model's deleted_at
column to null
:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class TrashUsersController {
/**
* Update trashed user by id
* PUT /trash/users/:id
*/
async update({ params }: HttpContext) {
const user = await User.withTrashed().where('id', params.id).firstOrFail()
await user.restore()
return user
// or
await User.withTrashed().where('id', params.id).restore()
await User.query().withTrashed().where('id', params.id).restore()
}
}
Permanently Deleting Models
Sometimes you may need to truly remove a model from your database.
You may use the .forceDelete()
method to permanently remove a soft deleted model from the database table:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class UsersController {
/**
* Delete user by id
* DELETE /users/:id
*/
async destroy({ params, response }: HttpContext) {
const user = await User.findOrFail(params.id)
await user.forceDelete()
return response.noContent()
}
}
Including Soft Deleted Models
As noted above, soft deleted models will automatically be excluded from query results.
However, you may force soft deleted models to be included in a query's results
by calling the .withTrashed()
method on the model:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class UsersController {
/**
* Get a list users
* GET /users?withTrashed=1
*/
async index({ request }: HttpContext) {
const usersQuery = request.input('withTrashed')
? User.withTrashed()
: User.query()
return usersQuery.exec()
// or
return User.query().if(request.input('withTrashed'), (query) => {
query.withTrashed()
}).exec()
}
}
Retrieving only Soft Deleted Models
The .onlyTrashed()
method will retrieve only soft deleted models:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
export default class TrashUsersController {
/**
* Get a list trashed users
* GET /trash/users
*/
async index({ request }: HttpContext) {
return User.onlyTrashed().exec()
}
}
Soft Deletes methods
Methods .withTrashed()
, .onlyTrashed()
and .restore()
also available
in ModelQueryBuilder for models with soft delete, example:
await User.query().withTrashed().exec()
await User.query().onlyTrashed().restore()