-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
evaluate-expression.ts
116 lines (102 loc) · 2.89 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
105
106
107
108
109
110
111
112
113
114
115
116
import * as path from 'path';
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 { Construct } from 'constructs';
/**
* Properties for EvaluateExpression
*
* @experimental
*/
export interface EvaluateExpressionProps extends sfn.TaskStateBaseProps {
/**
* The expression to evaluate. The expression may 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 extends sfn.TaskStateBase {
protected readonly taskMetrics?: sfn.TaskMetricsConfig;
protected readonly taskPolicies?: iam.PolicyStatement[];
private readonly evalFn: lambda.SingletonFunction;
constructor(scope: Construct, id: string, private readonly props: EvaluateExpressionProps) {
super(scope, id, props);
this.evalFn = createEvalFn(this.props.runtime || lambda.Runtime.NODEJS_10_X, this);
this.taskPolicies = [
new iam.PolicyStatement({
resources: [this.evalFn.functionArn],
actions: ['lambda:InvokeFunction'],
}),
];
}
/**
* @internal
*/
protected _renderTask(): any {
const matches = this.props.expression.match(/\$[.\[][.a-zA-Z[\]0-9-_]+/g);
let expressionAttributeValues = {};
if (matches) {
expressionAttributeValues = matches.reduce(
(acc, m) => ({
...acc,
[m]: sfn.JsonPath.stringAt(m), // It's okay to always use `stringAt` here
}),
{},
);
}
const parameters: Event = {
expression: this.props.expression,
expressionAttributeValues,
};
return {
Resource: this.evalFn.functionArn,
Parameters: sfn.FieldUtils.renderObject(parameters),
};
}
}
function createEvalFn(runtime: lambda.Runtime, scope: 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.`);
}
}