Skip to content

Commit

Permalink
feat: ability to specific or operations
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeIbberson committed Mar 3, 2022
1 parent 5f525be commit a42c77a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
22 changes: 20 additions & 2 deletions lib/__tests__/comparison.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,26 @@ describe('Comparison', () => {
describe('query', () => {
it('should return truthy on dynamic matching', () =>
expect(
new Comparison(['dynamic={{age}}']).query(stub),
).toMatchObject({}));
new Comparison({
operand: '$or',
expressions: [
'dynamic={{age}}',
'foo={{deeply.deeply.nested}}',
],
}).query({
...stub,
deeply: { deeply: { nested: 'bar' } },
}),
).toMatchObject({
$or: [
{
dynamic: 21,
},
{
foo: /bar/i,
},
],
}));

it('should return as mongo query', () =>
expect(new Comparison(exp).query(stub)).toMatchObject({
Expand Down
40 changes: 32 additions & 8 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,19 @@ const getAssignment = {
}),
};

const getValue = (target = {}, key) =>
get(flat(target, { safe: true }), key);
const isObject = (v) => typeof v === 'object';
const toPlainObject = (xs) => {
try {
return isObject(xs) ? JSON.parse(JSON.stringify(xs)) : xs;
} catch (e) {
return xs;
}
};

const flatten = (xs) =>
flat(toPlainObject(xs), {
safe: true,
});

const keys = Object.keys(ops);
const re = new RegExp(`[${keys.map((v) => `(${v})`).join('')}]`, 'i');
Expand All @@ -73,7 +84,7 @@ const getOp = (v) => {
try {
const prop = v.split('{{')[1].split('}}')[0];
return getOp(
v.replace(TEMPLATE_VARIABLE_PATTERN, getValue(obj, prop)),
v.replace(TEMPLATE_VARIABLE_PATTERN, get(obj, prop)),
);
} catch (e) {
throw new Error('Template variable not properly formatted');
Expand All @@ -98,7 +109,15 @@ const getOp = (v) => {

class Comparison {
constructor(exp, locale = 'en') {
this.expressions = hasLength(exp) ? exp : [];
if (Array.isArray(exp) || !isObject(exp)) {
this.expressions = hasLength(exp) ? exp : [];
this.operand = '$and';
} else {
const { operand = '$and', expressions = [] } = exp;
this.expressions = expressions;
this.operand = operand;
}

this.locale = locale;
}

Expand All @@ -114,16 +133,18 @@ class Comparison {
}

query(obj = {}) {
const preflattened = flatten(obj);

return {
$and: this.eligible.reduce((a, params) => {
[this.operand]: this.eligible.reduce((a, params) => {
let key;
let value;
let fn;

if (Array.isArray(params)) {
[key, value, fn] = params;
} else if (isFn(params)) {
[key, value, fn] = params(obj);
[key, value, fn] = params(preflattened);
} else {
return a;
}
Expand All @@ -143,13 +164,16 @@ class Comparison {
}

eval(obj) {
return this.eligible.every((params) => {
const method = this.operand === '$and' ? 'every' : 'some';
const preflattened = flatten(obj);

return this.eligible[method]((params) => {
const [key, value, validator] = isFn(params)
? params(obj)
: params;

return isFn(validator)
? validator(getValue(obj, key), value, this.locale)
? validator(get(preflattened, key), value, this.locale)
: false;
});
}
Expand Down

0 comments on commit a42c77a

Please sign in to comment.