/
evaluate-expression.ts
104 lines (92 loc) · 2.56 KB
/
evaluate-expression.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import * as sfn from '@aws-cdk/aws-stepfunctions';
import * as cdk from '@aws-cdk/core';
import * as path from 'path';
/**
* Properties for EvaluateExpression
*
* @experimental
*/
export interface EvaluateExpressionProps {
/**
* The expression to evaluate. It must contain state paths.
*
* @example '$.a + $.b'
*/
readonly expression: string;
/**
* The runtime language to use to evaluate the expression.
*
* @default lambda.Runtime.NODEJS_10_X
*/
readonly runtime?: lambda.Runtime;
}
/**
* The event received by the Lambda function
*
* @internal
*/
export interface Event {
/**
* The expression to evaluate
*/
readonly expression: string;
/**
* The expression attribute values
*/
readonly expressionAttributeValues: { [key: string]: any };
}
/**
* A Step Functions Task to evaluate an expression
*
* OUTPUT: the output of this task is the evaluated expression.
*
* @experimental
*/
export class EvaluateExpression implements sfn.IStepFunctionsTask {
constructor(private readonly props: EvaluateExpressionProps) {
}
public bind(task: sfn.Task): sfn.StepFunctionsTaskConfig {
const matches = this.props.expression.match(/\$[.\[][.a-zA-Z[\]0-9]+/g);
if (!matches) {
throw new Error('No paths found in expression');
}
const expressionAttributeValues = matches.reduce(
(acc, m) => ({
...acc,
[m]: sfn.Data.stringAt(m) // It's okay to always use `stringAt` here
}),
{}
);
const evalFn = createEvalFn(this.props.runtime || lambda.Runtime.NODEJS_10_X, task);
return {
resourceArn: evalFn.functionArn,
policyStatements: [new iam.PolicyStatement({
resources: [evalFn.functionArn],
actions: ['lambda:InvokeFunction'],
})],
parameters: {
expression: this.props.expression,
expressionAttributeValues,
} as Event
};
}
}
function createEvalFn(runtime: lambda.Runtime, scope: cdk.Construct) {
const code = lambda.Code.asset(path.join(__dirname, `eval-${runtime.name}-handler`));
const lambdaPurpose = 'Eval';
switch (runtime) {
case lambda.Runtime.NODEJS_10_X:
return new lambda.SingletonFunction(scope, 'EvalFunction', {
runtime,
handler: 'index.handler',
uuid: 'a0d2ce44-871b-4e74-87a1-f5e63d7c3bdc',
lambdaPurpose,
code,
});
// TODO: implement other runtimes
default:
throw new Error(`The runtime ${runtime.name} is currently not supported.`);
}
}