1315 lines
36 KiB
JavaScript
1315 lines
36 KiB
JavaScript
// Switch these lines once there are useful utils
|
|
// const testUtils = require('./utils');
|
|
require('./utils');
|
|
const mongoUtils = require('../');
|
|
const assert = require('assert');
|
|
|
|
describe('Find statement', function () {
|
|
it('should match with object statement by key', function () {
|
|
const statements = {status: 'published'};
|
|
|
|
mongoUtils.findStatement(statements, 'page').should.eql(false);
|
|
mongoUtils.findStatement(statements, 'status').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'tags').should.eql(false);
|
|
mongoUtils.findStatement(statements, 'published').should.eql(false);
|
|
});
|
|
|
|
it('should match in object statement array by key', function () {
|
|
const statements = [
|
|
{page: false},
|
|
{status: 'published'}
|
|
];
|
|
|
|
mongoUtils.findStatement(statements, 'page').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'status').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'tags').should.eql(false);
|
|
mongoUtils.findStatement(statements, 'published').should.eql(false);
|
|
});
|
|
|
|
describe('nested $and/$or groups', function () {
|
|
it('should match inside nested $and group', function () {
|
|
const statements = {$and: [
|
|
{page: false},
|
|
{status: 'published'}
|
|
]};
|
|
|
|
mongoUtils.findStatement(statements, 'page').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'status').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'tags').should.eql(false);
|
|
mongoUtils.findStatement(statements, 'published').should.eql(false);
|
|
});
|
|
|
|
it('should match inside nested $or group', function () {
|
|
const statements = {$or: [
|
|
{page: false},
|
|
{status: 'published'}
|
|
]};
|
|
|
|
mongoUtils.findStatement(statements, 'page').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'status').should.eql(true);
|
|
mongoUtils.findStatement(statements, 'tags').should.eql(false);
|
|
mongoUtils.findStatement(statements, 'published').should.eql(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Reject statements', function () {
|
|
let rejectStatements;
|
|
let testFunction;
|
|
|
|
beforeEach(function () {
|
|
rejectStatements = mongoUtils.rejectStatements;
|
|
|
|
testFunction = (statements) => {
|
|
return (match) => {
|
|
return mongoUtils.findStatement(statements, match);
|
|
};
|
|
};
|
|
});
|
|
|
|
it('should reject from a simple object', function () {
|
|
const statements = {featured: true};
|
|
const filter = {featured: false};
|
|
|
|
rejectStatements(statements, testFunction(filter))
|
|
.should.eql({});
|
|
});
|
|
|
|
it('should NOT reject from a simple object when not matching', function () {
|
|
const statements = {featured: true};
|
|
const filter = {status: 'published'};
|
|
|
|
rejectStatements(statements, testFunction(filter))
|
|
.should.eql({featured: true});
|
|
});
|
|
|
|
it('returns filter intact if it is empty', function () {
|
|
const statements = null;
|
|
const filter = {featured: true};
|
|
|
|
const output = rejectStatements(statements, testFunction(filter));
|
|
|
|
should.equal(output, null);
|
|
});
|
|
|
|
it('rejects statements that match in filter in $or group', function () {
|
|
const statements = {$or: [{
|
|
featured: false
|
|
}, {
|
|
status: 'published'
|
|
}]};
|
|
|
|
const filter = {
|
|
featured: true
|
|
};
|
|
|
|
const output = {$or: [{
|
|
status: 'published'
|
|
}]};
|
|
|
|
rejectStatements(statements, testFunction(filter)).should.eql(output);
|
|
});
|
|
|
|
it('should remove group if all statements are removed', function () {
|
|
const statements = {$or: [{
|
|
featured: false
|
|
}]};
|
|
|
|
const filter = {
|
|
featured: true
|
|
};
|
|
|
|
const output = {};
|
|
|
|
rejectStatements(statements, testFunction(filter)).should.eql(output);
|
|
});
|
|
|
|
it('reduces statements if key matches with any keys in $and group', function () {
|
|
const statements = {$or: [
|
|
{page: false},
|
|
{author: 'cameron'}
|
|
]};
|
|
|
|
const filter = {$and: [
|
|
{tag: 'photo'},
|
|
{page: true}
|
|
]};
|
|
|
|
const output = {$or: [
|
|
{author: 'cameron'}
|
|
]};
|
|
|
|
rejectStatements(statements, testFunction(filter)).should.eql(output);
|
|
});
|
|
|
|
it('should reject statements that are nested multiple levels', function () {
|
|
const statements = {$and: [
|
|
{$or: [
|
|
{tag: {
|
|
$in: ['photo','video']
|
|
}},
|
|
{author: 'cameron'},
|
|
{status: 'draft'}
|
|
]},
|
|
{$and: [
|
|
{status: 'draft'},
|
|
{page: true}
|
|
]}
|
|
]};
|
|
|
|
const filter = {status: 'published'};
|
|
|
|
const output = {$and: [
|
|
{$or: [
|
|
{tag: {
|
|
$in: ['photo','video']
|
|
}},
|
|
{author: 'cameron'}
|
|
]},
|
|
{$and: [
|
|
{page: true}
|
|
]}
|
|
]};
|
|
|
|
rejectStatements(statements, testFunction(filter)).should.eql(output);
|
|
});
|
|
});
|
|
|
|
describe('Combine Filters', function () {
|
|
let combineFilters;
|
|
|
|
beforeEach(function () {
|
|
combineFilters = mongoUtils.combineFilters;
|
|
});
|
|
|
|
it('should return nothing when no filters are passed in', function () {
|
|
should.equal(combineFilters(undefined, undefined), undefined);
|
|
});
|
|
|
|
it('should return unmodified primary filter when secondary is not passed in', function () {
|
|
combineFilters({status: 'published'}).should.eql({status: 'published'});
|
|
});
|
|
|
|
it('should return unmodified secondary filter when primary is not defined in', function () {
|
|
combineFilters(undefined, {status: 'published'}).should.eql({status: 'published'});
|
|
});
|
|
|
|
it('should combine two filters in $and statement', function () {
|
|
combineFilters({page: true}, {status: 'published'}).should.eql({
|
|
$and: [
|
|
{page: true},
|
|
{status: 'published'}
|
|
]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Merge filters', function () {
|
|
it('should return empty statement object when there are no filters', function () {
|
|
mongoUtils.mergeFilters().should.eql({});
|
|
});
|
|
|
|
describe('single filters', function () {
|
|
it('should return only overrides filter when it is passed', function () {
|
|
const input = {
|
|
overrides: {status: 'published'}
|
|
};
|
|
|
|
const output = {
|
|
status: 'published'
|
|
};
|
|
|
|
mongoUtils.mergeFilters(input.overrides).should.eql(output);
|
|
});
|
|
|
|
it('should return only default filter when it is passed', function () {
|
|
const input = {
|
|
defaults: {status: 'published'}
|
|
};
|
|
|
|
const output = {
|
|
status: 'published'
|
|
};
|
|
|
|
mongoUtils.mergeFilters(input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should return only custom filter when it is passed', function () {
|
|
const input = {
|
|
custom: {status: 'published'}
|
|
};
|
|
|
|
const output = {
|
|
status: 'published'
|
|
};
|
|
|
|
mongoUtils.mergeFilters(input.custom).should.eql(output);
|
|
});
|
|
});
|
|
|
|
describe('combination of filters', function () {
|
|
it('should merge overrides and default filters if both are provided', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
defaults: {page: false}
|
|
};
|
|
const output = {$and: [
|
|
{status: 'published'},
|
|
{page: false}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should combine custom and overrides filters', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
custom: {tag: 'photo'}
|
|
};
|
|
const output = {$and: [
|
|
{status: 'published'},
|
|
{tag: 'photo'}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom).should.eql(output);
|
|
});
|
|
|
|
it('should remove custom filters if matches overrides', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
custom: {status: 'draft'}
|
|
};
|
|
const output = {status: 'published'};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom).should.eql(output);
|
|
});
|
|
|
|
it('should reduce custom filters if any matches overrides', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
custom: {$or: [
|
|
{tag: 'photo'},
|
|
{status: 'draft'}
|
|
]}
|
|
};
|
|
const output = {$and: [
|
|
{status: 'published'},
|
|
{$or: [
|
|
{tag: 'photo'}
|
|
]}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom).should.eql(output);
|
|
});
|
|
|
|
it('should combine default filters if default and custom are provided', function () {
|
|
const input = {
|
|
defaults: {page: false},
|
|
custom: {tag: 'photo'}
|
|
};
|
|
const output = {$and: [
|
|
{tag: 'photo'},
|
|
{page: false}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should reduce default filters if default and custom are same', function () {
|
|
const input = {
|
|
defaults: {page: false},
|
|
custom: {page: true}
|
|
};
|
|
const output = {page: true};
|
|
|
|
mongoUtils.mergeFilters(input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should match nested $and with a key inside primary filter', function () {
|
|
const input = {
|
|
defaults: {
|
|
$and: [
|
|
{page: false},
|
|
{status: 'published'}
|
|
]
|
|
},
|
|
custom: {
|
|
page: {
|
|
$in: [false,true]
|
|
}
|
|
}
|
|
};
|
|
const output = {$and: [
|
|
{page: {
|
|
$in: [false,true]
|
|
}},
|
|
{$and: [
|
|
{status: 'published'}
|
|
]}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should reduce default filters if default and custom overlap', function () {
|
|
const input = {
|
|
defaults: {$or: [
|
|
{page: false},
|
|
{author: 'cameron'}
|
|
]},
|
|
custom: {$and: [
|
|
{tag: 'photo'},
|
|
{page: true}
|
|
]}
|
|
};
|
|
const output = {$and: [
|
|
{$and: [
|
|
{tag: 'photo'},
|
|
{page: true}
|
|
]},
|
|
{$or: [
|
|
{author: 'cameron'}
|
|
]}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should return a merger of overrides and defaults plus custom filters if provided', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
defaults: {page: false},
|
|
custom: {tag: 'photo'}
|
|
};
|
|
const output = {$and: [
|
|
{$and: [
|
|
{status: 'published'},
|
|
{tag: 'photo'}
|
|
]},
|
|
{page: false}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('should handle getting overrides, default and multiple custom filters', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
defaults: {page: true},
|
|
custom: {$or: [
|
|
{tag: {
|
|
$in: ['photo','video']
|
|
}},
|
|
{author: 'cameron'}
|
|
]}
|
|
};
|
|
|
|
const output = {$and: [
|
|
{
|
|
$and: [
|
|
{
|
|
status: 'published'
|
|
},
|
|
{
|
|
$or: [
|
|
{
|
|
tag: {$in: ['photo','video']}
|
|
},
|
|
{
|
|
author: 'cameron'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
page: true
|
|
}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('combination of all filters', function () {
|
|
const input = {
|
|
overrides: {featured: true},
|
|
defaults: {page: false},
|
|
custom: {status: {$in: ['draft','published']}}
|
|
};
|
|
const output = {$and: [
|
|
{$and: [
|
|
{featured: true},
|
|
{
|
|
status: {
|
|
$in: ['draft', 'published']
|
|
}
|
|
}
|
|
]},
|
|
{page: false}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom, input.defaults).should.eql(output);
|
|
});
|
|
|
|
it('does not match incorrect custom filters', function () {
|
|
const input = {
|
|
overrides: {status: 'published'},
|
|
defaults: {page: false},
|
|
custom: {$or: [
|
|
{page: true},
|
|
{statusstatus: ':5Bdraft%2Cpublished%5D'}
|
|
]}
|
|
};
|
|
const output = {$and: [
|
|
{status: 'published'},
|
|
{$or: [
|
|
{page: true},
|
|
{statusstatus: ':5Bdraft%2Cpublished%5D'}
|
|
]}
|
|
]};
|
|
|
|
mongoUtils.mergeFilters(input.overrides, input.custom, input.defaults).should.eql(output);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Expand filters', function () {
|
|
let expandFilters;
|
|
|
|
beforeEach(function () {
|
|
expandFilters = mongoUtils.expandFilters;
|
|
});
|
|
|
|
it('should return unchanged filter when no expansions match', function () {
|
|
expandFilters({status: 'published'}, []).should.eql({status: 'published'});
|
|
});
|
|
|
|
it('should substitute single alias without expansion', function () {
|
|
const filter = {primary_tag: 'en'};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug'
|
|
}];
|
|
|
|
const processed = {'tags.slug': 'en'};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute single alias', function () {
|
|
const filter = {primary_tag: 'en'};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{'tags.slug': 'en'},
|
|
{order: 0}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute single alias with multiple expansions', function () {
|
|
const filter = {primary_tag: 'en'};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {$and: [{order: 0}, {visibility: 'public'}]}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{'tags.slug': 'en'},
|
|
{order: 0},
|
|
{visibility: 'public'}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute filter with negation and - sign', function () {
|
|
const filter = {
|
|
primary_tag: {
|
|
$ne: 'great-movies'
|
|
}
|
|
};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{'tags.slug': {
|
|
$ne: 'great-movies'
|
|
}},
|
|
{order: 0}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should NOT match similarly named filter keys', function () {
|
|
const filter = {tags: 'hello'};
|
|
const expansions = [{
|
|
key: 'tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {tags: 'hello'};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute IN notation single alias', function () {
|
|
const filter = {primary_tag: {
|
|
$in: ['en', 'es']
|
|
}};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{'tags.slug': {$in: ['en', 'es']}},
|
|
{order: 0}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute single alias nested in $and statement', function () {
|
|
const filter = {$and: [
|
|
{status: 'published'},
|
|
{featured: true},
|
|
{primary_tag: {$in: ['en', 'es']}}
|
|
]};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{status: 'published'},
|
|
{featured: true},
|
|
{$and: [
|
|
{'tags.slug': {$in: ['en', 'es']}},
|
|
{order: 0}]}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute multiple occurrences of the filter with expansions', function () {
|
|
const filter = {$and: [
|
|
{status: 'published'},
|
|
{primary_tag: 'de'},
|
|
{featured: true},
|
|
{primary_tag: 'en'}
|
|
]};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{status: 'published'},
|
|
{$and: [
|
|
{'tags.slug': 'de'},
|
|
{order: 0}
|
|
]},
|
|
{featured: true},
|
|
{$and: [
|
|
{'tags.slug': 'en'},
|
|
{order: 0}
|
|
]}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('should substitute multiple nested on different levels occurrences', function () {
|
|
const filter = {$and: [
|
|
{status: 'published'},
|
|
{primary_tag: 'de'},
|
|
{featured: true},
|
|
{$or: [
|
|
{primary_tag: 'us'},
|
|
{primary_tag: 'es'}
|
|
]}
|
|
], $or: [
|
|
{primary_tag: 'pl'}
|
|
]};
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {$and: [
|
|
{status: 'published'},
|
|
{$and: [
|
|
{'tags.slug': 'de'},
|
|
{order: 0}
|
|
]},
|
|
{featured: true},
|
|
{$or: [
|
|
{$and: [
|
|
{'tags.slug': 'us'},
|
|
{order: 0}
|
|
]},
|
|
{$and: [
|
|
{'tags.slug': 'es'},
|
|
{order: 0}
|
|
]}
|
|
]}
|
|
], $or: [
|
|
{$and: [
|
|
{'tags.slug': 'pl'},
|
|
{order: 0}
|
|
]}
|
|
]};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
|
|
it('combine multiple expansions', function () {
|
|
const filter = {$and: [{primary_tag: 'yalla'},{primary_author: 'hulk'}]};
|
|
|
|
const expansions = [{
|
|
key: 'primary_tag',
|
|
replacement: 'tags.slug',
|
|
expansion: {order: 0}
|
|
}, {
|
|
key: 'primary_author',
|
|
replacement: 'authors.slug',
|
|
expansion: {order: 0}
|
|
}];
|
|
|
|
const processed = {
|
|
$and: [
|
|
{
|
|
$and: [
|
|
{
|
|
'tags.slug': 'yalla'
|
|
},
|
|
{
|
|
order: 0
|
|
}
|
|
]
|
|
},
|
|
{
|
|
$and: [
|
|
{
|
|
'authors.slug': 'hulk'
|
|
},
|
|
{
|
|
order: 0
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
|
|
expandFilters(filter, expansions).should.eql(processed);
|
|
});
|
|
});
|
|
|
|
describe('mapQuery', function () {
|
|
it('uses the return value instead of existing value', function () {
|
|
const filter = {
|
|
$and: [{
|
|
hello: 'world'
|
|
}, {
|
|
never: {
|
|
$ne: 'have i ever'
|
|
}
|
|
}, {
|
|
list: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
};
|
|
|
|
mongoUtils.mapQuery(filter, function (value, key) {
|
|
return {
|
|
[key.toUpperCase()]: value
|
|
};
|
|
}).should.eql({
|
|
$and: [{
|
|
HELLO: 'world'
|
|
}, {
|
|
NEVER: {
|
|
$ne: 'have i ever'
|
|
}
|
|
}, {
|
|
LIST: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('can modify both key and value', function () {
|
|
const filter = {
|
|
$and: [{
|
|
oh: 'no'
|
|
}, {
|
|
oh: 'yes'
|
|
}, {
|
|
untouched: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
};
|
|
|
|
mongoUtils.mapQuery(filter, function (value, key) {
|
|
if (key === 'oh') {
|
|
if (value === 'no') {
|
|
return {
|
|
['hey']: 'nay'
|
|
};
|
|
} else if (value === 'yes') {
|
|
return {
|
|
['hey']: 'ay'
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
[key]: value
|
|
};
|
|
}).should.eql({
|
|
$and: [{
|
|
hey: 'nay'
|
|
}, {
|
|
hey: 'ay'
|
|
}, {
|
|
untouched: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('allows removal of queries by returning undefined', function () {
|
|
const filter = {
|
|
$and: [{
|
|
hello: 'world'
|
|
}, {
|
|
never: {
|
|
$ne: 'have i ever'
|
|
}
|
|
}, {
|
|
DELETEME: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
};
|
|
|
|
mongoUtils.mapQuery(filter, function (value, key) {
|
|
if (key === 'DELETEME') {
|
|
return;
|
|
}
|
|
return {
|
|
[key]: value
|
|
};
|
|
}).should.eql({
|
|
$and: [{
|
|
hello: 'world'
|
|
}, {
|
|
never: {
|
|
$ne: 'have i ever'
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('allows removal of parents by emptying the children', function () {
|
|
const filter = {
|
|
$and: [{
|
|
hello: 'world'
|
|
}, {
|
|
never: {
|
|
$ne: 'have i ever'
|
|
}
|
|
}, {
|
|
DELETEME: {
|
|
$in: ['a', 'b']
|
|
}
|
|
}]
|
|
};
|
|
|
|
mongoUtils.mapQuery(filter, function (/*value, key*/) {
|
|
return;
|
|
}).should.eql({
|
|
// EMPTY
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('mapKeyValues', function () {
|
|
it('Is able to replace both keys and values', function () {
|
|
const query = {
|
|
good: true
|
|
};
|
|
|
|
const transformer = mongoUtils.mapKeyValues({
|
|
key: {
|
|
from: 'good',
|
|
to: 'bad'
|
|
},
|
|
values: [{
|
|
from: true,
|
|
to: false
|
|
}, {
|
|
from: false,
|
|
to: true
|
|
}]
|
|
});
|
|
|
|
transformer(query).should.eql({
|
|
bad: false
|
|
});
|
|
});
|
|
|
|
it('Is able to replace nested keys and values', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
good: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const transformer = mongoUtils.mapKeyValues({
|
|
key: {
|
|
from: 'good',
|
|
to: 'bad'
|
|
},
|
|
values: [{
|
|
from: true,
|
|
to: false
|
|
}, {
|
|
from: false,
|
|
to: true
|
|
}]
|
|
});
|
|
|
|
transformer(query).should.eql({
|
|
$and: [{
|
|
bad: {
|
|
$ne: true
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
bad: {
|
|
$ne: false
|
|
}
|
|
}]
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getUsedKeys', function () {
|
|
it('Returns all keys', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else',
|
|
multiple: 'keys'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
mongoUtils.getUsedKeys(query).should.eql(['good', 'something', 'multiple', 'other']);
|
|
});
|
|
|
|
it('Does not return duplicate keys', function () {
|
|
const query = {
|
|
$and: [
|
|
{good: {$ne: false}},
|
|
{good: 'other'}
|
|
]
|
|
};
|
|
|
|
mongoUtils.getUsedKeys(query).should.eql(['good']);
|
|
});
|
|
|
|
it('Returns empty array for undefined filters', function () {
|
|
mongoUtils.getUsedKeys().should.eql([]);
|
|
});
|
|
});
|
|
|
|
describe('mapKeys', function () {
|
|
it('Maps multiple keys', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const chained = mongoUtils.chainTransformers(...mongoUtils.mapKeys({
|
|
good: 'bad',
|
|
something: 'elsewhere',
|
|
other: 'another'
|
|
}));
|
|
|
|
assert.deepEqual(chained(query), {
|
|
$and: [{
|
|
bad: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
elsewhere: 'else'
|
|
}, {
|
|
another: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('replaceFilters', function () {
|
|
it('Can replace a filter by key', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const updatedQuery = mongoUtils.replaceFilters(query, {
|
|
something: {
|
|
else: true
|
|
}
|
|
});
|
|
|
|
assert.deepEqual(updatedQuery, {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
else: true
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Chain transformers', function () {
|
|
it('Passes filter from transformer to transformer', function () {
|
|
const transformer1 = (f) => {
|
|
return {
|
|
transformer1: f
|
|
};
|
|
};
|
|
const transformer2 = (f) => {
|
|
return {
|
|
transformer2: f
|
|
};
|
|
};
|
|
|
|
const chained = mongoUtils.chainTransformers(transformer1, transformer2);
|
|
assert.deepEqual(chained('test'), {
|
|
transformer2: {
|
|
transformer1: 'test'
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('splitFilter', function () {
|
|
it('Can split AND', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['good']);
|
|
first.should.eql({
|
|
good: {
|
|
$ne: false
|
|
}
|
|
});
|
|
second.should.eql({
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Does a simple pass through to yg contents', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['good']);
|
|
assert.deepEqual(first, {
|
|
good: {
|
|
$ne: false
|
|
}
|
|
});
|
|
assert.deepEqual(second, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Can split long AND', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['good']);
|
|
first.should.eql({
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}]
|
|
});
|
|
second.should.eql({
|
|
$and: [{
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Can\'t split subfilter in AND using both', function () {
|
|
const query = {
|
|
$and: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
good: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
assert.throws(() => mongoUtils.splitFilter(query, ['good']), /This filter is not supported because you cannot combine good filters with other filters except at the root level in an AND/);
|
|
});
|
|
|
|
it('Cannot split OR', function () {
|
|
const query = {
|
|
$or: [{
|
|
good: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
assert.throws(() => mongoUtils.splitFilter(query, ['good']), /This filter is not supported because you cannot combine good filters with other filters in an OR/);
|
|
});
|
|
|
|
it('Can use OR if everything belongs in second group', function () {
|
|
const query = {
|
|
$or: [{
|
|
other2: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['good']);
|
|
assert.equal(first, undefined);
|
|
assert.equal(second, query);
|
|
});
|
|
|
|
it('Can use OR if everything belongs in first group', function () {
|
|
const query = {
|
|
$or: [{
|
|
other2: {
|
|
$ne: false
|
|
}
|
|
}, {
|
|
$or: [{
|
|
something: 'else'
|
|
}, {
|
|
other: {
|
|
$ne: true
|
|
}
|
|
}]
|
|
}]
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['other2', 'something', 'other']);
|
|
assert.equal(first, query);
|
|
assert.equal(second, undefined);
|
|
});
|
|
|
|
it('Returns both undefined for undefined filter', function () {
|
|
const [first, second] = mongoUtils.splitFilter(undefined, ['other2', 'something', 'other']);
|
|
assert.equal(first, undefined);
|
|
assert.equal(second, undefined);
|
|
});
|
|
|
|
it('Can split object', function () {
|
|
const query = {
|
|
good: true,
|
|
good2: true,
|
|
bad: false,
|
|
bad2: false
|
|
};
|
|
|
|
const [first, second] = mongoUtils.splitFilter(query, ['good', 'good2']);
|
|
assert.deepEqual(first, {
|
|
good: true,
|
|
good2: true
|
|
});
|
|
assert.deepEqual(second, {
|
|
bad: false,
|
|
bad2: false
|
|
});
|
|
});
|
|
});
|