Skip to content

Instantly share code, notes, and snippets.

@oldmonad
Forked from marianozunino/soft-delete-obj.ts
Created July 20, 2022 03:34
Show Gist options
  • Save oldmonad/c24bc6e2954d49e55ff59dc035e62c60 to your computer and use it in GitHub Desktop.
Save oldmonad/c24bc6e2954d49e55ff59dc035e62c60 to your computer and use it in GitHub Desktop.
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { Model, Page, QueryBuilder } from 'objection';
type Options = {
columnName?: string;
deletedValue?: Date;
};
let options: Options;
export class DeleteQueryBuilder<M extends Model, R = M[]> extends QueryBuilder<M, R> {
// These are necessary. You can just copy-paste them and change the
// name of the query builder class.
public ArrayQueryBuilderType!: DeleteQueryBuilder<M, M[]>;
public SingleQueryBuilderType!: DeleteQueryBuilder<M, M>;
public MaybeSingleQueryBuilderType!: DeleteQueryBuilder<M, M | undefined>;
public NumberQueryBuilderType!: DeleteQueryBuilder<M, number>;
public PageQueryBuilderType!: DeleteQueryBuilder<M, Page<M>>;
public execute(): Promise<R> {
if (this.isFind() && !this.context().includeDeleted) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const tableRef = this.tableRefFor(this.modelClass()); // qualify the column name
void this.whereNull(`${tableRef}.${options.columnName}`);
}
return super.execute();
}
public delete(): this['NumberQueryBuilderType'] {
void this.context({
deletedAt: new Date(),
});
const patch = {};
patch[options.columnName] = options.deletedValue;
return this.patch(patch);
}
public hardDelete(): this['NumberQueryBuilderType'] {
return super.delete();
}
public undelete(): this['NumberQueryBuilderType'] {
void this.context({
undelete: true,
});
const patch = {};
patch[options.columnName] = null;
return this.patch(patch);
}
public includeDeleted(): this {
return this.context({ includeDeleted: true });
}
}
type Constructor<T> = new (...args: any[]) => T;
export const SoftDeleteMixin = (passedOptions?: Options) => {
options = {
columnName: 'deletedAt',
deletedValue: new Date(),
...passedOptions,
};
return function <T extends Constructor<Model>>(Base: T): T {
return class extends Base {
public QueryBuilderType!: DeleteQueryBuilder<this>;
public static QueryBuilder = DeleteQueryBuilder;
public static modifiers = {
includeDeleted(query: DeleteQueryBuilder<Model>): void {
void query.includeDeleted();
},
};
};
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment