Skip to content

Commit

Permalink
Add deletedAt feature
Browse files Browse the repository at this point in the history
  • Loading branch information
clovis-maniguet committed Jul 13, 2018
1 parent 52cffe1 commit 01be6ff
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 10,728 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ index.js
index.js.map
time-stamp.js
time-stamp.js.map
package-lock\.json
33 changes: 9 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
[![NPM](https://nodei.co/npm/loopback-ds-timestamp-mixin.png?compact=true)](https://nodei.co/npm/loopback-ds-timestamp-mixin/)

[![dependencies](https://img.shields.io/david/clarkbw/loopback-ds-timestamp-mixin.svg)]()
[![devDependencies](https://img.shields.io/david/dev/clarkbw/loopback-ds-timestamp-mixin.svg)]()
[![Build Status](https://travis-ci.org/clarkbw/loopback-ds-timestamp-mixin.svg?branch=master)](https://travis-ci.org/clarkbw/loopback-ds-timestamp-mixin)
[![Coverage Status](https://coveralls.io/repos/clarkbw/loopback-ds-timestamp-mixin/badge.svg)](https://coveralls.io/r/clarkbw/loopback-ds-timestamp-mixin)

TIMESTAMPS
=============

This module is designed for the [Strongloop Loopback](https://github.com/strongloop/loopback) framework. It automatically adds `createdAt` and `updatedAt` attributes to any Model.
This module is designed for the [Strongloop Loopback](https://github.com/strongloop/loopback) framework. It automatically adds `createdAt`, `updatedAt` and `deletedAt` attributes to any Model.

`createdAt` will be set to the current Date the by using the default property of the attribute.

`updatedAt` will be set for every update of an object through bulk `updateAll` or instance `model.save` methods.

`deletedAt` will be set for every delete of an object through bulk `deleteAll` or instance `model.delete` methods.

This module is implemented with the `before save` [Operation Hook](http://docs.strongloop.com/display/public/LB/Operation+hooks#Operationhooks-beforesave) which requires the loopback-datasource-juggler module greater than [v2.23.0](strongloop/loopback-datasource-juggler@0002aaedeffadda34ae03752d03d0805ab661665).

INSTALL
Expand All @@ -23,11 +18,6 @@ INSTALL
npm i loopback-ds-timestamp-mixin --save
```

UPSERT ISSUES
=============

With version 2.33.2 of this module the [upsert validation was turned off](https://github.com/clarkbw/loopback-ds-timestamp-mixin/blob/master/es6/time-stamp.js#L16). This may create issues for your project if upsert validation is required. If you require upsert validation, set the `validateUpsert` option to true, however most upserts will fail unless you supply the `createdAt` and `updatedAt` fields or set `required` option to false.

SERVER CONFIG
=============

Expand All @@ -44,7 +34,7 @@ Add the `mixins` property to your `server/model-config.json`:
],
"mixins": [
"loopback/common/mixins",
"../node_modules/loopback-ds-timestamp-mixin",
"../node_modules/loopback-timestamp-mixin",
"../common/mixins"
]
}
Expand Down Expand Up @@ -73,16 +63,12 @@ To use with your Models add the `mixins` attribute to the definition object of y
MODEL OPTIONS
=============

The attribute names `createdAt` and `updatedAt` are configurable. To use different values for the default attribute names add the following parameters to the mixin options.
The attribute names `createdAt`, `updatedAt` and `deletedAt` are configurable. To use different values for the default attribute names add the following parameters to the mixin options.

You can also configure whether `createdAt` and `updatedAt` are required or not. This can be useful when applying this mixin to existing data where the `required` constraint would fail by default.

By setting the `validateUpsert` option to true you will prevent this mixin from overriding the default Model settings. With validation turned on most upsert operations will fail with validation errors about missing the required fields like `createdAt` or `updatedAt`.
You can also configure whether `createdAt`, `updatedAt` and `deletedAt` are required or not. This can be useful when applying this mixin to existing data where the `required` constraint would fail by default.

This mixin uses console logs to warn you whenever something might need your attention. If you would prefer not to receive these warnings, you can disable them by setting the option `silenceWarnings` to `true` on a per model basis.

In this example we change `createdAt` and `updatedAt` to `createdOn` and `updatedOn`, respectively. We also change the default `required` to `false` and set `validateUpsert` to true. We also disable console warnings with `silenceWarnings`.

```json
{
"name": "Widget",
Expand All @@ -93,10 +79,9 @@ In this example we change `createdAt` and `updatedAt` to `createdOn` and `update
},
"mixins": {
"TimeStamp" : {
"createdAt" : "createdOn",
"updatedAt" : "updatedOn",
"required" : false,
"validateUpsert": true,
"createdAt" : "created_at",
"updatedAt" : "updated_at",
"deletedAt" : "deleted_at",
"silenceWarnings": true
}
}
Expand Down
36 changes: 36 additions & 0 deletions es6/time-stamp.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default (Model, bootOptions = {}) => {
const options = Object.assign({
createdAt: 'createdAt',
updatedAt: 'updatedAt',
deletedAt: 'deletedAt',
required: true,
validateUpsert: false, // default to turning validation off
silenceWarnings: false,
Expand Down Expand Up @@ -41,6 +42,19 @@ export default (Model, bootOptions = {}) => {
required: options.required,
});

Model.defineProperty(options.deletedAt, {
type: Date,
required: false,
mysql: {
columnName: options.deletedAt,
dataType: "timestamp",
dataLength: null,
dataPrecision: null,
dataScale: null,
nullable: "Y"
}
});

Model.observe('before save', (ctx, next) => {
debug('ctx.options', ctx.options);
if (ctx.options && ctx.options.skipUpdatedAt) { return next(); }
Expand All @@ -54,6 +68,28 @@ export default (Model, bootOptions = {}) => {
}
return next();
});

/**
* Watches destroyAll(), deleteAll(), destroyById() , deleteById(), prototype.destroy(), prototype.delete() methods
* and instead of deleting object, sets properties deletedAt and isDeleted.
*/
Model.observe('before delete', function (ctx, next) {
Model.updateAll(ctx.where, {[options.deletedAt]: new Date()}).then(function (result) {
next(null);
});
});

/**
* When ever model tries to access data, we add by default isDeleted: false to where query
* if there is already in query isDeleted property, then we do not modify query
*/
Model.observe('access', function (ctx, next) {
if (!ctx.query.isDeleted && (!ctx.query.where || ctx.query.where && JSON.stringify(ctx.query.where).indexOf('isDeleted') == -1)) {
if (!ctx.query.where) ctx.query.where = {};
ctx.query.where[options.deletedAt] = null;
}
next();
});
};

module.exports = exports.default;
Loading

0 comments on commit 01be6ff

Please sign in to comment.