Skip to content

Commit dc8e028

Browse files
authored
feat: make AppSync::DataSource mappings (DynamoDB) (#2906)
Disregarding failed backward compatibility check as the deleted functionality wasn't ever released
1 parent ce51f0c commit dc8e028

20 files changed

+961
-46
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from typing import Any, Dict, List, Optional
2+
3+
from typing_extensions import TypedDict
4+
5+
from samtranslator.model import GeneratedProperty, Resource
6+
from samtranslator.model.intrinsics import fnGetAtt
7+
from samtranslator.utils.types import Intrinsicable
8+
9+
# Data source constants can be found here under "Type" property:
10+
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html
11+
SUPPORTED_DATASOURCES = {"AMAZON_DYNAMODB"}
12+
13+
14+
class DeltaSyncConfigType(TypedDict):
15+
BaseTableTTL: str
16+
DeltaSyncTableName: str
17+
DeltaSyncTableTTL: str
18+
19+
20+
class DynamoDBConfigType(TypedDict, total=False):
21+
AwsRegion: str
22+
TableName: str
23+
UseCallerCredentials: bool
24+
Versioned: bool
25+
DeltaSyncConfig: DeltaSyncConfigType
26+
27+
28+
class GraphQLApi(Resource):
29+
resource_type = "AWS::AppSync::GraphQLApi"
30+
property_types = {
31+
"Name": GeneratedProperty(),
32+
"Tags": GeneratedProperty(),
33+
"XrayEnabled": GeneratedProperty(),
34+
"AuthenticationType": GeneratedProperty(),
35+
}
36+
37+
Name: str
38+
AuthenticationType: str
39+
Tags: Optional[List[Dict[str, Any]]]
40+
XrayEnabled: Optional[bool]
41+
42+
runtime_attrs = {"api_id": lambda self: fnGetAtt(self.logical_id, "ApiId")}
43+
44+
45+
class GraphQLSchema(Resource):
46+
resource_type = "AWS::AppSync::GraphQLSchema"
47+
property_types = {
48+
"ApiId": GeneratedProperty(),
49+
"Definition": GeneratedProperty(),
50+
"DefinitionS3Location": GeneratedProperty(),
51+
}
52+
53+
ApiId: Intrinsicable[str]
54+
Definition: Optional[str]
55+
DefinitionS3Location: Optional[str]
56+
57+
58+
class DataSource(Resource):
59+
resource_type = "AWS::AppSync::DataSource"
60+
property_types = {
61+
"ApiId": GeneratedProperty(),
62+
"Description": GeneratedProperty(),
63+
"Name": GeneratedProperty(),
64+
"Type": GeneratedProperty(),
65+
"ServiceRoleArn": GeneratedProperty(),
66+
"DynamoDBConfig": GeneratedProperty(),
67+
}
68+
69+
ApiId: Intrinsicable[str]
70+
Description: Optional[str]
71+
Name: str
72+
Type: str
73+
ServiceRoleArn: str
74+
DynamoDBConfig: DynamoDBConfigType

samtranslator/model/appsync.py

Lines changed: 0 additions & 42 deletions
This file was deleted.

samtranslator/model/sam_resources.py

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
import samtranslator.model.eventsources.push
1010
import samtranslator.model.eventsources.scheduler
1111
from samtranslator.feature_toggle.feature_toggle import FeatureToggle
12+
from samtranslator.internal.model.appsync import (
13+
SUPPORTED_DATASOURCES,
14+
DataSource,
15+
DeltaSyncConfigType,
16+
DynamoDBConfigType,
17+
GraphQLApi,
18+
GraphQLSchema,
19+
)
1220
from samtranslator.intrinsics.resolver import IntrinsicsResolver
1321
from samtranslator.metrics.method_decorator import cw_timer
1422
from samtranslator.model import (
@@ -29,7 +37,6 @@
2937
ApiGatewayUsagePlanKey,
3038
)
3139
from samtranslator.model.apigatewayv2 import ApiGatewayV2DomainName, ApiGatewayV2Stage
32-
from samtranslator.model.appsync import Auth, GraphQLApi, GraphQLSchema
3340
from samtranslator.model.architecture import ARM64, X86_64
3441
from samtranslator.model.cloudformation import NestedStack
3542
from samtranslator.model.connector.connector import (
@@ -2149,7 +2156,7 @@ class SamGraphQLApi(SamResourceMacro):
21492156
"SchemaUri": Property(False, IS_STR),
21502157
}
21512158

2152-
Auth: Auth
2159+
Auth: Dict[str, Any]
21532160
Tags: Optional[Dict[str, Any]]
21542161
XrayEnabled: Optional[PassThrough]
21552162
Name: Optional[str]
@@ -2194,3 +2201,106 @@ def _construct_appsync_schema(self, api_id: Intrinsicable[str]) -> GraphQLSchema
21942201
schema.DefinitionS3Location = self.SchemaUri
21952202

21962203
return schema
2204+
2205+
2206+
class SamGraphQLDataSource(SamResourceMacro):
2207+
"""SAM GraphQL Data Source Macro (WIP)."""
2208+
2209+
# TODO: This currently only supports DataSource with a defined ServiceRoleArn.
2210+
# The proposed connector change will come in a follow up PR.
2211+
resource_type = "AWS::Serverless::GraphQLDataSource"
2212+
property_types = {
2213+
"ApiId": PassThroughProperty(True),
2214+
"Name": Property(False, IS_STR),
2215+
"Type": Property(True, IS_STR),
2216+
"Description": PassThroughProperty(False),
2217+
"ServiceRoleArn": Property(False, IS_STR),
2218+
"DynamoDBConfig": Property(False, IS_DICT),
2219+
}
2220+
2221+
ApiId: PassThrough
2222+
Type: str
2223+
DynamoDBConfig: Optional[Dict[str, Any]]
2224+
Name: Optional[str]
2225+
Description: Optional[PassThrough]
2226+
ServiceRoleArn: Optional[str]
2227+
2228+
@cw_timer
2229+
def to_cloudformation(self, **kwargs: Any) -> List[Resource]:
2230+
appsync_datasource = self._construct_appsync_datasource()
2231+
resources: List[Resource] = [appsync_datasource]
2232+
2233+
return resources
2234+
2235+
def _parse_deltasync_properties(self, deltasync_properties: Dict[str, Any]) -> DeltaSyncConfigType:
2236+
# TODO: add defaults
2237+
sam_expect(
2238+
deltasync_properties.get("BaseTableTTL"), self.logical_id, "DynamoDBConfig.DeltaSyncConfig.BaseTableTTL"
2239+
).to_be_a_string()
2240+
2241+
sam_expect(
2242+
deltasync_properties.get("DeltaSyncTableName"),
2243+
self.logical_id,
2244+
"DynamoDBConfig.DeltaSyncConfig.DeltaSyncTableName",
2245+
).to_be_a_string()
2246+
2247+
sam_expect(
2248+
deltasync_properties.get("DeltaSyncTableTTL"),
2249+
self.logical_id,
2250+
"DynamoDBConfig.DeltaSyncConfig.DeltaSyncTableTTL",
2251+
).to_be_a_string()
2252+
2253+
return cast(DeltaSyncConfigType, deltasync_properties)
2254+
2255+
def _parse_dynamodb_datasource(self, ddb_properties: Dict[str, Any]) -> DynamoDBConfigType:
2256+
ddb_config: DynamoDBConfigType = {}
2257+
2258+
ddb_config["TableName"] = sam_expect(
2259+
ddb_properties.get("TableName"),
2260+
self.logical_id,
2261+
"DynamoDBConfig.TableName",
2262+
).to_be_a_string()
2263+
2264+
ddb_config["AwsRegion"] = ddb_properties["Region"] if "Region" in ddb_properties else ref("AWS::Region")
2265+
2266+
if "DeltaSync" in ddb_properties:
2267+
deltasync_properties = ddb_properties["DeltaSync"]
2268+
deltasync_config = self._parse_deltasync_properties(deltasync_properties)
2269+
ddb_config["DeltaSyncConfig"] = deltasync_config
2270+
2271+
if "UseCallerCredentials" in ddb_properties:
2272+
ddb_config["UseCallerCredentials"] = ddb_properties["UseCallerCredentials"]
2273+
2274+
if "Versioned" in ddb_properties:
2275+
ddb_config["Versioned"] = ddb_properties["Versioned"]
2276+
2277+
return ddb_config
2278+
2279+
def _validate_config_properties(self, datasource: DataSource) -> None:
2280+
# DataSourceConfig is quite large property so we require a lot of additional validation.
2281+
# The datasource object is modified by reference.
2282+
if self.Type == "AMAZON_DYNAMODB":
2283+
if not self.DynamoDBConfig:
2284+
raise InvalidResourceException(
2285+
self.logical_id, "'DynamoDBConfig' must be defined when 'Type' is 'AMAZON_DYNAMODB'."
2286+
)
2287+
datasource.DynamoDBConfig = self._parse_dynamodb_datasource(self.DynamoDBConfig)
2288+
2289+
def _construct_appsync_datasource(self) -> DataSource:
2290+
datasource = DataSource(
2291+
logical_id=self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes
2292+
)
2293+
2294+
if self.Type not in SUPPORTED_DATASOURCES:
2295+
raise InvalidResourceException(self.logical_id, f"'{self.Type}' is not a supported data source type.")
2296+
2297+
datasource.Type = self.Type
2298+
datasource.Name = self.Name if self.Name else self.logical_id
2299+
datasource.Description = self.Description
2300+
datasource.ApiId = self.ApiId
2301+
# I will remove this ignore after, it will be fixed with pseudo-embedded connector implementation.
2302+
datasource.ServiceRoleArn = self.ServiceRoleArn # type: ignore
2303+
2304+
self._validate_config_properties(datasource)
2305+
2306+
return datasource

samtranslator/schema/schema.json

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187346,6 +187346,30 @@
187346187346
"title": "DeadLetterQueue",
187347187347
"type": "object"
187348187348
},
187349+
"DeltaSyncConfig": {
187350+
"additionalProperties": false,
187351+
"properties": {
187352+
"BaseTableTTL": {
187353+
"title": "Basetablettl",
187354+
"type": "string"
187355+
},
187356+
"DeltaSyncTableName": {
187357+
"title": "Deltasynctablename",
187358+
"type": "string"
187359+
},
187360+
"DeltaSyncTableTTL": {
187361+
"title": "Deltasynctablettl",
187362+
"type": "string"
187363+
}
187364+
},
187365+
"required": [
187366+
"BaseTableTTL",
187367+
"DeltaSyncTableName",
187368+
"DeltaSyncTableTTL"
187369+
],
187370+
"title": "DeltaSyncConfig",
187371+
"type": "object"
187372+
},
187349187373
"DeploymentPreference": {
187350187374
"additionalProperties": false,
187351187375
"properties": {
@@ -187441,6 +187465,33 @@
187441187465
"title": "DeploymentPreference",
187442187466
"type": "object"
187443187467
},
187468+
"DynamoDBConfig": {
187469+
"additionalProperties": false,
187470+
"properties": {
187471+
"DeltaSync": {
187472+
"$ref": "#/definitions/DeltaSyncConfig"
187473+
},
187474+
"Region": {
187475+
"title": "Region",
187476+
"type": "string"
187477+
},
187478+
"TableName": {
187479+
"title": "Tablename",
187480+
"type": "string"
187481+
},
187482+
"UseCallerCredentials": {
187483+
"$ref": "#/definitions/PassThroughProp"
187484+
},
187485+
"Versioned": {
187486+
"$ref": "#/definitions/PassThroughProp"
187487+
}
187488+
},
187489+
"required": [
187490+
"TableName"
187491+
],
187492+
"title": "DynamoDBConfig",
187493+
"type": "object"
187494+
},
187444187495
"DynamoDBEvent": {
187445187496
"additionalProperties": false,
187446187497
"properties": {
@@ -192631,6 +192682,61 @@
192631192682
"title": "Resource",
192632192683
"type": "object"
192633192684
},
192685+
"schema_source__aws_serverless_graphqldatasource__Properties": {
192686+
"additionalProperties": false,
192687+
"properties": {
192688+
"ApiId": {
192689+
"$ref": "#/definitions/PassThroughProp"
192690+
},
192691+
"Description": {
192692+
"title": "Description",
192693+
"type": "string"
192694+
},
192695+
"DynamoDBConfig": {
192696+
"$ref": "#/definitions/DynamoDBConfig"
192697+
},
192698+
"Name": {
192699+
"title": "Name",
192700+
"type": "string"
192701+
},
192702+
"ServiceRoleArn": {
192703+
"title": "Servicerolearn",
192704+
"type": "string"
192705+
},
192706+
"Type": {
192707+
"title": "Type",
192708+
"type": "string"
192709+
}
192710+
},
192711+
"required": [
192712+
"ApiId",
192713+
"Type",
192714+
"DynamoDBConfig"
192715+
],
192716+
"title": "Properties",
192717+
"type": "object"
192718+
},
192719+
"schema_source__aws_serverless_graphqldatasource__Resource": {
192720+
"additionalProperties": false,
192721+
"properties": {
192722+
"Properties": {
192723+
"$ref": "#/definitions/schema_source__aws_serverless_graphqldatasource__Properties"
192724+
},
192725+
"Type": {
192726+
"enum": [
192727+
"AWS::Serverless::GraphQLDataSource"
192728+
],
192729+
"title": "Type",
192730+
"type": "string"
192731+
}
192732+
},
192733+
"required": [
192734+
"Type",
192735+
"Properties"
192736+
],
192737+
"title": "Resource",
192738+
"type": "object"
192739+
},
192634192740
"schema_source__aws_serverless_httpapi__Auth": {
192635192741
"additionalProperties": false,
192636192742
"properties": {
@@ -194377,6 +194483,9 @@
194377194483
{
194378194484
"$ref": "#/definitions/schema_source__aws_serverless_graphqlapi__Resource"
194379194485
},
194486+
{
194487+
"$ref": "#/definitions/schema_source__aws_serverless_graphqldatasource__Resource"
194488+
},
194380194489
{
194381194490
"$ref": "#/definitions/AWS::ACMPCA::Certificate"
194382194491
},

0 commit comments

Comments
 (0)