Skip to content

Commit 995e282

Browse files
authored
Merge pull request #395 from emilefokkemanavara/fix/352/v8
re-apply the changes from #390 onto v8
2 parents 53f66b1 + b8b6f30 commit 995e282

File tree

3 files changed

+122
-2
lines changed

3 files changed

+122
-2
lines changed

test/engine-event.test.mjs

+64
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ describe("Engine: event", () => {
1313
canOrderDrinks: true,
1414
},
1515
};
16+
17+
const awesomeEvent = {
18+
type: 'awesome'
19+
}
1620
/**
1721
* sets up a simple 'any' rule with 2 conditions
1822
*/
@@ -85,6 +89,46 @@ describe("Engine: event", () => {
8589
engine.addFact("gender", "male"); // gender succeeds
8690
}
8791

92+
function setupWithConditionReference () {
93+
const conditionName = 'awesomeCondition'
94+
const conditions = {
95+
any: [{ condition: conditionName }]
96+
}
97+
engine = engineFactory()
98+
const ruleOptions = { conditions, event: awesomeEvent, priority: 100 }
99+
const rule = ruleFactory(ruleOptions)
100+
engine.addRule(rule)
101+
engine.setCondition(conditionName, {
102+
all: [{
103+
name: 'over 21',
104+
fact: 'age',
105+
operator: 'greaterThanInclusive',
106+
value: 21
107+
}]
108+
})
109+
engine.addFact('age', 21)
110+
}
111+
112+
function setupWithUndefinedCondition () {
113+
const conditionName = 'conditionThatIsNotDefined'
114+
const conditions = {
115+
any: [
116+
{ condition: conditionName, name: 'nameOfTheUndefinedConditionReference' },
117+
{
118+
name: 'over 21',
119+
fact: 'age',
120+
operator: 'greaterThanInclusive',
121+
value: 21
122+
}
123+
]
124+
}
125+
engine = engineFactory([], { allowUndefinedConditions: true })
126+
const ruleOptions = { conditions, event: awesomeEvent, priority: 100 }
127+
const rule = ruleFactory(ruleOptions)
128+
engine.addRule(rule)
129+
engine.addFact('age', 21)
130+
}
131+
88132
describe("engine events: simple", () => {
89133
beforeEach(() => simpleSetup());
90134

@@ -647,4 +691,24 @@ describe("Engine: event", () => {
647691
expect(JSON.stringify(ruleResult)).toBe(expected);
648692
});
649693
});
694+
695+
describe('rule events: json serializing with condition reference', () => {
696+
beforeEach(() => setupWithConditionReference())
697+
it('serializes properties', async () => {
698+
const { results: [ruleResult] } = await engine.run()
699+
const expected = '{"conditions":{"priority":1,"any":[{"priority":1,"all":[{"name":"over 21","operator":"greaterThanInclusive","value":21,"fact":"age","factResult":21,"result":true}]}]},"event":{"type":"awesome"},"priority":100,"result":true}'
700+
expect(JSON.stringify(ruleResult)).toEqual(expected)
701+
})
702+
})
703+
704+
describe('rule events: json serializing with condition reference that is undefined', () => {
705+
beforeEach(() => setupWithUndefinedCondition())
706+
it('serializes properties', async () => {
707+
const { results: [ruleResult] } = await engine.run()
708+
const { conditions: { any: [conditionReference] } } = ruleResult
709+
expect(conditionReference.result).toEqual(false)
710+
const expected = '{"conditions":{"priority":1,"any":[{"name":"nameOfTheUndefinedConditionReference","condition":"conditionThatIsNotDefined"},{"name":"over 21","operator":"greaterThanInclusive","value":21,"fact":"age","factResult":21,"result":true}]},"event":{"type":"awesome"},"priority":100,"result":true}'
711+
expect(JSON.stringify(ruleResult)).toEqual(expected)
712+
})
713+
})
650714
});

test/types.test-d.mts

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import rulesEngine, {
1515
RuleProperties,
1616
RuleResult,
1717
RuleSerializable,
18+
TopLevelConditionResult,
19+
AnyConditionsResult,
20+
AllConditionsResult,
21+
NotConditionsResult
1822
} from "../types/index.js";
1923

2024
// setup basic fixture data
@@ -63,7 +67,20 @@ describe("type tests", () => {
6367
const engine = rulesEngine([complexRuleProps]);
6468

6569
it("engine run returns a promise of the result", () => {
66-
expectTypeOf<Promise<EngineResult>>(engine.run({ displayMessage: true }));
70+
const result = engine.run({ displayMessage: true })
71+
expectTypeOf<Promise<EngineResult>>(result);
72+
73+
const topLevelConditionResult = result.then(r => r.results[0].conditions);
74+
expectTypeOf<Promise<TopLevelConditionResult>>(topLevelConditionResult)
75+
76+
const topLevelAnyConditionsResult = topLevelConditionResult.then(r => (r as AnyConditionsResult).result);
77+
expectTypeOf<Promise<boolean | undefined>>(topLevelAnyConditionsResult)
78+
79+
const topLevelAllConditionsResult = topLevelConditionResult.then(r => (r as AllConditionsResult).result);
80+
expectTypeOf<Promise<boolean | undefined>>(topLevelAllConditionsResult)
81+
82+
const topLevelNotConditionsResult = topLevelConditionResult.then(r => (r as NotConditionsResult).result);
83+
expectTypeOf<Promise<boolean | undefined>>(topLevelNotConditionsResult)
6784
});
6885

6986
describe("rule tests", () => {

types/index.d.ts

+40-1
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,22 @@ export type RuleSerializable = Pick<
170170
"conditions" | "event" | "name" | "priority"
171171
>;
172172

173+
export type RuleResultSerializable = Pick<
174+
Required<RuleResult>,
175+
"name" | "event" | "priority" | "result"> & {
176+
conditions: TopLevelConditionResultSerializable
177+
}
178+
173179
export interface RuleResult {
174180
name: string;
175-
conditions: TopLevelCondition;
181+
conditions: TopLevelConditionResult;
176182
event?: Event;
177183
priority?: number;
178184
result: any;
185+
toJSON(): string;
186+
toJSON<T extends boolean>(
187+
stringify: T
188+
): T extends true ? string : RuleResultSerializable;
179189
}
180190

181191
export class Rule implements RuleProperties {
@@ -193,6 +203,14 @@ export class Rule implements RuleProperties {
193203
): T extends true ? string : RuleSerializable;
194204
}
195205

206+
interface BooleanConditionResultProperties {
207+
result?: boolean
208+
}
209+
210+
interface ConditionResultProperties extends BooleanConditionResultProperties {
211+
factResult?: unknown
212+
}
213+
196214
interface ConditionProperties {
197215
fact: string;
198216
operator: string;
@@ -203,25 +221,46 @@ interface ConditionProperties {
203221
name?: string;
204222
}
205223

224+
type ConditionPropertiesResult = ConditionProperties & ConditionResultProperties
225+
206226
type NestedCondition = ConditionProperties | TopLevelCondition;
227+
type NestedConditionResult = ConditionPropertiesResult | TopLevelConditionResult;
207228
type AllConditions = {
208229
all: NestedCondition[];
209230
name?: string;
210231
priority?: number;
211232
};
233+
type AllConditionsResult = AllConditions & {
234+
all: NestedConditionResult[]
235+
} & BooleanConditionResultProperties
212236
type AnyConditions = {
213237
any: NestedCondition[];
214238
name?: string;
215239
priority?: number;
216240
};
241+
type AnyConditionsResult = AnyConditions & {
242+
any: NestedConditionResult[]
243+
} & BooleanConditionResultProperties
217244
type NotConditions = { not: NestedCondition; name?: string; priority?: number };
245+
type NotConditionsResult = NotConditions & {not: NestedConditionResult} & BooleanConditionResultProperties;
218246
type ConditionReference = {
219247
condition: string;
220248
name?: string;
221249
priority?: number;
222250
};
251+
type ConditionReferenceResult = ConditionReference & BooleanConditionResultProperties
223252
export type TopLevelCondition =
224253
| AllConditions
225254
| AnyConditions
226255
| NotConditions
227256
| ConditionReference;
257+
export type TopLevelConditionResult =
258+
| AllConditionsResult
259+
| AnyConditionsResult
260+
| NotConditionsResult
261+
| ConditionReferenceResult
262+
export type TopLevelConditionResultSerializable =
263+
| AllConditionsResult
264+
| AnyConditionsResult
265+
| NotConditionsResult
266+
| ConditionReference

0 commit comments

Comments
 (0)