mongoose-hidden
Advanced tools
Comparing version
# Changelog | ||
1.9.0 | ||
1.9.1 | ||
- refactor: clean the codebase to make it easier to contribute | ||
- chore: upgrade mpath to 8.0 | ||
1.9.0 | ||
- feat: support for nested documents (issue #83) | ||
- chore: remove dependency on 'debug' | ||
1.8.1 | ||
1.8.1 | ||
- fix bug introduced in 1.7.0 when populating relations using `match` (issue #75) | ||
1.8.0 | ||
1.8.0 | ||
- reveret to old setPath of pre-1.7 but still use the mpath.set patching approach to make the client compatible with mpath.set | ||
1.7.0 | ||
1.7.0 | ||
- replace custom setPath function with mpath.set (#69) | ||
1.6.2 | ||
1.6.2 | ||
- added TypeScript definitions (thanks to @marshalys) | ||
1.6.0 | ||
1.6.0 | ||
@@ -34,7 +39,7 @@ Drop support for node 4 + 5, supported node version is [Maintenance LTS](https://github.com/nodejs/Release). Version 1.5.4 is the last version | ||
1.5.1 | ||
1.5.1 | ||
- fix: 1.5.0 would add entries from the schema that were not in the original transform (thanks to @proswdev) | ||
1.5.0 | ||
1.5.0 | ||
@@ -41,0 +46,0 @@ refactor: Replaced get and delete path parts with mpath |
@@ -0,1 +1,3 @@ |
/* eslint no-use-before-define: 0 operator-linebreak: 0 */ |
'use strict' |
@@ -14,6 +16,131 @@ |
/** |
* Plugin constructor |
* |
* @param {Schema} schema a mongoose schema |
* @param {Object} options a set of options |
* |
* @return {void} |
*/ |
function plugin(schema, options) { |
const paths = getPathnames(options, schema) |
const transformer = transformerFactory(schema, options, paths) |
applyTransformers(schema, transformer) |
applyToChildren(schema, options) |
} |
/** |
* Returns an array of pathnames based on the schema and the default settings |
* |
* @access private |
* |
* @param {Object} options a set of options |
* @param {Schema} schema a mongoose schema |
* @returns {array} an array of paths |
*/ |
function getPathnames(options, schema) { |
let paths = pathsFromTree(schema.tree) |
Object.keys(options['defaultHidden']).forEach(path => { |
if (paths.indexOf(path) === -1) { |
paths.push(path) |
} |
}) |
return paths |
} |
/** |
* Constructs a transformer function that can be applied to toJSON and toObject |
* on the schema |
* |
* @param {Schema} schema a mongoose schema |
* @param {Object} options a set of options |
* @param {array} paths an array of paths |
* @return {Function} a transformer function |
*/ |
function transformerFactory(schema, options, paths) { |
return (target, prevTransform) => (doc, transformed, opt) => { |
const transformation = { |
finalTransform: {}, |
options, |
schema, |
target, |
transformed, |
} |
// Apply existing transformer |
applyExisting(transformation, prevTransform, opt) |
// Copy real values |
paths.forEach(copyRealValues(transformation, doc)) |
// Copy virtual values |
Object.keys(transformed).forEach(copyVirtualValues(transformation)) |
return transformation.finalTransform |
} |
} |
/** |
* Applies existing transformation if any |
* |
* @param {Object} transformation a transformation value object |
* @param {Function} prevTransform existing transformer function |
* @param {Object} opt transformation options |
* |
* @return {void} |
*/ |
function applyExisting(transformation, prevTransform, opt) { |
if (typeof prevTransform === 'function') { |
const { doc, transformed } = transformation |
transformation.finalTransform = prevTransform(doc, transformed, opt) |
} |
} |
/** |
* Copy 'real' values (non-virtuals) onto the finalTransform |
* |
* @param {Object} transformation a transformation value object |
* @param {Object} doc the document being transformed |
* |
* @return {Function} transformer function for a given path |
*/ |
function copyRealValues(transformation, doc) { |
return pathname => { |
const { finalTransform, transformed } = transformation |
if (shouldHide(transformation, doc, pathname)) { |
mpath.unset(pathname, finalTransform) |
return |
} |
const value = mpath.get(pathname, transformed) |
if (typeof value !== 'undefined') { |
mpath.set(pathname, value, finalTransform) |
} |
} |
} |
/** |
* Copy virtual values onto the finalTransform |
* |
* @param {Object} transformation a transformation value object |
* @return {Function} transformer function for a given key |
*/ |
function copyVirtualValues(transformation) { |
return key => { |
const { finalTransform, transformed } = transformation |
if (shouldCopyVirtual(transformation, key)) { |
mpath.set(key, mpath.get(key, transformed), finalTransform) |
} |
} |
} |
/** |
* Tests to see if the pathname for target is hidden by an option |
* |
* @access private |
* @param {object} options a set of options |
* |
* @param {Object} options a set of options |
* @param {string} pathname property path |
@@ -30,6 +157,7 @@ * @returns {Boolen} true of pathname should be hidden |
* @access private |
* |
* @param {Schema} schema a mongoose schema |
* @param {string} key the key to test |
* @param {object} doc original document |
* @param {object} transformed transformed document |
* @param {Object} doc original document |
* @param {Object} transformed transformed document |
* @returns {Boolen} true of pathname should be hidden |
@@ -52,12 +180,11 @@ */ |
* @access private |
* @param {Schema} schema a mongoose schema |
* @param {object} options a set of options |
* @param {string} target the target to test, e.g 'JSON' |
* @param {object} doc original document |
* @param {object} transformed transformed document |
* |
* @param {Object} transformation a transformation value object |
* @param {Object} doc original document |
* @param {string} pathname property path |
* @returns {Boolen} true of pathname should be hidden |
*/ |
function shouldHide(schema, options, target, doc, transformed, pathname) { |
let hideTarget = hide + target |
function shouldHide({ options, schema, target, transformed }, doc, pathname) { |
const schemaType = schema.path(pathname) |
const hideTarget = hide + target |
@@ -72,4 +199,4 @@ // Is hiding turned off? |
testOptions(options, pathname) || |
testSchema(schema, hide, doc, transformed) || |
testSchema(schema, hideTarget, doc, transformed) |
testSchema(schemaType, hide, doc, transformed) || |
testSchema(schemaType, hideTarget, doc, transformed) |
) |
@@ -82,9 +209,8 @@ } |
* @access private |
* |
* @param {Schema} schema a mongoose schema |
* @param {string} key object key name |
* @param {object} options a set of options |
* @param {string} target the target to test, e.g 'JSON' |
* @returns {Boolen} true of pathname should be hidden |
*/ |
function shouldCopyVirtual(schema, key, options, target) { |
function shouldCopyVirtual({ options, schema, target }, key) { |
return ( |
@@ -100,2 +226,3 @@ schema.pathType(key) === 'virtual' && |
* @access private |
* |
* @param {string} parent first part |
@@ -106,6 +233,3 @@ * @param {string} child second part |
function joinKey(parent, child) { |
if (!parent) { |
return child |
} |
return parent + '.' + child |
return parent ? parent + '.' + child : child |
} |
@@ -117,3 +241,4 @@ |
* @access private |
* @param {object} obj the root object |
* |
* @param {Object} obj the root object |
* @param {string} parentPath the path taken to get to here |
@@ -144,36 +269,41 @@ * @returns {array} an array of paths from all children of the root object |
/** |
* Returns an array of pathnames based on the schema and the default settings |
* Returns a safe options lookup function |
* |
* @access private |
* @param {object} options a set of options |
* @param {Schema} schema a mongoose schema |
* @returns {array} an array of paths |
* @private |
* |
* @param {Object} options plugin options |
* @return {Function} ensure function |
*/ |
function getPathnames(options, schema) { |
let paths = pathsFromTree(schema.tree) |
Object.keys(options['defaultHidden']).forEach(path => { |
if (paths.indexOf(path) === -1) { |
paths.push(path) |
} |
}) |
return paths |
function ensureOption(options) { |
return (option, fallback) => (option in options ? options[option] : fallback) |
} |
/** |
* Returns a safe options lookup function |
* Merges interal defaults with plugin defaults |
* |
* @private |
* @param {Object} options |
* @return {Function} |
* @access private |
* |
* @param {Object} defaults the default set of options |
* @returns {Object} a combined options set |
*/ |
function ensureOption(options) { |
return function(option, fallback) { |
return option in options ? options[option] : fallback |
} |
function prepDefaults(defaults) { |
return Object.assign( |
{}, |
{ |
applyRecursively: false, |
autoHide: true, |
autoHideJSON: true, |
autoHideObject: true, |
defaultHidden: { _id: true, __v: true }, |
virtuals: {}, |
}, |
defaults || {} |
) |
} |
/** |
* Merges options from defaults and instantiation |
* Merges options from defaults |
* |
* @access private |
* |
* @param {Object} options an optional set of options |
@@ -210,78 +340,35 @@ * @param {Object} defaults the default set of options |
module.exports = function(defaults) { |
let _defaults = Object.assign( |
{}, |
{ |
applyRecursively: false, |
autoHide: true, |
autoHideJSON: true, |
autoHideObject: true, |
defaultHidden: { _id: true, __v: true }, |
virtuals: {}, |
}, |
defaults || {} |
) |
function applyTransformers(schema, transformer) { |
let toJSONOptions = schema.get('toJSON') || {} |
const plugin = function(schema, options) { |
options = prepOptions(options, _defaults) |
schema.set('toJSON', { |
getters: toJSONOptions['getters'] || false, |
virtuals: toJSONOptions[virtuals] || false, |
transform: transformer('JSON', toJSONOptions['transform'] || null), |
}) |
let paths = getPathnames(options, schema) |
let toObjectOptions = schema.get('toObject') || {} |
let transformer = function(target, prevTransform) { |
return function(doc, transformed, opt) { |
schema.set('toObject', { |
getters: toObjectOptions['getters'] || false, |
virtuals: toObjectOptions[virtuals] || false, |
transform: transformer('Object', toObjectOptions['transform'] || null), |
}) |
} |
// Apply existing transformer |
let finalTransform = {} |
if (typeof prevTransform === 'function') { |
finalTransform = prevTransform(doc, transformed, opt) |
} |
// Copy real values |
paths.forEach(function(pathname) { |
let schemaType = schema.path(pathname) |
if (shouldHide(schemaType, options, target, doc, transformed, pathname)) { |
mpath.unset(pathname, finalTransform) |
} else { |
let value = mpath.get(pathname, transformed) |
if (typeof value !== 'undefined') { |
mpath.set(pathname, value, finalTransform) |
} |
} |
}) |
// Copy virtual values |
for (let key in transformed) { |
if (shouldCopyVirtual(schema, key, options, target)) { |
mpath.set(key, mpath.get(key, transformed), finalTransform) |
} |
} |
return finalTransform |
} |
} |
let toJSONOptions = schema.get('toJSON') || {} |
schema.set('toJSON', { |
getters: toJSONOptions['getters'] || false, |
virtuals: toJSONOptions[virtuals] || false, |
transform: transformer('JSON', toJSONOptions['transform'] || null), |
function applyToChildren(schema, options) { |
if (options.applyRecursively) { |
schema.childSchemas.forEach(child => { |
plugin(child.schema, options) |
}) |
} |
} |
let toObjectOptions = schema.get('toObject') || {} |
module.exports = function (defaults) { |
let _defaults = prepDefaults(defaults) |
schema.set('toObject', { |
getters: toObjectOptions['getters'] || false, |
virtuals: toObjectOptions[virtuals] || false, |
transform: transformer('Object', toObjectOptions['transform'] || null), |
}) |
if (options.applyRecursively) { |
schema.childSchemas.forEach(child => { |
plugin(child.schema, options) |
}) |
} |
return function (schema, options) { |
options = prepOptions(options, _defaults) |
return plugin(schema, options) |
} |
return plugin |
} |
{ | ||
"name": "mongoose-hidden", | ||
"version": "1.9.0", | ||
"version": "1.9.1", | ||
"author": "Michael Bøcker-Larsen <m19n@pm.me>", | ||
@@ -29,3 +29,3 @@ "description": "Hides certain model properties when invoking toJSON or toObject.", | ||
"dependencies": { | ||
"mpath": "^0.7.0" | ||
"mpath": "^0.8.0" | ||
}, | ||
@@ -32,0 +32,0 @@ "devDependencies": { |
@@ -1,9 +0,8 @@ | ||
# mongoose-hidden | ||
# mongoose-hidden :see_no_evil: | ||
[](http://travis-ci.org/mblarsen/mongoose-hidden) | ||
[](http://travis-ci.org/mblarsen/mongoose-hidden) | ||
[](https://codebeat.co/projects/github-com-mblarsen-mongoose-hidden-master) | ||
[](https://coveralls.io/github/mblarsen/mongoose-hidden?branch=master) | ||
[](https://snyk.io/test/github/mblarsen/mongoose-hidden) | ||
[](http://makeapullrequest.com) | ||
[](https://coveralls.io/github/mblarsen/mongoose-hidden?branch=master) | ||
[](https://snyk.io/test/github/mblarsen/mongoose-hidden) | ||
[](http://makeapullrequest.com) | ||
[](https://www.npmjs.com/package/mongoose-hidden) | ||
@@ -14,2 +13,4 @@ [](https://www.npmjs.com/package/mongoose-hidden) | ||
[](https://www.codementor.io/@mblarsen?refer=badge) | ||
# Install | ||
@@ -72,29 +73,20 @@ | ||
There are two methods: when creating the plugin and when attaching the plugin, and they can be combined. | ||
There are two ways to set this up and they can be combined for more granular control. | ||
#### Method 1: constructor param | ||
```javascript | ||
let mongooseHidden = require('mongoose-hidden')({ hidden: { _id: true, password: true } }) | ||
// Passing constructor parameters | ||
const mongooseHidden = require('mongoose-hidden')({ hidden: { _id: true, password: true } }) | ||
UserSchema.plugin(mongooseHidden) | ||
``` | ||
#### Method 2: attach plugin param | ||
```javascript | ||
let mongooseHidden = require('mongoose-hidden')() | ||
// Passing plugin parameters when attaching to schema | ||
const mongooseHidden = require('mongoose-hidden')() | ||
UserSchema.plugin(mongooseHidden, { hidden: { _id: true, password: true } }) | ||
``` | ||
#### Method 1+2: combination | ||
```javascript | ||
let mongooseHidden = require('mongoose-hidden')({ hidden: { _id: true, password: true } }) | ||
// Here they are used together | ||
const mongooseHidden = require('mongoose-hidden')({ hidden: { _id: true, password: true } }) | ||
UserSchema.plugin(mongooseHidden, { hidden: { resetToken: true } }) | ||
PaymentSchema.plugin(mongooseHidden, { hidden: { _id: false, authToken: true } }) // unhides _id | ||
``` | ||
.. another example: | ||
//.. another example: | ||
```javascript | ||
if (app === 'web') { | ||
@@ -128,7 +120,7 @@ UserSchema.plugin(mongooseHidden, { hidden: { _id: true, password: true } }) | ||
// By default in Mongoose virtuals will not be included. Turn on before enabling plugin. | ||
schema.set('toJSON', { virtuals: true }); | ||
schema.set('toObject', { virtuals: true }); | ||
schema.set('toJSON', { virtuals: true }) | ||
schema.set('toObject', { virtuals: true }) | ||
// Enable plugin | ||
schema.plugin(mongooseHidden, { virtuals: { fullname: 'hideJSON' }}); | ||
schema.plugin(mongooseHidden, { virtuals: { fullname: 'hideJSON' } }) | ||
``` | ||
@@ -155,6 +147,8 @@ | ||
// First define transform function | ||
UserSchema.set('toJSON', { transform: function (doc, ret, opt) { | ||
ret['name'] = 'Mr ' + ret['name'] | ||
return ret | ||
}}) | ||
UserSchema.set('toJSON', { | ||
transform: function (doc, ret, opt) { | ||
ret['name'] = 'Mr ' + ret['name'] | ||
return ret | ||
}, | ||
}) | ||
@@ -173,7 +167,38 @@ // Then apply plugin | ||
* Always set `{ getters: true, virtuals: true }` before installing plugin if you want virtuals to be returned: | ||
- Always set `{ getters: true, virtuals: true }` before installing plugin if you want virtuals to be returned: | ||
```javascript | ||
schema.set('toJSON', { getters: true, virtuals: true }); | ||
schema.plugin(require(mongooseHidden)); | ||
schema.set('toJSON', { getters: true, virtuals: true }) | ||
schema.plugin(require(mongooseHidden)) | ||
``` | ||
## Contributors ✨ | ||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): | ||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> | ||
<!-- prettier-ignore-start --> | ||
<!-- markdownlint-disable --> | ||
<table> | ||
<tr> | ||
<td align="center"><a href="https://github.com/AlbertHambardzumyan"><img src="https://avatars3.githubusercontent.com/u/11527341?v=4" width="100px;" alt=""/><br /><sub><b>Albert Hambardzumyan</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/commits?author=AlbertHambardzumyan" title="Tests">⚠️</a> <a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3AAlbertHambardzumyan" title="Bug reports">🐛</a></td> | ||
<td align="center"><a href="https://github.com/awelllle"><img src="https://avatars0.githubusercontent.com/u/25726727?v=4" width="100px;" alt=""/><br /><sub><b>Awele</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/commits?author=awelllle" title="Documentation">📖</a></td> | ||
<td align="center"><a href="http://infiniscene.com"><img src="https://avatars3.githubusercontent.com/u/938128?v=4" width="100px;" alt=""/><br /><sub><b>Dan Trocchio</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3Alavarsicious" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=lavarsicious" title="Tests">⚠️</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=lavarsicious" title="Code">💻</a></td> | ||
<td align="center"><a href="https://www.codeboutique.com"><img src="https://avatars0.githubusercontent.com/u/247048?v=4" width="100px;" alt=""/><br /><sub><b>Michael Bøcker-Larsen</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3Amblarsen" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=mblarsen" title="Code">💻</a> <a href="#maintenance-mblarsen" title="Maintenance">🚧</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=mblarsen" title="Documentation">📖</a></td> | ||
<td align="center"><a href="https://twitter.com/ohnobinki"><img src="https://avatars2.githubusercontent.com/u/82626?v=4" width="100px;" alt=""/><br /><sub><b>Nathan Phillip Brink</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/commits?author=binki" title="Documentation">📖</a></td> | ||
<td align="center"><a href="https://github.com/Santinell"><img src="https://avatars2.githubusercontent.com/u/3122009?v=4" width="100px;" alt=""/><br /><sub><b>Pavel Evdokimov</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3ASantinell" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=Santinell" title="Code">💻</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=Santinell" title="Tests">⚠️</a></td> | ||
<td align="center"><a href="https://github.com/Bajix"><img src="https://avatars3.githubusercontent.com/u/4229773?v=4" width="100px;" alt=""/><br /><sub><b>Thomas Sieverding</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3ABajix" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=Bajix" title="Code">💻</a></td> | ||
</tr> | ||
<tr> | ||
<td align="center"><a href="https://github.com/lykmapipo"><img src="https://avatars3.githubusercontent.com/u/1610857?v=4" width="100px;" alt=""/><br /><sub><b>lally elias</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3Alykmapipo" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=lykmapipo" title="Code">💻</a></td> | ||
<td align="center"><a href="https://github.com/marshalys"><img src="https://avatars3.githubusercontent.com/u/344530?v=4" width="100px;" alt=""/><br /><sub><b>mars</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3Amarshalys" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=marshalys" title="Code">💻</a></td> | ||
<td align="center"><a href="https://github.com/proswdev"><img src="https://avatars3.githubusercontent.com/u/9143637?v=4" width="100px;" alt=""/><br /><sub><b>proswdev</b></sub></a><br /><a href="https://github.com/mblarsen/mongoose-hidden/issues?q=author%3Aproswdev" title="Bug reports">🐛</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=proswdev" title="Tests">⚠️</a> <a href="https://github.com/mblarsen/mongoose-hidden/commits?author=proswdev" title="Code">💻</a></td> | ||
</tr> | ||
</table> | ||
<!-- markdownlint-enable --> | ||
<!-- prettier-ignore-end --> | ||
<!-- ALL-CONTRIBUTORS-LIST:END --> | ||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! | ||
Sorry, the diff of this file is not supported yet
77627
14.92%21
5%1814
4.49%200
14.29%+ Added
- Removed
Updated