NestboltNestbolt

@nestbolt/soft-delete

Configuration

SoftDeleteModule.forRoot()/forRootAsync() options and the full SoftDeleteService API.

forRoot

SoftDeleteModule.forRoot() registers SoftDeleteService and the SoftDeleteSubscriber globally:

import { SoftDeleteModule } from "@nestbolt/soft-delete";

@Module({
  imports: [SoftDeleteModule.forRoot()],
})
export class AppModule {}

Options

OptionTypeDefaultDescription
columnNamestring"deleted_at"Default name of the timestamp column used for soft deletion.
SoftDeleteModule.forRoot({
  columnName: "deleted_at",
});

Per-entity overrides defined via the @SoftDeletable({ columnName }) decorator take priority over this global default.

forRootAsync

Use forRootAsync() when you need module setup to depend on other providers (e.g., ConfigService):

import { ConfigModule, ConfigService } from "@nestjs/config";
import { SoftDeleteModule } from "@nestbolt/soft-delete";

@Module({
  imports: [
    ConfigModule.forRoot(),
    SoftDeleteModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        columnName: config.get("SOFT_DELETE_COLUMN", "deleted_at"),
      }),
    }),
  ],
})
export class AppModule {}

forRootAsync Options

OptionTypeDescription
importsany[]Modules to import for dependency injection
injectany[]Providers to inject into the factory function
useFactory(...args) => SoftDeleteModuleOptions | Promise<SoftDeleteModuleOptions>Factory function that returns the options

SoftDeleteService API

SoftDeleteService is available via dependency injection after module registration:

@Injectable()
export class MyService {
  constructor(private readonly softDelete: SoftDeleteService) {}
}

All mutation methods take the entity constructor as the first argument so the service can resolve the deleted-at column for that entity from TypeORM metadata.

softDelete(Entity, id)

Sets the deleted-at column to new Date() for the row with the given id:

await softDelete.softDelete(Post, post.id);

Emits soft-delete.deleted.

restore(Entity, id)

Sets the deleted-at column back to NULL:

await softDelete.restore(Post, post.id);

Emits soft-delete.restored.

forceDelete(Entity, id)

Issues a real DELETE for the row -- the row is physically removed from the table:

await softDelete.forceDelete(Post, post.id);

Emits soft-delete.force-deleted.

withTrashed(Entity, alias?)

Returns a SelectQueryBuilder<T> that selects from the entity's table without filtering on the deleted-at column. The default alias is the lowercase class name:

const all = await softDelete.withTrashed(Post).getMany();
const all = await softDelete.withTrashed(Post, "post")
  .andWhere("post.title LIKE :q", { q: "%news%" })
  .getMany();

This is the same as repo.createQueryBuilder() -- it's provided as a paired API with onlyTrashed() for symmetry.

onlyTrashed(Entity, alias?)

Returns a SelectQueryBuilder<T> that filters down to rows where the deleted-at column is not NULL:

const trashed = await softDelete.onlyTrashed(Post).getMany();
const old = await softDelete
  .onlyTrashed(Post, "post")
  .andWhere("post.createdAt < :cutoff", { cutoff })
  .getMany();

isSoftDeletable(Entity)

Returns true if the entity class is decorated with @SoftDeletable():

softDelete.isSoftDeletable(Post);             // true
softDelete.isSoftDeletable(SomeOtherEntity);  // false

getColumnName(Entity?)

Resolves the deleted-at column name for an entity. If the entity has a @SoftDeletable({ columnName }) override, that wins; otherwise the module-level columnName is returned, falling back to "deleted_at":

softDelete.getColumnName(Post);     // "deleted_at"
softDelete.getColumnName(Article);  // "removed_at" (per-entity override)
softDelete.getColumnName();         // module-level default

getPropertyName(Entity)

Resolves the entity property that maps to the deleted-at column. Reads TypeORM column metadata and falls back to "deletedAt" if the entity isn't registered with the DataSource or has no column with the resolved name:

softDelete.getPropertyName(Post); // "deletedAt"

This is mostly used internally by the mixin to write the local property after a remote update.

getOptions()

Returns the resolved SoftDeleteModuleOptions passed to forRoot() / forRootAsync():

const options = softDelete.getOptions();

Static: SoftDeleteService.getInstance()

Returns the active SoftDeleteService instance, or null if the module hasn't been initialized. This is what the mixin and subscriber use internally to bridge entity-side calls to the service:

const service = SoftDeleteService.getInstance();

You normally don't need to call this directly -- prefer dependency injection or the mixin methods.