-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
appsync-mapping-templates.ts
82 lines (69 loc) · 3.5 KB
/
appsync-mapping-templates.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
import * as AWS from 'aws-sdk';
import { ISDK } from '../aws-auth';
import { EvaluateCloudFormationTemplate } from '../evaluate-cloudformation-template';
import { ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, HotswappableChangeCandidate, lowerCaseFirstCharacter, transformObjectKeys } from './common';
export async function isHotswappableAppSyncChange(
logicalId: string, change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate,
): Promise<ChangeHotswapResult> {
const isResolver = change.newValue.Type === 'AWS::AppSync::Resolver';
const isFunction = change.newValue.Type === 'AWS::AppSync::FunctionConfiguration';
if (!isResolver && !isFunction) {
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
}
for (const updatedPropName in change.propertyUpdates) {
if (updatedPropName !== 'RequestMappingTemplate' && updatedPropName !== 'ResponseMappingTemplate') {
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
}
}
const resourceProperties = change.newValue.Properties;
if (isResolver && resourceProperties?.Kind === 'PIPELINE') {
// Pipeline resolvers can't be hotswapped as they reference
// the FunctionId of the underlying functions, which can't be resolved.
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
}
const resourcePhysicalName = await evaluateCfnTemplate.establishResourcePhysicalName(logicalId, isFunction ? resourceProperties?.Name : undefined);
if (!resourcePhysicalName) {
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
}
const evaluatedResourceProperties = await evaluateCfnTemplate.evaluateCfnExpression(resourceProperties);
const sdkCompatibleResourceProperties = transformObjectKeys(evaluatedResourceProperties, lowerCaseFirstCharacter);
if (isResolver) {
// Resolver physical name is the ARN in the format:
// arn:aws:appsync:us-east-1:111111111111:apis/<apiId>/types/<type>/resolvers/<field>.
// We'll use `<type>.<field>` as the resolver name.
const arnParts = resourcePhysicalName.split('/');
const resolverName = `${arnParts[3]}.${arnParts[5]}`;
return new ResolverHotswapOperation(resolverName, sdkCompatibleResourceProperties);
} else {
return new FunctionHotswapOperation(resourcePhysicalName, sdkCompatibleResourceProperties);
}
}
class ResolverHotswapOperation implements HotswapOperation {
public readonly service = 'appsync'
public readonly resourceNames: string[];
constructor(resolverName: string, private readonly updateResolverRequest: AWS.AppSync.UpdateResolverRequest) {
this.resourceNames = [`AppSync resolver '${resolverName}'`];
}
public async apply(sdk: ISDK): Promise<any> {
return sdk.appsync().updateResolver(this.updateResolverRequest).promise();
}
}
class FunctionHotswapOperation implements HotswapOperation {
public readonly service = 'appsync'
public readonly resourceNames: string[];
constructor(
private readonly functionName: string,
private readonly updateFunctionRequest: Omit<AWS.AppSync.UpdateFunctionRequest, 'functionId'>,
) {
this.resourceNames = [`AppSync function '${functionName}'`];
}
public async apply(sdk: ISDK): Promise<any> {
const { functions } = await sdk.appsync().listFunctions({ apiId: this.updateFunctionRequest.apiId }).promise();
const { functionId } = functions?.find(fn => fn.name === this.functionName) ?? {};
const request = {
...this.updateFunctionRequest,
functionId: functionId!,
};
return sdk.appsync().updateFunction(request).promise();
}
}