Skip to content

re-apply the changes from #390 onto v8 #395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading