From db278a44863ac06f6928cab33de2112e1399da07 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Thu, 10 Mar 2022 23:16:17 +0900 Subject: [PATCH 1/4] feat(iot-events): support comparison operators --- packages/@aws-cdk/aws-iotevents/README.md | 12 +- .../@aws-cdk/aws-iotevents/lib/expression.ts | 44 ++++++- .../aws-iotevents/test/detector-model.test.ts | 114 +++--------------- .../test/integ.detector-model.expected.json | 22 ++-- 4 files changed, 78 insertions(+), 114 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 9089fdec07cbd..db12291df9f12 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -81,20 +81,20 @@ const coldState = new iotevents.State({ stateName: 'cold', }); -// transit to coldState when temperature is 10 +// transit to coldState when temperature is less than 15 warmState.transitionTo(coldState, { eventName: 'to_coldState', // optional property, default by combining the names of the States - when: iotevents.Expression.eq( + when: iotevents.Expression.lt( iotevents.Expression.inputAttribute(input, 'payload.temperature'), - iotevents.Expression.fromString('10'), + iotevents.Expression.fromString('15'), ), executing: [new actions.LambdaInvokeAction(func)], // optional }); -// transit to warmState when temperature is 20 +// transit to warmState when temperature is greater than or equal to 15 coldState.transitionTo(warmState, { - when: iotevents.Expression.eq( + when: iotevents.Expression.gte( iotevents.Expression.inputAttribute(input, 'payload.temperature'), - iotevents.Expression.fromString('20'), + iotevents.Expression.fromString('15'), ), }); diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts index fd686e9761802..685c670c9fc19 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/expression.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -34,6 +34,41 @@ export abstract class Expression { return new BinaryOperationExpression(left, '==', right); } + /** + * Create a expression for the Not Equal operator. + */ + public static neq(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '!=', right); + } + + /** + * Create a expression for the Less Than operator. + */ + public static lt(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '<', right); + } + + /** + * Create a expression for the Less Than Or Equal operator. + */ + public static lte(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '<=', right); + } + + /** + * Create a expression for the Greater Than operator. + */ + public static gt(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '>', right); + } + + /** + * Create a expression for the Greater Than Or Equal operator. + */ + public static gte(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '>=', right); + } + /** * Create a expression for the AND operator. */ @@ -41,6 +76,13 @@ export abstract class Expression { return new BinaryOperationExpression(left, '&&', right); } + /** + * Create a expression for the OR operator. + */ + public static or(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '||', right); + } + constructor() { } @@ -70,6 +112,6 @@ class BinaryOperationExpression extends Expression { } public evaluate() { - return `${this.left.evaluate()} ${this.operator} ${this.right.evaluate()}`; + return `(${this.left.evaluate()} ${this.operator} ${this.right.evaluate()})`; } } diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts index e3844ce7915ba..d28ea5ae76da2 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -345,7 +345,7 @@ test('can set states with transitions', () => { TransitionEvents: [{ EventName: 'firstState_to_secondState', NextState: 'secondState', - Condition: '$input.test-input.payload.temperature == 12', + Condition: '($input.test-input.payload.temperature == 12)', }], }, }, @@ -356,12 +356,12 @@ test('can set states with transitions', () => { { EventName: 'secondToFirst', NextState: 'firstState', - Condition: '$input.test-input.payload.temperature == 21', + Condition: '($input.test-input.payload.temperature == 21)', }, { EventName: 'secondState_to_thirdState', NextState: 'thirdState', - Condition: '$input.test-input.payload.temperature == 23', + Condition: '($input.test-input.payload.temperature == 23)', }, ], }, @@ -498,14 +498,26 @@ test('cannot create transitions that transit to duprecated target state', () => }); describe('Expression', () => { - test('currentInput', () => { + const E = iotevents.Expression; + test.each([ + ['currentInput', (_input: iotevents.IInput) => E.currentInput(_input), 'currentInput("test-input")'], + ['inputAttribute', (_input: iotevents.IInput) => E.inputAttribute(_input, 'json.path'), '$input.test-input.json.path'], + ['eq', () => E.eq(E.fromString('"aaa"'), E.fromString('"bbb"')), '("aaa" == "bbb")'], + ['neq', () => E.neq(E.fromString('"aaa"'), E.fromString('"bbb"')), '("aaa" != "bbb")'], + ['lt', () => E.lt(E.fromString('5'), E.fromString('2')), '(5 < 2)'], + ['lte', () => E.lte(E.fromString('5'), E.fromString('2')), '(5 <= 2)'], + ['gt', () => E.gt(E.fromString('5'), E.fromString('2')), '(5 > 2)'], + ['gte', () => E.gte(E.fromString('5'), E.fromString('2')), '(5 >= 2)'], + ['and', () => E.and(E.fromString('true'), E.fromString('false')), '(true && false)'], + ['or', () => E.or(E.fromString('true'), E.fromString('false')), '(true || false)'], + ])('%s', (_, getExpression, expectedCondition) => { // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', onEnter: [{ eventName: 'test-eventName', - condition: iotevents.Expression.currentInput(input), + condition: getExpression(input), }], }), }); @@ -517,97 +529,7 @@ describe('Expression', () => { Match.objectLike({ OnEnter: { Events: [Match.objectLike({ - Condition: 'currentInput("test-input")', - })], - }, - }), - ], - }, - }); - }); - - test('inputAttribute', () => { - // WHEN - new iotevents.DetectorModel(stack, 'MyDetectorModel', { - initialState: new iotevents.State({ - stateName: 'test-state', - onEnter: [{ - eventName: 'test-eventName', - condition: iotevents.Expression.inputAttribute(input, 'json.path'), - }], - }), - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { - DetectorModelDefinition: { - States: [ - Match.objectLike({ - OnEnter: { - Events: [Match.objectLike({ - Condition: '$input.test-input.json.path', - })], - }, - }), - ], - }, - }); - }); - - test('eq', () => { - // WHEN - new iotevents.DetectorModel(stack, 'MyDetectorModel', { - initialState: new iotevents.State({ - stateName: 'test-state', - onEnter: [{ - eventName: 'test-eventName', - condition: iotevents.Expression.eq( - iotevents.Expression.fromString('"aaa"'), - iotevents.Expression.fromString('"bbb"'), - ), - }], - }), - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { - DetectorModelDefinition: { - States: [ - Match.objectLike({ - OnEnter: { - Events: [Match.objectLike({ - Condition: '"aaa" == "bbb"', - })], - }, - }), - ], - }, - }); - }); - - test('eq', () => { - // WHEN - new iotevents.DetectorModel(stack, 'MyDetectorModel', { - initialState: new iotevents.State({ - stateName: 'test-state', - onEnter: [{ - eventName: 'test-eventName', - condition: iotevents.Expression.and( - iotevents.Expression.fromString('true'), - iotevents.Expression.fromString('false'), - ), - }], - }), - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { - DetectorModelDefinition: { - States: [ - Match.objectLike({ - OnEnter: { - Events: [Match.objectLike({ - Condition: 'true && false', + Condition: expectedCondition, })], }, }), diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index 3b24a7f7776d8..e0e964456b0ff 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -47,15 +47,15 @@ "Fn::Join": [ "", [ - "currentInput(\"", + "(currentInput(\"", { "Ref": "MyInput08947B23" }, - "\") && $input.", + "\") && ($input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.5" + ".payload.temperature == 31.5))" ] ] }, @@ -70,11 +70,11 @@ "Fn::Join": [ "", [ - "$input.", + "($input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.7" + ".payload.temperature == 31.7)" ] ] }, @@ -89,11 +89,11 @@ "Fn::Join": [ "", [ - "$input.", + "($input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.6" + ".payload.temperature == 31.6)" ] ] }, @@ -106,11 +106,11 @@ "Fn::Join": [ "", [ - "$input.", + "($input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 12" + ".payload.temperature == 12)" ] ] }, @@ -129,11 +129,11 @@ "Fn::Join": [ "", [ - "$input.", + "($input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 21" + ".payload.temperature == 21)" ] ] }, From 50a37210f72f574433fd5739c0945706d17a94f6 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Sat, 12 Mar 2022 00:01:44 +0900 Subject: [PATCH 2/4] add integ test --- .../test/integ.detector-model.expected.json | 43 +++++++++++++++++++ .../test/integ.detector-model.ts | 11 +++++ 2 files changed, 54 insertions(+) diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index e0e964456b0ff..5b565623de4f6 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -123,6 +123,49 @@ }, { "OnInput": { + "Events": [ + { + "Actions": [ + { + "SetVariable": { + "Value": "(31.7 != 31.7)", + "VariableName": "neq" + } + }, + { + "SetVariable": { + "Value": "(31.7 > 31.7)", + "VariableName": "gt" + } + }, + { + "SetVariable": { + "Value": "(31.7 < 31.7)", + "VariableName": "lt" + } + }, + { + "SetVariable": { + "Value": "(31.7 >= 31.7)", + "VariableName": "gte" + } + }, + { + "SetVariable": { + "Value": "(31.7 <= 31.7)", + "VariableName": "lte" + } + }, + { + "SetVariable": { + "Value": "(true || false)", + "VariableName": "or" + } + } + ], + "EventName": "test-input-event" + } + ], "TransitionEvents": [ { "Condition": { diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts index 1c3996b226623..1e2ffae65e58b 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -40,6 +40,17 @@ class TestStack extends cdk.Stack { }); const offlineState = new iotevents.State({ stateName: 'offline', + onInput: [{ + eventName: 'test-input-event', + actions: [ + ['neq', iotevents.Expression.neq(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, + ['gt', iotevents.Expression.gt(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, + ['lt', iotevents.Expression.lt(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, + ['gte', iotevents.Expression.gte(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, + ['lte', iotevents.Expression.lte(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, + ['or', iotevents.Expression.or(iotevents.Expression.fromString('true'), iotevents.Expression.fromString('false'))] as const, + ].map(([variableName, value]) => ({ bind: () => ({ configuration: { setVariable: { variableName, value: value.evaluate() } } }) })), + }], }); // 1st => 2nd From 9d59b18949886dbfad7f3f565bbd7402d90860f4 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Sat, 2 Apr 2022 22:35:38 +0900 Subject: [PATCH 3/4] add priority of the operators --- .../@aws-cdk/aws-iotevents/lib/expression.ts | 39 +++++++++++++------ .../aws-iotevents/test/detector-model.test.ts | 26 +++++++------ .../test/integ.detector-model.expected.json | 34 ++++++++-------- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts index 685c670c9fc19..62be584a4ac03 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/expression.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -31,56 +31,56 @@ export abstract class Expression { * Create a expression for the Equal operator. */ public static eq(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '==', right); + return new BinaryOperationExpression(left, '==', right, 9); } /** * Create a expression for the Not Equal operator. */ public static neq(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '!=', right); + return new BinaryOperationExpression(left, '!=', right, 9); } /** * Create a expression for the Less Than operator. */ public static lt(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '<', right); + return new BinaryOperationExpression(left, '<', right, 10); } /** * Create a expression for the Less Than Or Equal operator. */ public static lte(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '<=', right); + return new BinaryOperationExpression(left, '<=', right, 10); } /** * Create a expression for the Greater Than operator. */ public static gt(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '>', right); + return new BinaryOperationExpression(left, '>', right, 10); } /** * Create a expression for the Greater Than Or Equal operator. */ public static gte(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '>=', right); + return new BinaryOperationExpression(left, '>=', right, 10); } /** * Create a expression for the AND operator. */ public static and(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '&&', right); + return new BinaryOperationExpression(left, '&&', right, 5); } /** * Create a expression for the OR operator. */ public static or(left: Expression, right: Expression): Expression { - return new BinaryOperationExpression(left, '||', right); + return new BinaryOperationExpression(left, '||', right, 4); } constructor() { @@ -89,7 +89,14 @@ export abstract class Expression { /** * This is called to evaluate the expression. */ - public abstract evaluate(): string; + public abstract evaluate( + /** + * The parent operator priority for determine to add parenthesis. + * This is intended to be set according to MDN rules. + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table + */ + parentPriority?: number + ): string; } class StringExpression extends Expression { @@ -107,11 +114,21 @@ class BinaryOperationExpression extends Expression { private readonly left: Expression, private readonly operator: string, private readonly right: Expression, + /** + * Indicates the priority of the operator. + * This is intended to be set according to MDN rules. + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table + */ + private readonly priority: number, ) { super(); } - public evaluate() { - return `(${this.left.evaluate()} ${this.operator} ${this.right.evaluate()})`; + public evaluate(parentPriority?: number) { + const expression = `${this.left.evaluate(this.priority)} ${this.operator} ${this.right.evaluate(this.priority)}`; + if (parentPriority === undefined) { + return expression; + } + return parentPriority > this.priority ? `(${expression})` : expression; } } diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts index d28ea5ae76da2..65ba02c7f5871 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -345,7 +345,7 @@ test('can set states with transitions', () => { TransitionEvents: [{ EventName: 'firstState_to_secondState', NextState: 'secondState', - Condition: '($input.test-input.payload.temperature == 12)', + Condition: '$input.test-input.payload.temperature == 12', }], }, }, @@ -356,12 +356,12 @@ test('can set states with transitions', () => { { EventName: 'secondToFirst', NextState: 'firstState', - Condition: '($input.test-input.payload.temperature == 21)', + Condition: '$input.test-input.payload.temperature == 21', }, { EventName: 'secondState_to_thirdState', NextState: 'thirdState', - Condition: '($input.test-input.payload.temperature == 23)', + Condition: '$input.test-input.payload.temperature == 23', }, ], }, @@ -502,14 +502,18 @@ describe('Expression', () => { test.each([ ['currentInput', (_input: iotevents.IInput) => E.currentInput(_input), 'currentInput("test-input")'], ['inputAttribute', (_input: iotevents.IInput) => E.inputAttribute(_input, 'json.path'), '$input.test-input.json.path'], - ['eq', () => E.eq(E.fromString('"aaa"'), E.fromString('"bbb"')), '("aaa" == "bbb")'], - ['neq', () => E.neq(E.fromString('"aaa"'), E.fromString('"bbb"')), '("aaa" != "bbb")'], - ['lt', () => E.lt(E.fromString('5'), E.fromString('2')), '(5 < 2)'], - ['lte', () => E.lte(E.fromString('5'), E.fromString('2')), '(5 <= 2)'], - ['gt', () => E.gt(E.fromString('5'), E.fromString('2')), '(5 > 2)'], - ['gte', () => E.gte(E.fromString('5'), E.fromString('2')), '(5 >= 2)'], - ['and', () => E.and(E.fromString('true'), E.fromString('false')), '(true && false)'], - ['or', () => E.or(E.fromString('true'), E.fromString('false')), '(true || false)'], + ['eq', () => E.eq(E.fromString('"aaa"'), E.fromString('"bbb"')), '"aaa" == "bbb"'], + ['neq', () => E.neq(E.fromString('"aaa"'), E.fromString('"bbb"')), '"aaa" != "bbb"'], + ['lt', () => E.lt(E.fromString('5'), E.fromString('2')), '5 < 2'], + ['lte', () => E.lte(E.fromString('5'), E.fromString('2')), '5 <= 2'], + ['gt', () => E.gt(E.fromString('5'), E.fromString('2')), '5 > 2'], + ['gte', () => E.gte(E.fromString('5'), E.fromString('2')), '5 >= 2'], + ['and', () => E.and(E.fromString('true'), E.fromString('false')), 'true && false'], + ['or', () => E.or(E.fromString('true'), E.fromString('false')), 'true || false'], + ['operator priority', () => E.and( + E.and(E.fromString('false'), E.fromString('false')), + E.or(E.fromString('true'), E.fromString('true')), + ), 'false && false && (true || true)'], ])('%s', (_, getExpression, expectedCondition) => { // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index 5b565623de4f6..708ac162bbb11 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -47,15 +47,15 @@ "Fn::Join": [ "", [ - "(currentInput(\"", + "currentInput(\"", { "Ref": "MyInput08947B23" }, - "\") && ($input.", + "\") && $input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.5))" + ".payload.temperature == 31.5" ] ] }, @@ -70,11 +70,11 @@ "Fn::Join": [ "", [ - "($input.", + "$input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.7)" + ".payload.temperature == 31.7" ] ] }, @@ -89,11 +89,11 @@ "Fn::Join": [ "", [ - "($input.", + "$input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 31.6)" + ".payload.temperature == 31.6" ] ] }, @@ -106,11 +106,11 @@ "Fn::Join": [ "", [ - "($input.", + "$input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 12)" + ".payload.temperature == 12" ] ] }, @@ -128,37 +128,37 @@ "Actions": [ { "SetVariable": { - "Value": "(31.7 != 31.7)", + "Value": "31.7 != 31.7", "VariableName": "neq" } }, { "SetVariable": { - "Value": "(31.7 > 31.7)", + "Value": "31.7 > 31.7", "VariableName": "gt" } }, { "SetVariable": { - "Value": "(31.7 < 31.7)", + "Value": "31.7 < 31.7", "VariableName": "lt" } }, { "SetVariable": { - "Value": "(31.7 >= 31.7)", + "Value": "31.7 >= 31.7", "VariableName": "gte" } }, { "SetVariable": { - "Value": "(31.7 <= 31.7)", + "Value": "31.7 <= 31.7", "VariableName": "lte" } }, { "SetVariable": { - "Value": "(true || false)", + "Value": "true || false", "VariableName": "or" } } @@ -172,11 +172,11 @@ "Fn::Join": [ "", [ - "($input.", + "$input.", { "Ref": "MyInput08947B23" }, - ".payload.temperature == 21)" + ".payload.temperature == 21" ] ] }, From f8e25e920f508dcf69e8e990f86a6ffe62b72054 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Tue, 5 Apr 2022 20:52:53 +0900 Subject: [PATCH 4/4] address comments --- .../@aws-cdk/aws-iotevents/lib/expression.ts | 22 +++++----- .../aws-iotevents/test/detector-model.test.ts | 4 +- .../test/integ.detector-model.expected.json | 43 ------------------- .../test/integ.detector-model.ts | 11 ----- 4 files changed, 12 insertions(+), 68 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts index 62be584a4ac03..bf4400c877206 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/expression.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -88,15 +88,14 @@ export abstract class Expression { /** * This is called to evaluate the expression. + * + * @param parentPriority priority of the parent of this expression, + * used for determining whether or not to add parenthesis around the expression. + * This is intended to be set according to MDN rules, see + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table + * for details */ - public abstract evaluate( - /** - * The parent operator priority for determine to add parenthesis. - * This is intended to be set according to MDN rules. - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table - */ - parentPriority?: number - ): string; + public abstract evaluate(parentPriority?: number): string; } class StringExpression extends Expression { @@ -126,9 +125,8 @@ class BinaryOperationExpression extends Expression { public evaluate(parentPriority?: number) { const expression = `${this.left.evaluate(this.priority)} ${this.operator} ${this.right.evaluate(this.priority)}`; - if (parentPriority === undefined) { - return expression; - } - return parentPriority > this.priority ? `(${expression})` : expression; + return parentPriority === undefined || parentPriority <= this.priority + ? expression + : `(${expression})`; } } diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts index 65ba02c7f5871..4f52e157c9356 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -500,8 +500,8 @@ test('cannot create transitions that transit to duprecated target state', () => describe('Expression', () => { const E = iotevents.Expression; test.each([ - ['currentInput', (_input: iotevents.IInput) => E.currentInput(_input), 'currentInput("test-input")'], - ['inputAttribute', (_input: iotevents.IInput) => E.inputAttribute(_input, 'json.path'), '$input.test-input.json.path'], + ['currentInput', (testInput: iotevents.IInput) => E.currentInput(testInput), 'currentInput("test-input")'], + ['inputAttribute', (testInput: iotevents.IInput) => E.inputAttribute(testInput, 'json.path'), '$input.test-input.json.path'], ['eq', () => E.eq(E.fromString('"aaa"'), E.fromString('"bbb"')), '"aaa" == "bbb"'], ['neq', () => E.neq(E.fromString('"aaa"'), E.fromString('"bbb"')), '"aaa" != "bbb"'], ['lt', () => E.lt(E.fromString('5'), E.fromString('2')), '5 < 2'], diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json index 708ac162bbb11..3b24a7f7776d8 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -123,49 +123,6 @@ }, { "OnInput": { - "Events": [ - { - "Actions": [ - { - "SetVariable": { - "Value": "31.7 != 31.7", - "VariableName": "neq" - } - }, - { - "SetVariable": { - "Value": "31.7 > 31.7", - "VariableName": "gt" - } - }, - { - "SetVariable": { - "Value": "31.7 < 31.7", - "VariableName": "lt" - } - }, - { - "SetVariable": { - "Value": "31.7 >= 31.7", - "VariableName": "gte" - } - }, - { - "SetVariable": { - "Value": "31.7 <= 31.7", - "VariableName": "lte" - } - }, - { - "SetVariable": { - "Value": "true || false", - "VariableName": "or" - } - } - ], - "EventName": "test-input-event" - } - ], "TransitionEvents": [ { "Condition": { diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts index 1e2ffae65e58b..1c3996b226623 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -40,17 +40,6 @@ class TestStack extends cdk.Stack { }); const offlineState = new iotevents.State({ stateName: 'offline', - onInput: [{ - eventName: 'test-input-event', - actions: [ - ['neq', iotevents.Expression.neq(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, - ['gt', iotevents.Expression.gt(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, - ['lt', iotevents.Expression.lt(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, - ['gte', iotevents.Expression.gte(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, - ['lte', iotevents.Expression.lte(iotevents.Expression.fromString('31.7'), iotevents.Expression.fromString('31.7'))] as const, - ['or', iotevents.Expression.or(iotevents.Expression.fromString('true'), iotevents.Expression.fromString('false'))] as const, - ].map(([variableName, value]) => ({ bind: () => ({ configuration: { setVariable: { variableName, value: value.evaluate() } } }) })), - }], }); // 1st => 2nd