Gathering detailed insights and metrics for objection-js-soft-delete
Gathering detailed insights and metrics for objection-js-soft-delete
Gathering detailed insights and metrics for objection-js-soft-delete
Gathering detailed insights and metrics for objection-js-soft-delete
npm install objection-js-soft-delete
Typescript
Module System
Node Version
NPM Version
JavaScript (99.87%)
Shell (0.13%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
15 Stars
378 Commits
5 Forks
2 Watchers
15 Branches
3 Contributors
Updated on May 07, 2024
Latest Version
3.0.5
Package Id
objection-js-soft-delete@3.0.5
Unpacked Size
11.60 kB
Size
3.95 kB
File Count
4
NPM Version
8.19.2
Node Version
18.12.1
Published on
Mar 01, 2023
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
A plugin that adds soft-delete functionality to Objection.js
1npm i objection-js-soft-delete
1yarn add objection-js-soft-delete
The mixin provides the following configuration to override the default options:
columnName: the column name that indicate if the record is deleted. The column must exist on the table for the model.
Default: 'deleted_at'
deletedValue: define which value indicate if the record is deleted.
Default: new Date()
(local time zone of the server)
It's also possible to use the time from the database: knex.fn.now()
notDeletedValue: define which value indicate if the record is not deleted. You can set (and should) this option along with deletedValue
.
Default: NULL
1// Import objection and the plugin. 2import { Model } from 'objection'; 3import objectionSoftDelete from 'objection-js-soft-delete'; 4 5// Specify the options for this plugin. This are the defaults. 6const softDelete = objectionSoftDelete({ 7 columnName: 'deleted_at', 8 deletedValue: new Date(), 9 notDeletedValue: null, 10}); 11 12// Inject the plugin to the model 13class User extends softDelete(Model) { 14 static get tableName() { 15 return 'Users'; 16 } 17}
Note: A deletedValue
value of NULL
will result in this plugin an unexpected behavior.
1await User.query().where('id', 1).delete(); 2await User.query().deleteById(1); 3 4// Deleted rows are still in the db: 5// User { id: 1, deleted_at: 'Sat Oct 31 2020 15:42:29 GMT+0100 (Central European Standard Time)' , ... }
1const notDeletedUsers = await User.query().whereNotDeleted();
1const deletedUsers = await User.query().whereDeleted();
1await User.query().where('id', 1).undelete(); 2// User { id: 1, deleted_at: null }
1await User.query.where('id', 1).hardDelete();
A notDeleted
and a deleted
filter will be added to the list of named filters for any model that use this mixin. Internally they are using the methods .whereNotDeleted()
and .whereDeleted()
from above:
1// withGraphFetched
2const rows = await User.query().withGraphFetched('contact(notDeleted)');
3// withGraphJoined
4const rows = await User.query().withGraphJoined('contact(notDeleted)');
1// withGraphFetched
2const rows = await User.query().withGraphFetched('contact(deleted)');
3// withGraphJoined
4const rows = await User.query().withGraphJoined('contact(deleted)');
1class User extends Model { 2 static get tableName() { 3 return 'user'; 4 } 5 6 static get relationMappings() { 7 const Contact = require('./Contact'); 8 9 return { 10 contact: { 11 relation: Model.ManyToManyRelation, 12 modelClass: Contact, 13 join: { 14 from: 'user.id', 15 through: { 16 from: 'user_contact.user_id', 17 to: 'user_contact.contact_id', 18 }, 19 to: 'contact.id', 20 }, 21 // .whereNotDeleted() or .whereDeleted() 22 filter: (f) => f.whereNotDeleted(), 23 }, 24 }; 25 } 26}
then:
1// Will return only records from the relationship contact that are not deleted
2await User.query().withGraphFetched('contact');
This plugin was actually born out of a need to have .upsertGraph()
soft delete in some tables, and hard delete in others.
1// a model with soft delete 2class Phone extends softDelete(Model) { 3 static get tableName() { 4 return 'Phones'; 5 } 6} 7 8// a model without soft delete 9class Email extends Model { 10 static get tableName() { 11 return 'Emails'; 12 } 13} 14 15// assume a User model that relates to both, and the following existing data: 16User { 17 id: 1, 18 name: 'Johnny Cash', 19 phones: [ 20 { 21 id: 6, 22 number: '+19195551234', 23 }, 24 ], 25 emails: [ 26 { 27 id: 3, 28 address: 'mib@americanrecords.com', 29 }, 30 ] 31} 32 33await User.query().upsertGraph({ 34 id: 1, 35 name: 'Johnny Cash', 36 phones: [], 37 emails: [], 38}); 39// => phone id 6 will be flagged deleted (and will still be related to Johnny!), email id 3 will be removed from the database
One issue that comes with doing soft deletes is that your calls to .delete()
will actually trigger lifecycle functions for .update()
, which may not be expected or desired. To help address this, some context flags have been added to the queryContext
that is passed into lifecycle functions to help discern whether the event that triggered (e.g.) $beforeUpdate
was a true update, a soft delete, or an undelete:
1$beforeUpdate(opt, queryContext) { 2 if (queryContext.softDelete) { 3 // do something before a soft delete, possibly including calling your $beforeDelete function. 4 // Think this through carefully if you are using additional plugins, as their lifecycle 5 // functions may execute before this one depending on how you have set up your inheritance chain! 6 } else if (queryContext.undelete) { 7 // do something before an undelete 8 } else { 9 // do something before a normal update 10 } 11} 12 13// same procedure for $afterUpdate
Available flags are:
Flags will be true
if set, and undefined
otherwise.
All models with the soft delete mixin will have an isSoftDelete
property, which returns true
.
1const modelHasSoftDelete = User.isSoftDelete;
Tests can be run with:
1npm test
or:
1yarn test
The linter can be run with:
1npm run lint
or:
1yarn lint
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
Found 1/9 approved changesets -- score normalized to 1
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
license file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
13 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More