1+ from  abc  import  ABC , abstractmethod 
12import  logging 
23from  itertools  import  groupby 
3- from  typing  import  Any , Callable , List , Optional , Type , Union 
4+ from  typing  import  Any , Callable , Dict ,  List , Optional , Type , Union 
45
56from  aws_lambda_powertools .utilities .data_classes  import  AppSyncResolverEvent 
67from  aws_lambda_powertools .utilities .typing  import  LambdaContext 
1011
1112class  RouterContext :
1213    def  __init__ (self ):
13-         super ().__init__ ()
14-         self .context  =  {}
14+         self ._context  =  {}
1515
16-     def  append_context (self , ** additional_context ):
16+     @property  
17+     def  context (self ) ->  Dict [str , Any ]:
18+         return  self ._context 
19+ 
20+     @context .setter  
21+     def  context (self , additional_context : Dict [str , Any ]) ->  None :
1722        """Append key=value data as routing context""" 
18-         self .context .update (** additional_context )
23+         self ._context .update (** additional_context )
1924
20-     def  clear_context (self ):
25+     @context .deleter  
26+     def  context (self ):
2127        """Resets routing context""" 
22-         self .context .clear ()
28+         self ._context .clear ()
29+ 
30+ 
31+ class  IResolverRegistry (ABC ):
32+     @abstractmethod  
33+     def  resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ) ->  Callable :
34+         ...
2335
36+     @abstractmethod  
37+     def  find_resolver (self , type_name : str , field_name : str ) ->  Callable :
38+         ...
2439
25- class  ResolverRegistry :
40+ 
41+ class  ResolverRegistry (IResolverRegistry ):
2642    def  __init__ (self ):
27-         super ().__init__ ()
28-         self ._resolvers : dict  =  {}
29-         self ._batch_resolvers : dict  =  {}
43+         self ._resolvers : Dict [str , Dict [str , Any ]] =  {}
44+ 
45+     @property  
46+     def  resolvers (self ) ->  Dict [str , Dict [str , Any ]]:
47+         return  self ._resolvers 
48+ 
49+     @resolvers .setter  
50+     def  resolvers (self , resolvers : dict ) ->  None :
51+         self ._resolvers .update (resolvers )
3052
3153    def  resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
3254        """Registers the resolver for field_name 
@@ -46,26 +68,15 @@ def register(func):
4668
4769        return  register 
4870
49-     def  batch_resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
50-         """Registers the resolver for field_name 
51- 
52-         Parameters 
53-         ---------- 
54-         type_name : str 
55-             Type name 
56-         field_name : str 
57-             Field name 
58-         """ 
59- 
60-         def  register (func ):
61-             logger .debug (f"Adding batch resolver `{ func .__name__ } { type_name } { field_name }  )
62-             self ._batch_resolvers [f"{ type_name } { field_name }  ] =  {"func" : func }
63-             return  func 
64- 
65-         return  register 
71+     def  find_resolver (self , type_name : str , field_name : str ) ->  Callable :
72+         full_name  =  f"{ type_name } { field_name }  
73+         resolver  =  self ._resolvers .get (full_name , self ._resolvers .get (f"*.{ field_name }  ))
74+         if  not  resolver :
75+             raise  ValueError (f"No resolver found for '{ full_name }  )
76+         return  resolver ["func" ]
6677
6778
68- class  AppSyncResolver ( ResolverRegistry ,  RouterContext ) :
79+ class  AppSyncResolver :
6980    """ 
7081    AppSync resolver decorator 
7182
@@ -97,17 +108,20 @@ def common_field() -> str:
97108    """ 
98109
99110    def  __init__ (self ):
100-         super ().__init__ ()
111+         self ._resolver_registry : IResolverRegistry  =  ResolverRegistry ()
112+         self ._batch_resolver_registry : IResolverRegistry  =  ResolverRegistry ()
113+         self ._router_context : RouterContext  =  RouterContext ()
101114        self .current_batch_event : List [AppSyncResolverEvent ] =  []
102115        self .current_event : Optional [AppSyncResolverEvent ] =  None 
116+         self .lambda_context : Optional [LambdaContext ] =  None 
103117
104118    def  resolve (
105119        self ,
106-         event : Union [dict ,  List [dict ]],
120+         event : Union [Dict [ str ,  Any ],  List [Dict [ str ,  Any ] ]],
107121        context : LambdaContext ,
108122        data_model : Type [AppSyncResolverEvent ] =  AppSyncResolverEvent ,
109123    ) ->  Any :
110-         """Resolve field_name 
124+         """Resolve field_name in single event or in a batch event  
111125
112126        Parameters 
113127        ---------- 
@@ -180,17 +194,17 @@ def lambda_handler(event, context):
180194        self .lambda_context  =  context 
181195
182196        response  =  (
183-             self ._call_batch_resolver (event ,  data_model )
197+             self ._call_batch_resolver (event = event ,  data_model = data_model )
184198            if  isinstance (event , list )
185-             else  self ._call_resolver (event ,  data_model )
199+             else  self ._call_single_resolver (event = event ,  data_model = data_model )
186200        )
187-         self .clear_context () 
201+         del   self ._router_context . context 
188202
189203        return  response 
190204
191-     def  _call_resolver (self , event : dict , data_model : Type [AppSyncResolverEvent ]) ->  Any :
205+     def  _call_single_resolver (self , event : dict , data_model : Type [AppSyncResolverEvent ]) ->  Any :
192206        self .current_event  =  data_model (event )
193-         resolver  =  self ._get_resolver (self .current_event .type_name , self .current_event .field_name )
207+         resolver  =  self ._resolver_registry . find_resolver (self .current_event .type_name , self .current_event .field_name )
194208        return  resolver (** self .current_event .arguments )
195209
196210    def  _call_batch_resolver (self , event : List [dict ], data_model : Type [AppSyncResolverEvent ]) ->  List [Any ]:
@@ -202,54 +216,12 @@ def _call_batch_resolver(self, event: List[dict], data_model: Type[AppSyncResolv
202216            ValueError ("batch with different field names. It shouldn't happen!" )
203217
204218        self .current_batch_event  =  [data_model (event ) for  event  in  event_groups [0 ]["events" ]]
205-         resolver  =  self ._get_batch_resolver (
219+         resolver  =  self ._batch_resolver_registry . find_resolver (
206220            self .current_batch_event [0 ].type_name , self .current_batch_event [0 ].field_name 
207221        )
208222
209223        return  [resolver (event = appconfig_event ) for  appconfig_event  in  self .current_batch_event ]
210224
211-     def  _get_resolver (self , type_name : str , field_name : str ) ->  Callable :
212-         """Get resolver for field_name 
213- 
214-         Parameters 
215-         ---------- 
216-         type_name : str 
217-             Type name 
218-         field_name : str 
219-             Field name 
220- 
221-         Returns 
222-         ------- 
223-         Callable 
224-             callable function and configuration 
225-         """ 
226-         full_name  =  f"{ type_name } { field_name }  
227-         resolver  =  self ._resolvers .get (full_name , self ._resolvers .get (f"*.{ field_name }  ))
228-         if  not  resolver :
229-             raise  ValueError (f"No resolver found for '{ full_name }  )
230-         return  resolver ["func" ]
231- 
232-     def  _get_batch_resolver (self , type_name : str , field_name : str ) ->  Callable :
233-         """Get resolver for field_name 
234- 
235-         Parameters 
236-         ---------- 
237-         type_name : str 
238-             Type name 
239-         field_name : str 
240-             Field name 
241- 
242-         Returns 
243-         ------- 
244-         Callable 
245-             callable function and configuration 
246-         """ 
247-         full_name  =  f"{ type_name } { field_name }  
248-         resolver  =  self ._batch_resolvers .get (full_name , self ._batch_resolvers .get (f"*.{ field_name }  ))
249-         if  not  resolver :
250-             raise  ValueError (f"No batch resolver found for '{ full_name }  )
251-         return  resolver ["func" ]
252- 
253225    def  __call__ (
254226        self ,
255227        event : Union [dict , List [dict ]],
@@ -267,14 +239,38 @@ def include_router(self, router: "Router") -> None:
267239        router : Router 
268240            A router containing a dict of field resolvers 
269241        """ 
242+ 
270243        # Merge app and router context 
271-         self .context . update ( ** router .context ) 
244+         self ._router_context . context   =   router ._router_context . context 
272245        # use pointer to allow context clearance after event is processed e.g., resolve(evt, ctx) 
273-         router .context  =  self .context 
246+         router ._router_context . _context  =  self . _router_context .context 
274247
275-         self ._resolvers .update (router ._resolvers )
248+         self ._resolver_registry .resolvers  =  router ._resolver_registry .resolvers 
249+         self ._batch_resolver_registry .resolvers  =  router ._batch_resolver_registry .resolvers 
276250
251+     # Interfaces 
252+     def  resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
253+         return  self ._resolver_registry .resolver (field_name = field_name , type_name = type_name )
277254
278- class  Router (RouterContext , ResolverRegistry ):
255+     def  batch_resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
256+         return  self ._batch_resolver_registry .resolver (field_name = field_name , type_name = type_name )
257+ 
258+     def  append_context (self , ** additional_context ) ->  None :
259+         self ._router_context .context  =  additional_context 
260+ 
261+ 
262+ class  Router :
279263    def  __init__ (self ):
280-         super ().__init__ ()
264+         self ._resolver_registry  =  ResolverRegistry ()
265+         self ._batch_resolver_registry  =  ResolverRegistry ()
266+         self ._router_context  =  RouterContext ()
267+ 
268+     # Interfaces 
269+     def  resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
270+         return  self ._resolver_registry .resolver (field_name = field_name , type_name = type_name )
271+ 
272+     def  batch_resolver (self , type_name : str  =  "*" , field_name : Optional [str ] =  None ):
273+         return  self ._batch_resolver_registry .resolver (field_name = field_name , type_name = type_name )
274+ 
275+     def  append_context (self , ** additional_context ) ->  None :
276+         self ._router_context .context  =  additional_context 
0 commit comments