Skip to content

Commit

Permalink
Merge pull request #348 from feathers-plus/mongoKeys
Browse files Browse the repository at this point in the history
Added mongoKeys hook.
  • Loading branch information
eddyystop authored Feb 3, 2018
2 parents 8f08b6c + 7d17382 commit 907c0ce
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/services/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const keep = require('./keep');
const keepQuery = require('./keep-query');
const lowerCase = require('./lower-case');
const makeCallingParams = require('./make-calling-params');
const mongoKeys = require('./mongo-keys');
const paramsForServer = require('./params-for-server');
const paramsFromClient = require('./params-from-client');
const populate = require('./populate');
Expand Down Expand Up @@ -82,6 +83,7 @@ module.exports = Object.assign({ callbackToPromise,
keepQuery,
lowerCase,
makeCallingParams,
mongoKeys,
paramsForServer,
paramsFromClient,
populate,
Expand Down
59 changes: 59 additions & 0 deletions lib/services/mongo-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

const traverse = require('traverse');
const { ObjectID } = require('mongodb');
const checkContext = require('./check-context');

module.exports = function mongoKeys (ObjectID, keyFields) {
keyFields = Array.isArray(keyFields) ? keyFields : [keyFields];
const keyLeaves = [];

const keysInfo = keyFields.map(field => {
const fieldNames = field.split('.');
const leaf = fieldNames.slice(-1)[0];
keyLeaves.push(leaf);

return { leaf, len: fieldNames.length, path: JSON.stringify(fieldNames) };
});

return context => {
checkContext(context, 'before', 'find', 'mongoKeys');
const query = context.params.query || {};

traverse(query).forEach(function (node) {
const typeofNode = typeof node;
const key = this.key;
const path = this.path;

if (keyLeaves.indexOf(key) === -1) return;

keysInfo.forEach(info => {
if (info.leaf === key && info.len <= path.length) {
const endPath = path.slice(-info.len);
if (JSON.stringify(endPath) === info.path) {
if (typeofNode === 'object' && node !== null && !Array.isArray(node)) {
// { keyPath: { ... } }
const actualProps = Object.keys(node);
const onlyProp = actualProps[0];

if (actualProps.length === 1 && onlyProp === '$in') {
// { keyPath: { $in: [...] } }
const newNode = { $in: wrapValue(node[onlyProp], true) };
this.update(newNode);
}
} else if (typeofNode === 'string' || typeofNode === 'number') {
// { keyPath: '111111111111' }
const newNode = wrapValue(node, true);
this.update(newNode);
}
}
}
});
});

return context;
};
};

function wrapValue (value) {
return Array.isArray(value) ? value.map(val => new ObjectID(val)) : new ObjectID(value);
}
43 changes: 43 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"feathers-tests-fake-app-users": "^1.0.0",
"istanbul": "^1.1.0-alpha.1",
"mocha": "^3.1.2",
"mongodb": "3.0.2",
"semistandard": "^11.0.0",
"shx": "^0.2.2",
"sift": "^4.0.0"
Expand Down
1 change: 1 addition & 0 deletions tests/services/exposed.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const hookNames = [
'keepQuery',
'lowerCase',
'makeCallingParams',
'mongoKeys',
'paramsForServer',
'paramsFromClient',
'populate',
Expand Down
90 changes: 90 additions & 0 deletions tests/services/mongo-keys.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@

const { assert } = require('chai');
const { ObjectID } = require('mongodb');
const { mongoKeys } = require('../../lib/services');

const s0 = '000000000000';
const s1 = '111111111111';
const s2 = '222222222222';
const s5 = '555555555555';
const s8 = '888888888888';

describe('services mongoKeys', () => {
it('{ a: s1, c: s0 }', () => {
const newQuery = wrapper(
['a'],
{ a: s1, c: s0 }
);

assert.instanceOf(newQuery.a, ObjectID, '"a" not ObjectID');
assert.isString(newQuery.c, '"c" not a string');
});

it('{ a: { b: s0 }, c: s0 }', () => {
const newQuery = wrapper(
['a'],
{ a: { b: s0 }, c: s0 }
);

assert.isString(newQuery.a.b, '"a.b" not a string');
assert.isString(newQuery.c, '"c" not a string');
});

it('{ a: { $in: [s1, s2] }, c: s0 }', () => {
const newQuery = wrapper(
['a'],
{ a: { $in: [s1, s2] }, c: s0 }
);

assert.instanceOf(newQuery.a.$in[0], ObjectID, '"a.$in[0]" not ObjectID');
assert.instanceOf(newQuery.a.$in[1], ObjectID, '"a.$in[1]" not ObjectID');
assert.isString(newQuery.c, '"c" not a string');
});

it('{ a: s1, b: \'111111111111\', c: s0 }', () => {
const newQuery = wrapper(
['a', 'b'],
{ a: s1, b: s2, c: s0 }
);

assert.instanceOf(newQuery.a, ObjectID, '"a" not ObjectID');
assert.instanceOf(newQuery.b, ObjectID, '"b" not ObjectID');
assert.isString(newQuery.c, '"c" not a string');
});

it('{ a: { x: s8 } }', () => {
const newQuery = wrapper(
['a.x'],
{ a: { x: s8 } }
);

assert.instanceOf(newQuery.a.x, ObjectID, '"a.x" not ObjectID');
});

it('{ $or: [{ a: { x: s8 } }, { b: s5 }, { c: s0 }], d: s0 }', () => {
const newQuery = wrapper(
['a.x', 'b'],
{ $or: [{ a: { x: s8 } }, { b: s5 }, { c: s0 }], d: s0 }
);

assert.instanceOf(newQuery.$or[0].a.x, ObjectID, '"$or[0].a.x" not ObjectID');
assert.instanceOf(newQuery.$or[1].b, ObjectID, '"$or[1].b" not ObjectID');
assert.isString(newQuery.$or[2].c, '"$or[2].c" not a string');
assert.isString(newQuery.d, '"d" not a string');
});

it('{ $or: [{ a: { x: s8 } }, { a: s5 }] } - questionable', () => {
const newQuery = wrapper(
['a', 'a.x'],
{ $or: [{ a: { x: s8 } }, { a: s5 }] }
);

assert.instanceOf(newQuery.$or[0].a.x, ObjectID, '"$or[0].a.x" not ObjectID');
assert.instanceOf(newQuery.$or[1].a, ObjectID, '"$or[1].a" not ObjectID');
});
});

function wrapper (keys, query) {
const newContext = mongoKeys(ObjectID, keys)({ params: { query }, type: 'before', method: 'find' });
return newContext.params.query;
}

0 comments on commit 907c0ce

Please sign in to comment.