mikro-orm-recycle-bin
v1.0.0
Published
A MikroORM-based soft delete library for TypeScript that moves soft-deleted entities into a recycle bin table using decorators.
Maintainers
Readme
MikroORM Recycle Bin ♻️
A MikroORM-based soft-delete library for TypeScript that automatically moves soft-deleted (or hard-deleted) entities into a dedicated recycle bin table.
Unlike traditional soft-delete implementations that simply hide records with a deleted_at flag, this library physically moves the data to a separate table. This keeps your main tables lean and optimized while ensuring that deleted data is safely archived and recoverable.
✨ Features
- Automatic Archiving: Moves entities to a recycle bin table upon deletion or soft-delete.
- Auto Table Creation: Automatically creates the recycle bin table with the correct schema if it doesn't exist, mirroring the entity's structure.
- Flexible Triggers: Supports both hard deletes (
em.remove()) and soft-delete updates (e.g., setting adeleted_attimestamp). - Schema Support: Supports custom database schemas for the recycle bin tables (e.g.,
archive.user_history). - MikroORM Integration: Plugs directly into the MikroORM lifecycle using an
EventSubscriber. - Lightweight: Zero external dependencies (besides MikroORM and its Knex-based drivers).
📋 Requirements
- MikroORM v6+ (may work with v5, but tested on v6)
- Knex-based driver (primarily PostgreSQL, also supports MySQL/MariaDB)
- TypeScript
🚀 Installation
npm install mikro-orm-recycle-bin🛠️ Usage
1. Define your Entity
Use the @RecycleBin() decorator to mark an entity for the recycle bin.
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";
import { RecycleBin } from "mikro-orm-recycle-bin";
@Entity()
@RecycleBin({
tableName: "user_recycle_bin", // Target table for deleted records
columnName: "deleted_at", // The property/column that triggers soft-delete move
schema: "recycle_bin", // Optional: separate schema for the bin
})
export class User {
@PrimaryKey()
id!: number;
@Property()
username!: string;
@Property({ nullable: true })
deletedAt?: Date;
}2. Register the Subscriber
Register the RecycleBinSubscriber in your MikroORM configuration.
import { MikroORM } from "@mikro-orm/postgresql";
import { RecycleBinSubscriber } from "mikro-orm-recycle-bin";
const orm = await MikroORM.init({
entities: [User],
dbName: "my_db",
subscribers: [new RecycleBinSubscriber()], // Add it here
});💡 How it works
The RecycleBinSubscriber listens to the onFlush event. When an entity with the @RecycleBin decorator is encountered during a flush:
- Detection:
- Hard Delete: If the entity is being deleted via
em.remove(entity). - Soft Delete: If the entity is being updated and the property specified in
columnName(e.g.,deletedAt) has a truthy value in the changeset payload.
- Hard Delete: If the entity is being deleted via
- Archiving:
- It checks if the target recycle bin table exists; if not, it automatically creates it based on the entity's metadata (columns, types, etc.).
- It inserts the current entity data (all mapped fields) into the recycle bin table.
- If it was a soft-delete update, it removes the record from the original table to complete the "move" operation.
🏗️ Examples
Simple Deletion (Hard Delete)
When you use em.remove(), the subscriber intercepts the deletion and moves the data to the recycle bin before it's gone forever.
const user = await em.findOneOrFail(User, 1);
await em.removeAndFlush(user);
// User is now in 'user_recycle_bin' table and removed from 'user' table.Soft-Delete Move
If you prefer to trigger the move by setting a timestamp:
const user = await em.findOneOrFail(User, 1);
user.deletedAt = new Date();
await em.flush();
// User is now in 'user_recycle_bin' table and removed from 'user' table.NestJS Integration
Integrating with @mikro-orm/nestjs is straightforward:
// app.module.ts
import { MikroOrmModule } from "@mikro-orm/nestjs";
import { RecycleBinSubscriber } from "mikro-orm-recycle-bin";
@Module({
imports: [
MikroOrmModule.forRoot({
// … your config
subscribers: [new RecycleBinSubscriber()],
}),
],
})
export class AppModule {}⚙️ Configuration Options
The @RecycleBin() decorator accepts the following options:
| Option | Type | Description |
|:-------------|:---------|:--------------------------------------------------------------------------------------------------------------|
| tableName | string | Required. The name of the table where deleted records will be stored. |
| columnName | string | Required. The entity property name (or database column name) that triggers a soft-delete move when set. |
| schema | string | Optional. The database schema where the recycle bin table resides. If it doesn't exist, it will be created. |
