-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tom Kirkpatrick
committed
Feb 8, 2017
0 parents
commit 8eb408b
Showing
11 changed files
with
465 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"extends": "fullcube", | ||
"root": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
npm-debug.log | ||
node_modules/ | ||
coverage/ | ||
.idea | ||
.nyc_output/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
.git | ||
.idea/ | ||
npm-debug.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
language: node_js | ||
node_js: | ||
- "6" | ||
- "5" | ||
- "4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
CASCADE UPDATE MIXIN | ||
================ | ||
|
||
This module is designed for the [Strongloop Loopback](https://github.com/strongloop/loopback) framework. It provides cascade update functionality with a simple configuration on your models. This can be used to keep property values synchronised across related models. | ||
|
||
INSTALL | ||
================ | ||
|
||
```bash | ||
npm install --save loopback-ds-cascade-update-mixin | ||
``` | ||
|
||
SERVER CONFIG | ||
============= | ||
Add the mixins property to your server/model-config.json: | ||
|
||
```json | ||
{ | ||
"_meta": { | ||
"sources": [ | ||
"loopback/common/models", | ||
"loopback/server/models", | ||
"../common/models", | ||
"./models" | ||
], | ||
"mixins": [ | ||
"loopback/common/mixins", | ||
"../node_modules/loopback-ds-cascade-update-mixin/lib", | ||
"../common/mixins" | ||
] | ||
} | ||
} | ||
``` | ||
|
||
CONFIG | ||
============= | ||
|
||
To use with your Models add the `mixins` attribute to the definition object of your model config. | ||
|
||
The config keys are the property names that you want to cascade. | ||
|
||
The config values are an array of relationships that the property updates should cascade to. | ||
|
||
|
||
```json | ||
{ | ||
"name": "Product", | ||
"properties": { | ||
"name": { | ||
"type": "string", | ||
} | ||
}, | ||
"relations": { | ||
"relation1": { | ||
"type": "hasMany", | ||
"model": "Property", | ||
"foreignKey": "" | ||
} | ||
}, | ||
"mixins": { | ||
"CascadeUpdate": { | ||
"status": [ "relation1", "relation2" ], | ||
"isTest": [ "relation1", "relation2" "relation3" ] | ||
} | ||
} | ||
} | ||
``` | ||
|
||
TESTING | ||
============= | ||
|
||
Run the tests in `test.js` | ||
|
||
```bash | ||
npm test | ||
``` | ||
|
||
DEBUGGING | ||
============= | ||
|
||
Run with debugging output on: | ||
|
||
```bash | ||
DEBUG='loopback:mixins:cascade-update' npm test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
'use strict' | ||
|
||
const debug = require('debug')('loopback:mixins:cascade-update') | ||
const _ = require('lodash') | ||
|
||
module.exports = function cascadeUpdateMixin(Model, options) { | ||
|
||
debug('CascadeUpdate mixin for Model %s with options %o', Model.modelName, options) | ||
|
||
function idName(m) { | ||
return m.definition.idName() || 'id' | ||
} | ||
|
||
function getIdValue(m, data) { | ||
return _.get(data, idName(m)) | ||
} | ||
|
||
function cascadeUpdates(instance) { | ||
return Promise.resolve(Object.keys(options)) | ||
.each(property => Promise.resolve([].concat(options[property])) | ||
.map(relation => { | ||
debug(`Cascading '${property}' property via '${relation}' relation on ${Model.definition.name} model`) | ||
|
||
if (!Model.relations[relation]) { | ||
debug(`Relation ${relation} not found for model ${Model.definition.name}`) | ||
return null | ||
} | ||
|
||
if (typeof instance[property] === 'undefined') { | ||
debug(`Property ${property} not found for model ${Model.definition.name}`) | ||
return null | ||
} | ||
|
||
const where = {} | ||
const data = {} | ||
|
||
let relationModel = Model.relations[relation].modelTo | ||
const relationKey = Model.relations[relation].keyTo | ||
|
||
if (Model.relations[relation].modelThrough) { | ||
relationModel = Model.relations[relation].modelThrough | ||
} | ||
|
||
if (Model.relations[relation].polymorphic) { | ||
where[Model.relations[relation].polymorphic.discriminator] = Model.definition.name | ||
} | ||
|
||
where[relationKey] = getIdValue(Model, instance) | ||
data[property] = instance[property] | ||
|
||
debug(`Calling ${relationModel.definition.name}.updateAll(%o, %o)`, where, data) | ||
|
||
return relationModel.updateAll(where, data) | ||
.then(res => debug(`Updated ${res.count} items from the ${relationModel.definition.name} model`)) | ||
}) | ||
) | ||
} | ||
|
||
Model.observe('after save', (ctx, next) => { | ||
debug('after save: ctx.instance', ctx.instance) | ||
debug('after save: ctx.where', ctx.where) | ||
debug('after save: ctx.data', ctx.data) | ||
|
||
const name = idName(Model) | ||
const hasInstanceId = ctx.instance && ctx.instance[name] | ||
const hasWhereId = ctx.where && ctx.where[name] | ||
|
||
if (ctx.isNewInstance) { | ||
debug('Skipping update for ', Model.definition.name, 'isNewInstance') | ||
return next() | ||
} | ||
|
||
if (!(hasWhereId || hasInstanceId)) { | ||
debug('Skipping update for ', Model.definition.name, 'Multi-instance update') | ||
return next() | ||
} | ||
|
||
return cascadeUpdates(ctx.instance || ctx.data) | ||
.then(() => debug('Cascade update has successfully finished')) | ||
.catch(err => { | ||
debug('Error with cascading updates', err) | ||
throw err | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
{ | ||
"name": "loopback-ds-cascade-update-mixin", | ||
"description": "Loopback cascade update mixin.", | ||
"version": "0.0.0-development", | ||
"author": { | ||
"name": "Tom Kirkpatrick @mrfelton" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/fullcube/loopback-ds-cascade-update-mixin.git" | ||
}, | ||
"keywords": [ | ||
"loopback", | ||
"strongloop", | ||
"cascade" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/fullcube/loopback-ds-cascade-update-mixin/issues" | ||
}, | ||
"homepage": "https://github.com/fullcube/loopback-ds-cascade-update-mixin", | ||
"files": [ | ||
"lib", | ||
"test" | ||
], | ||
"directories": { | ||
"lib": "lib", | ||
"test": "test" | ||
}, | ||
"main": "lib/cascade-update.js", | ||
"scripts": { | ||
"lint": "eslint .", | ||
"pretest": "npm run lint", | ||
"test": "nyc --reporter=lcov --reporter=text --reporter=text-summary mocha test/*test.js", | ||
"test:watch": "npm run test -- -w", | ||
"coverage": "nyc report --reporter=text-lcov | coveralls", | ||
"semantic-release": "semantic-release pre && npm publish && semantic-release post" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"condition-circle": "^1.5.0", | ||
"coveralls": "^2.11.16", | ||
"dirty-chai": "^1.2.2", | ||
"eslint": "2.13.1", | ||
"eslint-config-fullcube": "latest", | ||
"eslint-plugin-mocha": "latest", | ||
"loopback": "^2.36.0", | ||
"mocha": "^3.2.0", | ||
"mocha-sinon": "^1.1.6", | ||
"nyc": "^10.1.2", | ||
"semantic-release": "^6.3.2", | ||
"sinon": "^1.17.6", | ||
"sinon-chai": "^2.8.0" | ||
}, | ||
"dependencies": { | ||
"lodash": "^4.17.2", | ||
"debug": "^2.3.3" | ||
}, | ||
"release": { | ||
"verifyConditions": "condition-circle" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"extends": "fullcube/mocha", | ||
"root": true, | ||
"globals": { | ||
"loopback": true, | ||
"expect": true, | ||
"sinon": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--reporter spec |
Oops, something went wrong.