Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduced whereDeleted & whereNotDeleted functions to use custom compare methods #237

Open
wants to merge 8 commits into
base: 235-soft-delete-saves-in-created_at-the-timestamp-of-the-last-restart-of-the-server
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
node_modules
tests/test.db
dist
tests/test.db
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ const softDelete = objectionSoftDelete({
columnName: 'deleted_at',
deletedValue: new Date(),
notDeletedValue: null,
});
// You can optionally specify custom rules for whereDeleted or whereNotDeleted
whereNotDeleted: () => {
return Model.query().where('deleted_at', '>', moment().toISOString());
},
whereDeleted: () => {
return Model.query().whereNot('deleted_at', '>', moment().toISOString());
},
})(Model);

// Inject the plugin to the model
class User extends softDelete(Model) {
Expand Down
93 changes: 93 additions & 0 deletions dist/softDelete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
const softDelete = incomingOptions => {
const options = {
columnName: 'deleted_at',
deletedValue: () => new Date(),
notDeletedValue: () => null,
...incomingOptions
};
return Model => {
class SDQueryBuilder extends Model.QueryBuilder {
// override the normal delete function with one that patches the row's "deleted" column
delete() {
this.context({
softDelete: true
});
const patch = {};
patch[options.columnName] = options.deletedValue();
return this.patch(patch);
}

// provide a way to actually delete the row if necessary
hardDelete() {
return super.delete();
}

// provide a way to undo the delete
undelete() {
this.context({
undelete: true
});
const patch = {};
patch[options.columnName] = options.notDeletedValue();
return this.patch(patch);
}

// provide a way to filter to ONLY deleted records without having to remember the column name
whereDeleted() {
const columnRef = this.modelClass().ref(options.columnName);
// this if is for backwards compatibility, to protect those that used a nullable `deleted` field
if (options.deletedValue === true) {
return this.where(columnRef, options.deletedValue());
}

// use custom whereDeleted function if specified
if (typeof options.whereDeleted === 'function') {
return options.whereDeleted(this, columnRef);
} else {
// qualify the column name
return this.whereNot(columnRef, options.notDeletedValue());
}
}

// provide a way to filter out deleted records without having to remember the column name
whereNotDeleted() {
const columnRef = this.modelClass().ref(options.columnName);

// use custom whereDeleted function if specified
if (typeof options.whereNotDeleted === 'function') {
return options.whereNotDeleted(this, columnRef);
} else {
// qualify the column name
return this.where(columnRef, options.notDeletedValue());
}
}
}
return class extends Model {
static get QueryBuilder() {
return SDQueryBuilder;
}
static get modifiers() {
return {
...super.modifiers,
notDeleted(builder) {
builder.whereNotDeleted();
},
deleted(builder) {
builder.whereDeleted();
}
};
}
static get isSoftDelete() {
return true;
}
};
};
};
var _default = softDelete;
exports.default = _default;
18 changes: 10 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
declare module 'objection-js-soft-delete' {
import { Model, QueryBuilder } from 'objection';
declare module 'objection-js-soft-delete' {
import { Model, QueryBuilder, ReferenceBuilder, ReferenceFunction } from 'objection';

class SoftDeleteQueryBuilder<M extends Model, R = M[]> extends QueryBuilder<M, R> {
ArrayQueryBuilderType: SoftDeleteQueryBuilder<M>;

NumberQueryBuilderType: SoftDeleteQueryBuilder<M, number>;

delete(): this['NumberQueryBuilderType'];
hardDelete(): this['NumberQueryBuilderType'];
undelete(): this['NumberQueryBuilderType'];
whereDeleted(): this['ArrayQueryBuilderType'];
whereNotDeleted(): this['ArrayQueryBuilderType'];
}

interface SoftDeleteInstance<T extends typeof Model> {
//@ts-ignore
QueryBuilderType: SoftDeleteQueryBuilder<this, this[]>;
}

interface SoftDeleteStatic<T extends typeof Model> {
QueryBuilder: typeof SoftDeleteQueryBuilder;
isSoftDelete: boolean;
namedFilters(): object;
new (): SoftDeleteInstance<T> & T['prototype'];
}

export default function softDelete<T extends typeof Model>(
options?: Partial<{
columnName: string;
deletedValue: () => Date | boolean | number;
notDeletedValue: () => boolean | null;
whereDeleted: (qb: QueryBuilder<InstanceType<T>>, columnRef: ReferenceBuilder ) => QueryBuilder<InstanceType<T>>;
whereNotDeleted: (qb: QueryBuilder<InstanceType<T>>, columnRef: ReferenceBuilder ) => QueryBuilder<InstanceType<T>>;
}>,
): (model: T) => Omit<T, 'new'> & SoftDeleteStatic<T>;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "objection-js-soft-delete",
"version": "4.0.0-beta.0",
"version": "4.0.3-beta.0",
"description": "A plugin for objection js that supports soft delete",
"main": "dist/softDelete.js",
"types": "./index.d.ts",
Expand Down
22 changes: 16 additions & 6 deletions src/softDelete.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const softDelete = (incomingOptions) => {
notDeletedValue: () => null,
...incomingOptions,
};

return (Model) => {
class SDQueryBuilder extends Model.QueryBuilder {
// override the normal delete function with one that patches the row's "deleted" column
Expand Down Expand Up @@ -40,15 +39,27 @@ const softDelete = (incomingOptions) => {
if (options.deletedValue === true) {
return this.where(columnRef, options.deletedValue());
}
// qualify the column name
return this.whereNot(columnRef, options.notDeletedValue());

// use custom whereDeleted function if specified
if (typeof options.whereDeleted === 'function') {
return options.whereDeleted(this, columnRef);
} else {
// qualify the column name
return this.whereNot(columnRef, options.notDeletedValue());
}
}

// provide a way to filter out deleted records without having to remember the column name
whereNotDeleted() {
const columnRef = this.modelClass().ref(options.columnName);
// qualify the column name
return this.where(columnRef, options.notDeletedValue());

// use custom whereDeleted function if specified
if (typeof options.whereNotDeleted === 'function') {
return options.whereNotDeleted(this, columnRef);
} else {
// qualify the column name
return this.where(columnRef, options.notDeletedValue());
}
}
}
return class extends Model {
Expand All @@ -66,7 +77,6 @@ const softDelete = (incomingOptions) => {
},
};
}

static get isSoftDelete() {
return true;
}
Expand Down