Skip to content

Commit 9c5cbd9

Browse files
author
Michal Ploski
committed
Extend router to accept List of events. Add functional test
1 parent da1e745 commit 9c5cbd9

File tree

3 files changed

+164
-10
lines changed

3 files changed

+164
-10
lines changed

aws_lambda_powertools/event_handler/appsync.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import logging
2-
from typing import Any, Callable, Optional, Type, TypeVar, List, Union
2+
from itertools import groupby
3+
from typing import Any, Callable, List, Optional, Type, TypeVar, Union
34

45
from aws_lambda_powertools.utilities.data_classes import AppSyncResolverEvent
56
from aws_lambda_powertools.utilities.typing import LambdaContext
6-
from itertools import groupby
7-
from operator import itemgetter
87

98
logger = logging.getLogger(__name__)
109

@@ -155,6 +154,8 @@ def lambda_handler(event, context):
155154
"""
156155
# Maintenance: revisit generics/overload to fix [attr-defined] in mypy usage
157156

157+
BaseRouter.lambda_context = context
158+
158159
# If event is a list it means that AppSync sent batch request
159160
if isinstance(event, list):
160161
event_groups = [
@@ -164,15 +165,15 @@ def lambda_handler(event, context):
164165
if len(event_groups) > 1:
165166
ValueError("batch with different field names. It shouldn't happen!")
166167

167-
BaseRouter.current_event = [data_model(event) for event in event_groups[0]["events"]]
168-
169-
resolver = self._get_resolver(BaseRouter.current_event[0].type_name, event_groups[0]["field_name"])
168+
appconfig_events = [data_model(event) for event in event_groups[0]["events"]]
169+
BaseRouter.current_event = appconfig_events
170+
resolver = self._get_resolver(appconfig_events[0].type_name, event_groups[0]["field_name"])
170171
response = resolver()
171172
else:
172-
BaseRouter.current_event = data_model(event)
173-
resolver = self._get_resolver(BaseRouter.current_event.type_name, BaseRouter.current_event.field_name)
174-
response = resolver(**BaseRouter.current_event.arguments)
175-
BaseRouter.lambda_context = context
173+
appconfig_event = data_model(event)
174+
BaseRouter.current_event = appconfig_event
175+
resolver = self._get_resolver(appconfig_event.type_name, appconfig_event.field_name)
176+
response = resolver(**appconfig_event.arguments)
176177

177178
self.clear_context()
178179

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from typing import List
2+
3+
4+
from aws_lambda_powertools.event_handler import AppSyncResolver
5+
from aws_lambda_powertools.utilities.typing import LambdaContext
6+
from pydantic import BaseModel
7+
8+
app = AppSyncResolver()
9+
10+
11+
posts = {
12+
"1": {
13+
"id": "1",
14+
"title": "First book",
15+
"author": "Author1",
16+
"url": "https://amazon.com/",
17+
"content": "SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1",
18+
"ups": "100",
19+
"downs": "10",
20+
},
21+
"2": {
22+
"id": "2",
23+
"title": "Second book",
24+
"author": "Author2",
25+
"url": "https://amazon.com",
26+
"content": "SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT",
27+
"ups": "100",
28+
"downs": "10",
29+
},
30+
"3": {
31+
"id": "3",
32+
"title": "Third book",
33+
"author": "Author3",
34+
"url": None,
35+
"content": None,
36+
"ups": None,
37+
"downs": None,
38+
},
39+
"4": {
40+
"id": "4",
41+
"title": "Fourth book",
42+
"author": "Author4",
43+
"url": "https://www.amazon.com/",
44+
"content": "SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4",
45+
"ups": "1000",
46+
"downs": "0",
47+
},
48+
"5": {
49+
"id": "5",
50+
"title": "Fifth book",
51+
"author": "Author5",
52+
"url": "https://www.amazon.com/",
53+
"content": "SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT",
54+
"ups": "50",
55+
"downs": "0",
56+
},
57+
}
58+
59+
posts_related = {
60+
"1": [posts["4"]],
61+
"2": [posts["3"], posts["5"]],
62+
"3": [posts["2"], posts["1"]],
63+
"4": [posts["2"], posts["1"]],
64+
"5": [],
65+
}
66+
67+
68+
class Post(BaseModel):
69+
id: str
70+
author: str
71+
title: str
72+
url: str
73+
content: str
74+
ups: str
75+
downs: str
76+
77+
78+
@app.resolver(type_name="Query", field_name="getPost")
79+
def get_post(id: str = "") -> dict:
80+
post = Post(**posts[id]).dict()
81+
return post
82+
83+
84+
@app.resolver(type_name="Query", field_name="allPosts")
85+
def all_posts() -> List[dict]:
86+
parsed_posts = [post for post in posts.values()]
87+
return parsed_posts
88+
89+
90+
@app.resolver(type_name="Post", field_name="relatedPosts")
91+
def related_posts() -> List[dict]:
92+
posts = []
93+
for resolver_event in app.current_event:
94+
if resolver_event.source:
95+
posts.append(posts_related[resolver_event.source["id"]])
96+
return posts
97+
98+
99+
def lambda_handler(event, context: LambdaContext) -> dict:
100+
return app.resolve(event, context)

tests/functional/event_handler/test_appsync.py

+53
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,59 @@ def create_something(id: str): # noqa AA03 VNE003
164164
assert app.current_event.country_viewer == "US"
165165

166166

167+
def test_resolve_batch_processing():
168+
event = [
169+
{
170+
"typeName": "Query",
171+
"info": {
172+
"fieldName": "listLocations",
173+
"parentTypeName": "Post",
174+
},
175+
"fieldName": "listLocations",
176+
"arguments": {},
177+
"source": {
178+
"id": "1",
179+
},
180+
},
181+
{
182+
"typeName": "Query",
183+
"info": {
184+
"fieldName": "listLocations",
185+
"parentTypeName": "Post",
186+
},
187+
"fieldName": "listLocations",
188+
"arguments": {},
189+
"source": {
190+
"id": "2",
191+
},
192+
},
193+
{
194+
"typeName": "Query",
195+
"info": {
196+
"fieldName": "listLocations",
197+
"parentTypeName": "Post",
198+
},
199+
"fieldName": "listLocations",
200+
"arguments": {},
201+
"source": {
202+
"id": "3",
203+
},
204+
},
205+
]
206+
207+
app = AppSyncResolver()
208+
209+
@app.resolver(field_name="listLocations")
210+
def create_something(): # noqa AA03 VNE003
211+
return [event.source["id"] for event in app.current_event]
212+
213+
# Call the implicit handler
214+
result = app.resolve(event, LambdaContext())
215+
assert result == ["1", "2", "3"]
216+
217+
assert len(app.current_event) == len(event)
218+
219+
167220
def test_resolver_include_resolver():
168221
# GIVEN
169222
app = AppSyncResolver()

0 commit comments

Comments
 (0)