Skip to content

Commit 71aaadb

Browse files
committed
Merge branch 'feature/CG-1009' into 'master'
feat(operator): Allows comparison with fields on the same object Closes CG-1009 See merge request auto-cloud/cloudgraph/sdk!57
2 parents 9fb710e + 893a87c commit 71aaadb

File tree

3 files changed

+287
-1
lines changed

3 files changed

+287
-1
lines changed

src/rules-engine/evaluators/json-evaluator.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '../types'
1313
import { RuleEvaluator } from './rule-evaluator'
1414
import AdditionalOperators from '../operators'
15+
import ComparisonOperators from '../operators/comparison'
1516

1617
export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
1718
canEvaluate(rule: JsonRule): boolean {
@@ -124,14 +125,25 @@ export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
124125
// remaining field should be the op name
125126
const op = Object.keys(condition)[0] //
126127
const operator = this.operators[op]
127-
const otherArgs = condition[op] // {[and]: xxx }
128+
let otherArgs = condition[op] // {[and]: xxx }
128129
if (!op || !operator) {
129130
throw new Error(`unrecognized operation${JSON.stringify(condition)}`)
130131
}
131132

132133
const data = { ..._data }
133134
let firstArg
134135

136+
if (
137+
Object.keys(ComparisonOperators).includes(operator.name) &&
138+
this.isCondition(otherArgs) &&
139+
otherArgs.path
140+
) {
141+
const resourceData = { ..._data }
142+
const elementPath = this.calculatePath(resourceData, otherArgs.path)
143+
resourceData.elementPath = elementPath
144+
otherArgs = this.resolvePath(resourceData, elementPath)
145+
}
146+
135147
if (path) {
136148
const elementPath = this.calculatePath(data, path)
137149
data.elementPath = elementPath

tests/json-evaluator.test.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,4 +421,113 @@ describe('JsonEvaluator', () => {
421421

422422
expect(finding.result).toBe(Result.PASS)
423423
})
424+
425+
test('Should pass using the same value for the equal operator with the same path', async () => {
426+
const data = {
427+
data: { a: { b: [0, { e: 'same value', d: 'same value' }] } },
428+
}
429+
const rule = { path: 'a.b[1].d', equal: { path: 'a.b[1].e' } }
430+
431+
const finding = await evaluator.evaluateSingleResource(
432+
{
433+
conditions: rule,
434+
resource: {
435+
id: cuid(),
436+
},
437+
} as any,
438+
data
439+
)
440+
441+
expect(finding.result).toBe(Result.PASS)
442+
})
443+
444+
test('Should fail using two different values for the equal operator', async () => {
445+
const data = {
446+
data: { a: { b: [0, { e: 'not the same', d: 'values' }] } },
447+
}
448+
const rule = { path: 'a.b[1].d', equal: { path: 'a.b[1].e' } }
449+
450+
const finding = await evaluator.evaluateSingleResource(
451+
{
452+
conditions: rule,
453+
resource: {
454+
id: cuid(),
455+
},
456+
} as any,
457+
data
458+
)
459+
460+
expect(finding.result).toBe(Result.FAIL)
461+
})
462+
463+
test('Should fail using the same value for the equal operator but using a wrong path', async () => {
464+
const data = {
465+
data: { a: { b: [0, { e: 'values', d: 'values' }] } },
466+
}
467+
const rule = { path: 'a.b[1].d', equal: { path: 'b[0].e' } }
468+
469+
const finding = await evaluator.evaluateSingleResource(
470+
{
471+
conditions: rule,
472+
resource: {
473+
id: cuid(),
474+
},
475+
} as any,
476+
data
477+
)
478+
479+
expect(finding.result).toBe(Result.FAIL)
480+
})
481+
482+
test('Should pass comparing a date greater than other', async () => {
483+
const data = {
484+
data: {
485+
a: {
486+
b: [
487+
0,
488+
{ e: '2022-03-14T20:42:58.510Z', d: '2022-03-15T20:42:58.510Z' },
489+
],
490+
},
491+
},
492+
}
493+
const rule = { path: 'a.b[1].d', greaterThan: { path: 'a.b[1].e' } }
494+
495+
const finding = await evaluator.evaluateSingleResource(
496+
{
497+
conditions: rule,
498+
resource: {
499+
id: cuid(),
500+
},
501+
} as any,
502+
data
503+
)
504+
505+
expect(finding.result).toBe(Result.PASS)
506+
})
507+
508+
test('Should fail comparing a date after than other', async () => {
509+
const data = {
510+
data: {
511+
a: {
512+
b: [
513+
0,
514+
{ e: '2022-03-15T20:42:58.510Z', d: new Date().toISOString() },
515+
],
516+
},
517+
},
518+
}
519+
const rule = { path: 'a.b[1].d', lessThan: { path: 'a.b[1].e' } }
520+
521+
const finding = await evaluator.evaluateSingleResource(
522+
{
523+
conditions: rule,
524+
resource: {
525+
id: cuid(),
526+
},
527+
} as any,
528+
data
529+
)
530+
531+
expect(finding.result).toBe(Result.FAIL)
532+
})
424533
})

tests/operators/comparison.test.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import ComparisonOperators from '../../src/rules-engine/operators/comparison'
2+
3+
describe('Comparison Operators', () => {
4+
describe('Equal Operator', () => {
5+
test('Should pass given two equal strings', () => {
6+
const result = ComparisonOperators.equal('Switch', 'Switch')
7+
expect(result).toBeTruthy()
8+
})
9+
10+
test('Should fail given two different strings', () => {
11+
const result = ComparisonOperators.equal('PS5', 'Xbox Series X')
12+
expect(result).toBeFalsy()
13+
})
14+
test('Should pass given two different numbers', () => {
15+
const result = ComparisonOperators.equal(360, 360)
16+
expect(result).toBeTruthy()
17+
})
18+
test('Should fail given two different numbers', () => {
19+
const result = ComparisonOperators.equal(360, 90)
20+
expect(result).toBeFalsy()
21+
})
22+
test('Should pass given two equal values with different types', () => {
23+
const result = ComparisonOperators.equal(180, '180')
24+
expect(result).toBeTruthy()
25+
})
26+
})
27+
28+
describe('NotEqual Operator', () => {
29+
test('Should fail given two equal strings', () => {
30+
const result = ComparisonOperators.notEqual('Switch', 'Switch')
31+
expect(result).toBeFalsy()
32+
})
33+
34+
test('Should pass given two different strings', () => {
35+
const result = ComparisonOperators.notEqual('PS5', 'Xbox Series X')
36+
expect(result).toBeTruthy()
37+
})
38+
test('Should fail given two different numbers', () => {
39+
const result = ComparisonOperators.notEqual(360, 360)
40+
expect(result).toBeFalsy()
41+
})
42+
test('Should pass given two different numbers', () => {
43+
const result = ComparisonOperators.notEqual(360, 90)
44+
expect(result).toBeTruthy()
45+
})
46+
test('Should pass given two equal values with different types', () => {
47+
const result = ComparisonOperators.notEqual(180, '180')
48+
expect(result).toBeTruthy()
49+
})
50+
})
51+
52+
describe('LessThan and LessThanInclusive Operator', () => {
53+
test('Should fail if the first string is less than the second one', () => {
54+
const result = ComparisonOperators.lessThan('X', 'A')
55+
expect(result).toBeFalsy()
56+
})
57+
58+
test('Should fail comparing the same string', () => {
59+
const result = ComparisonOperators.lessThan('A', 'A')
60+
expect(result).toBeFalsy()
61+
})
62+
63+
test('Should pass if the first string is greater than the second one', () => {
64+
const result = ComparisonOperators.lessThan('A', 'X')
65+
expect(result).toBeTruthy()
66+
})
67+
68+
test('Should pass if the first number is less than the second one', () => {
69+
const result = ComparisonOperators.lessThan(10, 100)
70+
expect(result).toBeTruthy()
71+
})
72+
73+
test('Should fail comparing the same number', () => {
74+
const result = ComparisonOperators.lessThan(10, 10)
75+
expect(result).toBeFalsy()
76+
})
77+
78+
test('Should fail if the first number is greater than the second one', () => {
79+
const result = ComparisonOperators.lessThan(100, 10)
80+
expect(result).toBeFalsy()
81+
})
82+
83+
test('Should pass if the first number is less or equal than the second one', () => {
84+
expect(ComparisonOperators.lessThanInclusive(1, 10)).toBeTruthy()
85+
expect(ComparisonOperators.lessThanInclusive(10, 10)).toBeTruthy()
86+
})
87+
88+
test('Should pass if the first string is less or equal than the second one', () => {
89+
expect(ComparisonOperators.lessThanInclusive('a', 'x')).toBeTruthy()
90+
expect(ComparisonOperators.lessThanInclusive('a', 'a')).toBeTruthy()
91+
})
92+
93+
test('Should pass if the first date is before than the second one', () => {
94+
const result = ComparisonOperators.lessThan(
95+
'2022-03-15T20:42:58.510Z',
96+
new Date().toISOString()
97+
)
98+
expect(result).toBeTruthy()
99+
})
100+
test('Should fail if the first date is after than the second one', () => {
101+
const result = ComparisonOperators.lessThan(
102+
new Date().toISOString(),
103+
'2022-03-15T20:42:58.510Z'
104+
)
105+
expect(result).toBeFalsy()
106+
})
107+
})
108+
109+
describe('GreaterThan and GreaterThanInclusive Operator', () => {
110+
test('Should fail if the first string is greater than the second one', () => {
111+
const result = ComparisonOperators.greaterThan('A', 'X')
112+
expect(result).toBeFalsy()
113+
})
114+
115+
test('Should fail comparing the same string', () => {
116+
const result = ComparisonOperators.greaterThan('A', 'A')
117+
expect(result).toBeFalsy()
118+
})
119+
120+
test('Should pass if the first string is less than the second one', () => {
121+
const result = ComparisonOperators.greaterThan('X', 'A')
122+
expect(result).toBeTruthy()
123+
})
124+
125+
test('Should pass if the first number is greater than the second one', () => {
126+
const result = ComparisonOperators.greaterThan(100, 10)
127+
expect(result).toBeTruthy()
128+
})
129+
130+
test('Should fail comparing the same number', () => {
131+
const result = ComparisonOperators.greaterThan(10, 10)
132+
expect(result).toBeFalsy()
133+
})
134+
135+
test('Should fail if the first number is less than the second one', () => {
136+
const result = ComparisonOperators.greaterThan(10, 100)
137+
expect(result).toBeFalsy()
138+
})
139+
140+
test('Should pass if the first number is greater or equal than the second one', () => {
141+
expect(ComparisonOperators.greaterThanInclusive(10, 1)).toBeTruthy()
142+
expect(ComparisonOperators.greaterThanInclusive(10, 10)).toBeTruthy()
143+
})
144+
145+
test('Should pass if the first string is greater or equal than the second one', () => {
146+
expect(ComparisonOperators.greaterThanInclusive('x', 'a')).toBeTruthy()
147+
expect(ComparisonOperators.greaterThanInclusive('a', 'a')).toBeTruthy()
148+
})
149+
150+
test('Should pass if the first date is after than the second one', () => {
151+
const result = ComparisonOperators.greaterThan(
152+
new Date().toISOString(),
153+
'2022-03-15T20:42:58.510Z'
154+
)
155+
expect(result).toBeTruthy()
156+
})
157+
test('Should fail if the first date is before than the second one', () => {
158+
const result = ComparisonOperators.greaterThan(
159+
'2022-03-15T20:42:58.510Z',
160+
new Date().toISOString()
161+
)
162+
expect(result).toBeFalsy()
163+
})
164+
})
165+
})

0 commit comments

Comments
 (0)