diff --git a/lib/exposure/exposure.js b/lib/exposure/exposure.js index e3b74f4..2516437 100644 --- a/lib/exposure/exposure.js +++ b/lib/exposure/exposure.js @@ -6,6 +6,7 @@ import enforceMaxDepth from './lib/enforceMaxDepth.js'; import enforceMaxLimit from './lib/enforceMaxLimit.js'; import intersectDeep from './lib/intersectDeep.js'; import computeDeepFunctions from './lib/computeDeepFunctions.js'; +import intercomputeDeep from './lib/intercomputeDeep.js'; import deepClone from '../query/lib/deepClone'; import restrictFieldsFn from './lib/restrictFields.js'; import restrictLinks from './lib/restrictLinks.js'; @@ -83,7 +84,7 @@ export default class Exposure { return body; } - return intersectDeep(this.getBody(userId), body); + return intercomputeDeep(this.getBody(userId), body); } /** @@ -95,12 +96,12 @@ export default class Exposure { } if (_.isFunction(this.config.body)) { - return computeDeepFunctions( + return deepClone( this.config.body.call(this, userId), userId ); } else { - return computeDeepFunctions(this.config.body, userId); + return deepClone(this.config.body, userId); } } diff --git a/lib/exposure/lib/intercomputeDeep.js b/lib/exposure/lib/intercomputeDeep.js new file mode 100644 index 0000000..61ecd20 --- /dev/null +++ b/lib/exposure/lib/intercomputeDeep.js @@ -0,0 +1,48 @@ +import deepClone from '../../query/lib/deepClone'; + +/** + * Deep Inter Computation + */ +export default function intercomputeDeep(main, second, ...args) { + let object = {}; + + _.each(main, (value, key) => { + if (second[key] !== undefined) { + // if the main value is a function, we run it. + if (_.isFunction(value)) { + value = value.call(null, ...args); + } + + // if the main value is undefined or false, we skip the merge + if (value === undefined || value === false) { + return; + } + + // if the main value is an object + if (_.isObject(value)) { + if (_.isObject(second[key])) { + // if the second one is an object as well we run recursively run the intersection + object[key] = intercomputeDeep(value, second[key], ...args); + } + // if it is not, then we will ignore it, because it won't make sense. + // to merge {a: 1} with 1. + + return; + } + + // if the main value is not an object, a truthy value like 1 + if (_.isObject(second[key])) { + // if the second value is an object, then we will keep it. + // this won't cause problem with deep nesting because + // when you specify links you will have the main value as an object + + object[key] = deepClone(second[key]); + } else { + // if the second value is not an object, we just store the first value + object[key] = value; + } + } + }); + + return object; +} \ No newline at end of file diff --git a/lib/exposure/testing/units/units.js b/lib/exposure/testing/units/units.js index c6fa29e..7d90fb3 100644 --- a/lib/exposure/testing/units/units.js +++ b/lib/exposure/testing/units/units.js @@ -2,6 +2,7 @@ import restrictFields from '../../lib/restrictFields.js'; import enforceMaxLimit from '../../lib/enforceMaxLimit.js'; import intersectDeep from '../../lib/intersectDeep.js'; import computeDeepFunctions from '../../lib/computeDeepFunctions.js'; +import intercomputeDeep from '../../lib/intercomputeDeep.js'; import enforceMaxDepth, {getDepth} from '../../lib/enforceMaxDepth.js'; import CollectionNode from '../../../query/nodes/collectionNode.js'; @@ -200,7 +201,7 @@ describe('Unit Tests', function () { Object.freeze(obj1); Object.freeze(obj2); - const result = intersectDeep(obj1, obj2); + const result = intercomputeDeep(obj1, obj2); assert.isObject(result); assert.equal(result.a, 1); @@ -214,9 +215,7 @@ describe('Unit Tests', function () { assert.isUndefined(result.d.d1.d12); assert.isUndefined(result.d.d2); assert.isUndefined(result.testUndefined); - - assert.isObject(result.d.d1.d13); - assert.equal(result.d.d1.d13.d131, 1); + assert.isUndefined(result.d.d1.d13); }); it('Should compute functions nested', function () { @@ -237,5 +236,52 @@ describe('Unit Tests', function () { assert.equal(newObject.value.item, 'test'); assert.isObject(newObject.b.value); assert.equal(newObject.b.value.item, 'test'); + }); + + it('Should work intersect with computation and with infinite recursion avoidance', function () { + const link2 = (item) => { + return { + item, + link1 + } + }; + + const link1 = (item) => { + return { + item, + link2 + } + }; + + const obj1 = { + a: 1, + link1 + }; + + const obj2 = { + a: { + a1: 1 + }, + link1: { + item: 1, + link2: { + item: 1, + link1: { + item: 1 + } + } + } + }; + + const result = intercomputeDeep(obj1, obj2, 'test'); + + assert.isObject(result.a); + assert.isDefined(result.a.a1); + assert.isObject(result.link1); + assert.equal(result.link1.item, 'test'); + assert.isObject(result.link1.link2); + assert.equal(result.link1.link2.item, 'test'); + assert.isObject(result.link1.link2.link1); + assert.equal(result.link1.link2.link1.item, 'test'); }) }); \ No newline at end of file