mongoose-update-if-current
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -6,15 +6,20 @@ "use strict"; | ||
schema.set('saveErrorIfNotFound', true); | ||
// Enable the version key if necessary | ||
// Enable document version key if necessary | ||
if (!schema.get('versionKey')) { | ||
schema.set('versionKey', '__v'); | ||
} | ||
// Get version key name | ||
var versionKey = schema.get('versionKey'); | ||
// Add version condition and increment version | ||
// Add pre-save hook to check version | ||
schema.pre('save', function (next) { | ||
this.$where = {}; | ||
this.$where[versionKey] = this[versionKey]; | ||
// Condition the save on the versions matching | ||
this['$where'] = (_a = {}, | ||
_a[versionKey] = this[versionKey], | ||
_a); | ||
// Increment the version once saved | ||
this.increment(); | ||
next(); | ||
var _a; | ||
}); | ||
} | ||
exports.updateIfCurrentPlugin = updateIfCurrentPlugin; |
{ | ||
"name": "mongoose-update-if-current", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "Optimistic concurrency control (OCC) plugin for mongoose", | ||
@@ -8,9 +8,11 @@ "main": "dist/index.js", | ||
"engines": { | ||
"node": ">=4.0.0" | ||
"node": ">=6.0.0" | ||
}, | ||
"scripts": { | ||
"build": "gulp", | ||
"test": "jest", | ||
"coverage": "jest --coverage --no-cache", | ||
"ci": "npm run build && npm run coverage", | ||
"build": "npm run clean && npm run tsc", | ||
"ci": "npm run build && npm test -- --coverage --no-cache", | ||
"clean": "del-cli 'dist/**' '!dist' 'typings/**' '!typings'", | ||
"tsc": "tsc --project tsconfig.json", | ||
"tslint": "tslint --project tsconfig.json", | ||
"prepack": "npm run build && npm test" | ||
@@ -43,17 +45,10 @@ }, | ||
"devDependencies": { | ||
"@types/gulp": "^4.0.5", | ||
"@types/jest": "^22.0.0", | ||
"@types/merge2": "^1.1.4", | ||
"@types/mongoose": "^4.7.32", | ||
"@types/node": "^8.5.5", | ||
"@types/run-sequence": "0.0.30", | ||
"del": "^3.0.0", | ||
"gulp": "^3.9.1", | ||
"gulp-typescript": "^3.2.3", | ||
"@types/mongoose": "^5.0.12", | ||
"@types/node": "^10.0.4", | ||
"del-cli": "^1.1.0", | ||
"jest": "^22.0.4", | ||
"merge2": "^1.2.0", | ||
"mongoose": ">=4.8.0", | ||
"run-sequence": "^2.2.1", | ||
"ts-jest": "^22.0.1", | ||
"ts-node": "^4.1.0", | ||
"ts-node": "^6.0.3", | ||
"tslint": "^5.8.0", | ||
@@ -68,6 +63,6 @@ "tslint-config-airbnb": "^5.4.2", | ||
"jest": { | ||
"setupTestFrameworkScriptFile": "<rootDir>/__tests__/__setup__.ts", | ||
"transform": { | ||
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js" | ||
}, | ||
"mapCoverage": true, | ||
"collectCoverageFrom": [ | ||
@@ -74,0 +69,0 @@ "src/**/*.ts" |
123
README.md
# mongoose-update-if-current | ||
[![Build Status](https://travis-ci.org/eoin-obrien/mongoose-update-if-current.svg?branch=master)](https://travis-ci.org/eoin-obrien/mongoose-update-if-current) | ||
[![NPM version](https://img.shields.io/npm/v/mongoose-update-if-current.svg)](https://www.npmjs.com/package/mongoose-update-if-current) | ||
[![Node version](https://img.shields.io/node/v/mongoose-update-if-current.svg?style=flat)](https://www.npmjs.com/package/mongoose-update-if-current) | ||
[![Version](https://img.shields.io/npm/v/mongoose-update-if-current.svg)](https://www.npmjs.com/package/mongoose-update-if-current) | ||
[![Dependencies](https://david-dm.org/eoin-obrien/mongoose-update-if-current.svg)](https://david-dm.org/eoin-obrien/mongoose-update-if-current) | ||
@@ -11,13 +10,10 @@ [![DevDependencies](https://david-dm.org/eoin-obrien/mongoose-update-if-current/dev-status.svg)](https://david-dm.org/eoin-obrien/mongoose-update-if-current?type=dev) | ||
Optimistic concurrency (OCC) plugin for [mongoose](http://mongoosejs.com) v4.8 and higher. | ||
> Optimistic concurrency control plugin for [Mongoose](http://mongoosejs.com) v4.8 and higher. | ||
Increments document version numbers on each save, and prevents previous versions of a document | ||
from being saved over a newer version. | ||
This plugin brings optimistic concurrency control to Mongoose documents by incrementing document version numbers on each save, and preventing previous versions of a document from being saved over the current version. | ||
Inspired by [this issue](https://github.com/Automattic/mongoose/issues/4004) in the mongoose repo. | ||
Inspired by [issue #4004](https://github.com/Automattic/mongoose/issues/4004) in the Mongoose GitHub repository. | ||
See the `__tests__` directory for examples. | ||
## Installation | ||
## Install | ||
``` | ||
@@ -27,58 +23,109 @@ $ npm install --save mongoose-update-if-current | ||
## Usage | ||
The plugin requires Mongoose v4.8 or higher as a peer dependency. | ||
### With `require()` | ||
## Getting Started | ||
On a single schema: | ||
Import the plugin from the package: | ||
```javascript | ||
/* Using ES2015 imports */ | ||
import { updateIfCurrentPlugin } from 'mongoose-update-if-current'; | ||
/* Using require() */ | ||
var updateIfCurrentPlugin = require('mongoose-update-if-current').updateIfCurrentPlugin; | ||
var mongoose = require('mongoose'); | ||
var mySchema = new mongoose.Schema({ ... }); | ||
mySchema.plugin(updateIfCurrentPlugin); | ||
``` | ||
Globally: | ||
Add it to mongoose as a global plugin, or add it to a single schema: | ||
```javascript | ||
var updateIfCurrentPlugin = require('mongoose-update-if-current').updateIfCurrentPlugin; | ||
var mongoose = require('mongoose'); | ||
/* Global plugin */ | ||
mongoose.plugin(updateIfCurrentPlugin); | ||
mongoose.plugin(updateIfCurrentPlugin); | ||
/* Single schema */ | ||
const mySchema = new mongoose.Schema({ ... }); | ||
mySchema.plugin(updateIfCurrentPlugin); | ||
``` | ||
### With `import` | ||
The plugin will hook into the `save()` function on schema documents to increment the version and check that it matches the version in the database before persisting it. | ||
On a single schema: | ||
**NB:** If the schema does not have a version key, then the plugin will enable the default version key of `__v`. If the schema has a custom version key set, then the plugin will automatically regognise and use it. | ||
## Usage | ||
Let's save a new `Book` to MongoDB. | ||
```javascript | ||
import { updateIfCurrentPlugin } from 'mongoose-update-if-current'; | ||
const mongoose = require('mongoose'); | ||
// Save a new Book document to the database | ||
let book = await new Book({ | ||
title: 'The Prince', | ||
author: 'Niccolò Machiavelli', | ||
}).save(); | ||
``` | ||
const mySchema = new mongoose.Schema({ ... }); | ||
mySchema.plugin(updateIfCurrentPlugin); | ||
Our book document should look something like this: | ||
```javascript | ||
{ | ||
__v: 0, | ||
title: 'The Prince', | ||
author: 'Niccolò Machiavelli', | ||
... | ||
} | ||
``` | ||
Globally: | ||
Now that it's in the database, a user fetches the book and updates it. | ||
```javascript | ||
import { updateIfCurrentPlugin } from 'mongoose-update-if-current'; | ||
const mongoose = require('mongoose'); | ||
let book = await Book.findOne({ title: 'The Prince'}); | ||
book.title = 'Il Principe'; | ||
book = await book.save(); | ||
``` | ||
mongoose.plugin(updateIfCurrentPlugin); | ||
The book document in MongoDB now looks like this: | ||
```javascript | ||
{ | ||
__v: 1, // note the incremented version | ||
title: 'Il Principe', | ||
author: 'Niccolò Machiavelli', | ||
... | ||
} | ||
``` | ||
## Commands | ||
Meanwhile, another user tries to update the book, fetching it before it was updated. | ||
```javascript | ||
// Before the call to save() above, so book.__v is 0 | ||
let book = await Book.findOne({ title: 'The Prince'}); | ||
// Now the other user updates the book, so our version is out of date | ||
// Try to update the book based on the stale version | ||
book.author = 'Niccolò di Bernardo dei Machiavelli'; | ||
book = await book.save(); // throws | ||
``` | ||
npm run build # build the library files | ||
npm run test # run the tests | ||
npm run coverage # run the tests with coverage | ||
npm run prepare # build the library, make sure the tests passes, and then pack the library (creates .tgz) | ||
npm run release # prepare package for next release | ||
``` | ||
When the other user tries to save an out-of-date version of the document to the database, the operation fails and throws an error. | ||
See the `__tests__` directory for more usage examples. | ||
## Caveats | ||
- The plugin manages concurrency when a document is updated using `Document.save()`, but you can still force updates using `Model.update()`, `Model.findByIdAndUpdate()` or `Model.findOneAndUpdate()` if you so desire. | ||
- Due to its reliance on the document version key, this plugin might not be compatible with others that affect this key. | ||
- The plugin causes the document's version to be incremented whenever `save()` is called, contrary to Mongoose's default behaviour. | ||
## Development | ||
The project uses the [AirBnB JavaScript code style](https://github.com/airbnb/javascript) adapted for [TypeScript](https://github.com/progre/tslint-config-airbnb). The test suites are built on Facebook's [Jest](https://facebook.github.io/jest/). Make sure that any changes you make are fully tested and linted before submitting a pull request! | ||
| Command | Description | | ||
| --- | --- | | ||
| `npm test` | Runs tests | | ||
| `npm run build` | Builds the project | | ||
| `npm run ci` | Builds the project, runs tests and reports coverage | | ||
| `npm run clean` | Cleans build output directories | | ||
| `npm run tsc` | Transpiles TypeScript to ES5 | | ||
| `npm run tslint` | Lints TypeScript code | | ||
## License | ||
[MIT](http://vjpr.mit-license.org) | ||
[MIT](http://eoin.mit-license.org) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9580
11
31
130