Skip to content

Commit

Permalink
Merge pull request #395 from emilefokkemanavara/fix/352/v8
Browse files Browse the repository at this point in the history
re-apply the changes from #390 onto v8
  • Loading branch information
chris-pardy authored Nov 15, 2024
2 parents 53f66b1 + b8b6f30 commit 995e282
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 2 deletions.
64 changes: 64 additions & 0 deletions test/engine-event.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ describe("Engine: event", () => {
canOrderDrinks: true,
},
};

const awesomeEvent = {
type: 'awesome'
}
/**
* sets up a simple 'any' rule with 2 conditions
*/
Expand Down Expand Up @@ -85,6 +89,46 @@ describe("Engine: event", () => {
engine.addFact("gender", "male"); // gender succeeds
}

function setupWithConditionReference () {
const conditionName = 'awesomeCondition'
const conditions = {
any: [{ condition: conditionName }]
}
engine = engineFactory()
const ruleOptions = { conditions, event: awesomeEvent, priority: 100 }
const rule = ruleFactory(ruleOptions)
engine.addRule(rule)
engine.setCondition(conditionName, {
all: [{
name: 'over 21',
fact: 'age',
operator: 'greaterThanInclusive',
value: 21
}]
})
engine.addFact('age', 21)
}

function setupWithUndefinedCondition () {
const conditionName = 'conditionThatIsNotDefined'
const conditions = {
any: [
{ condition: conditionName, name: 'nameOfTheUndefinedConditionReference' },
{
name: 'over 21',
fact: 'age',
operator: 'greaterThanInclusive',
value: 21
}
]
}
engine = engineFactory([], { allowUndefinedConditions: true })
const ruleOptions = { conditions, event: awesomeEvent, priority: 100 }
const rule = ruleFactory(ruleOptions)
engine.addRule(rule)
engine.addFact('age', 21)
}

describe("engine events: simple", () => {
beforeEach(() => simpleSetup());

Expand Down Expand Up @@ -647,4 +691,24 @@ describe("Engine: event", () => {
expect(JSON.stringify(ruleResult)).toBe(expected);
});
});

describe('rule events: json serializing with condition reference', () => {
beforeEach(() => setupWithConditionReference())
it('serializes properties', async () => {
const { results: [ruleResult] } = await engine.run()
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}'
expect(JSON.stringify(ruleResult)).toEqual(expected)
})
})

describe('rule events: json serializing with condition reference that is undefined', () => {
beforeEach(() => setupWithUndefinedCondition())
it('serializes properties', async () => {
const { results: [ruleResult] } = await engine.run()
const { conditions: { any: [conditionReference] } } = ruleResult
expect(conditionReference.result).toEqual(false)
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}'
expect(JSON.stringify(ruleResult)).toEqual(expected)
})
})
});
19 changes: 18 additions & 1 deletion test/types.test-d.mts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import rulesEngine, {
RuleProperties,
RuleResult,
RuleSerializable,
TopLevelConditionResult,
AnyConditionsResult,
AllConditionsResult,
NotConditionsResult
} from "../types/index.js";

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

it("engine run returns a promise of the result", () => {
expectTypeOf<Promise<EngineResult>>(engine.run({ displayMessage: true }));
const result = engine.run({ displayMessage: true })
expectTypeOf<Promise<EngineResult>>(result);

const topLevelConditionResult = result.then(r => r.results[0].conditions);
expectTypeOf<Promise<TopLevelConditionResult>>(topLevelConditionResult)

const topLevelAnyConditionsResult = topLevelConditionResult.then(r => (r as AnyConditionsResult).result);
expectTypeOf<Promise<boolean | undefined>>(topLevelAnyConditionsResult)

const topLevelAllConditionsResult = topLevelConditionResult.then(r => (r as AllConditionsResult).result);
expectTypeOf<Promise<boolean | undefined>>(topLevelAllConditionsResult)

const topLevelNotConditionsResult = topLevelConditionResult.then(r => (r as NotConditionsResult).result);
expectTypeOf<Promise<boolean | undefined>>(topLevelNotConditionsResult)
});

describe("rule tests", () => {
Expand Down
41 changes: 40 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,22 @@ export type RuleSerializable = Pick<
"conditions" | "event" | "name" | "priority"
>;

export type RuleResultSerializable = Pick<
Required<RuleResult>,
"name" | "event" | "priority" | "result"> & {
conditions: TopLevelConditionResultSerializable
}

export interface RuleResult {
name: string;
conditions: TopLevelCondition;
conditions: TopLevelConditionResult;
event?: Event;
priority?: number;
result: any;
toJSON(): string;
toJSON<T extends boolean>(
stringify: T
): T extends true ? string : RuleResultSerializable;
}

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

interface BooleanConditionResultProperties {
result?: boolean
}

interface ConditionResultProperties extends BooleanConditionResultProperties {
factResult?: unknown
}

interface ConditionProperties {
fact: string;
operator: string;
Expand All @@ -203,25 +221,46 @@ interface ConditionProperties {
name?: string;
}

type ConditionPropertiesResult = ConditionProperties & ConditionResultProperties

type NestedCondition = ConditionProperties | TopLevelCondition;
type NestedConditionResult = ConditionPropertiesResult | TopLevelConditionResult;
type AllConditions = {
all: NestedCondition[];
name?: string;
priority?: number;
};
type AllConditionsResult = AllConditions & {
all: NestedConditionResult[]
} & BooleanConditionResultProperties
type AnyConditions = {
any: NestedCondition[];
name?: string;
priority?: number;
};
type AnyConditionsResult = AnyConditions & {
any: NestedConditionResult[]
} & BooleanConditionResultProperties
type NotConditions = { not: NestedCondition; name?: string; priority?: number };
type NotConditionsResult = NotConditions & {not: NestedConditionResult} & BooleanConditionResultProperties;
type ConditionReference = {
condition: string;
name?: string;
priority?: number;
};
type ConditionReferenceResult = ConditionReference & BooleanConditionResultProperties
export type TopLevelCondition =
| AllConditions
| AnyConditions
| NotConditions
| ConditionReference;
export type TopLevelConditionResult =
| AllConditionsResult
| AnyConditionsResult
| NotConditionsResult
| ConditionReferenceResult
export type TopLevelConditionResultSerializable =
| AllConditionsResult
| AnyConditionsResult
| NotConditionsResult
| ConditionReference

0 comments on commit 995e282

Please sign in to comment.