24
24
GraphQLInt ,
25
25
GraphQLNonNull ,
26
26
GraphQLObjectType ,
27
- GraphQLResolveInfo ,
28
27
GraphQLSchema ,
29
28
GraphQLString ,
30
29
)
@@ -43,42 +42,61 @@ class User(NamedTuple):
43
42
verified : bool = False
44
43
45
44
45
+ class MutationEnum (Enum ):
46
+ """Mutation event type"""
47
+
48
+ CREATED = "created"
49
+ UPDATED = "updated"
50
+ DELETED = "deleted"
51
+
52
+
46
53
class UserRegistry :
47
54
""""Simulation of a user registry with asynchronous database backend access."""
48
55
49
- registry : Dict [str , User ]
50
-
51
- def __init__ (self , ** users ):
52
- self .registry = users
56
+ def __init__ (self , ** users ) -> None :
57
+ self ._registry : Dict [str , User ] = users
58
+ self ._emitter = EventEmitter ()
53
59
54
- async def get (self , id_ ):
60
+ async def get (self , id_ : str ) -> User :
61
+ """Get a user object from the registry"""
55
62
await sleep (0 )
56
- return self .registry .get (id_ )
63
+ return self ._registry .get (id_ )
57
64
58
- async def create (self , ** kwargs ):
65
+ async def create (self , ** kwargs ) -> User :
66
+ """Get a user object in the registry"""
59
67
await sleep (0 )
60
- id_ = str (len (self .registry ))
68
+ id_ = str (len (self ._registry ))
61
69
user = User (id = id_ , ** kwargs )
62
- self .registry [id_ ] = user
70
+ self ._registry [id_ ] = user
71
+ self .emit_event (MutationEnum .CREATED , user )
63
72
return user
64
73
65
- async def update (self , id_ , ** kwargs ):
74
+ async def update (self , id_ : str , ** kwargs ) -> User :
75
+ """Update a user object in the registry"""
66
76
await sleep (0 )
67
- user = self .registry [id_ ]._replace (** kwargs )
68
- self .registry [id_ ] = user
77
+ # noinspection PyProtectedMember
78
+ user = self ._registry [id_ ]._replace (** kwargs )
79
+ self ._registry [id_ ] = user
80
+ self .emit_event (MutationEnum .UPDATED , user )
69
81
return user
70
82
71
- async def delete (self , id_ ):
83
+ async def delete (self , id_ : str ) -> User :
84
+ """Update a user object in the registry"""
72
85
await sleep (0 )
73
- return self .registry .pop (id_ )
86
+ user = self ._registry .pop (id_ )
87
+ self .emit_event (MutationEnum .DELETED , user )
88
+ return user
74
89
90
+ def emit_event (self , mutation : MutationEnum , user : User ) -> None :
91
+ """Emit mutation events for the given object and its class"""
92
+ emit = self ._emitter .emit
93
+ payload = {"user" : user , "mutation" : mutation .value }
94
+ emit ("User" , payload ) # notify all user subscriptions
95
+ emit (f"User_{ user .id } " , payload ) # notify single user subscriptions
75
96
76
- class MutationEnum (Enum ):
77
- """Mutation event type"""
78
-
79
- CREATED = "created"
80
- UPDATED = "updated"
81
- DELETED = "deleted"
97
+ def event_iterator (self , id_ : str ) -> EventEmitterAsyncIterator :
98
+ event_name = "User" if id_ is None else f"User_{ id_ } "
99
+ return EventEmitterAsyncIterator (self ._emitter , event_name )
82
100
83
101
84
102
mutation_type = GraphQLEnumType ("MutationType" , MutationEnum )
@@ -110,16 +128,6 @@ class MutationEnum(Enum):
110
128
)
111
129
112
130
113
- def emit_user_mutation_event (
114
- info : GraphQLResolveInfo , mutation : MutationEnum , user : User
115
- ) -> None :
116
- """Emit mutation events for the given object and its class."""
117
- emit = info .context ["event_emitter" ].emit
118
- payload = {"user" : user , "mutation" : mutation .value }
119
- emit ("User" , payload ) # notify all user subscriptions
120
- emit (f"User_{ user .id } " , payload ) # notify single user subscriptions
121
-
122
-
123
131
async def resolve_user (_root , info , ** args ):
124
132
"""Resolver function for fetching a user object"""
125
133
return await info .context ["registry" ].get (args ["id" ])
@@ -128,15 +136,13 @@ async def resolve_user(_root, info, **args):
128
136
async def resolve_create_user (_root , info , data ):
129
137
"""Resolver function for creating a user object"""
130
138
user = await info .context ["registry" ].create (** data )
131
- emit_user_mutation_event (info , MutationEnum .CREATED , user )
132
139
return user
133
140
134
141
135
142
# noinspection PyShadowingBuiltins
136
143
async def resolve_update_user (_root , info , id , data ):
137
144
"""Resolver function for updating a user object"""
138
145
user = await info .context ["registry" ].update (id , ** data )
139
- emit_user_mutation_event (info , MutationEnum .UPDATED , user )
140
146
return user
141
147
142
148
@@ -145,16 +151,14 @@ async def resolve_delete_user(_root, info, id):
145
151
"""Resolver function for deleting a user object"""
146
152
user = await info .context ["registry" ].get (id )
147
153
await info .context ["registry" ].delete (user .id )
148
- emit_user_mutation_event (info , MutationEnum .DELETED , user )
149
154
return True
150
155
151
156
152
157
# noinspection PyShadowingBuiltins
153
158
async def subscribe_user (_root , info , id = None ):
154
159
"""Subscribe to mutations of a specific user object or all user objects"""
155
- event_emitter = info .context ["event_emitter" ]
156
- event_name = "User" if id is None else f"User_{ id } "
157
- async for msg in EventEmitterAsyncIterator (event_emitter , event_name ):
160
+ async_iterator = info .context ["registry" ].event_iterator (id )
161
+ async for msg in async_iterator :
158
162
yield msg
159
163
160
164
@@ -210,7 +214,7 @@ async def resolve_subscription_user(event, info, id):
210
214
211
215
@fixture
212
216
def context ():
213
- return {"event_emitter" : EventEmitter (), " registry" : UserRegistry ()}
217
+ return {"registry" : UserRegistry ()}
214
218
215
219
216
220
def describe_query ():
@@ -256,8 +260,10 @@ def receive(msg):
256
260
257
261
return receive
258
262
259
- context ["event_emitter" ].add_listener ("User" , receiver ("User" ))
260
- context ["event_emitter" ].add_listener ("User_0" , receiver ("User_0" ))
263
+ # noinspection PyProtectedMember
264
+ add_listener = context ["registry" ]._emitter .add_listener
265
+ add_listener ("User" , receiver ("User" ))
266
+ add_listener ("User_0" , receiver ("User_0" ))
261
267
262
268
query = """
263
269
mutation ($userData: UserInputType!) {
@@ -301,8 +307,10 @@ def receive(msg):
301
307
302
308
return receive
303
309
304
- context ["event_emitter" ].add_listener ("User" , receiver ("User" ))
305
- context ["event_emitter" ].add_listener ("User_0" , receiver ("User_0" ))
310
+ # noinspection PyProtectedMember
311
+ add_listener = context ["registry" ]._emitter .add_listener
312
+ add_listener ("User" , receiver ("User" ))
313
+ add_listener ("User_0" , receiver ("User_0" ))
306
314
307
315
user = await context ["registry" ].create (
308
316
firstName = "John" , lastName = "Doe" , tweets = 42 , verified = True
@@ -355,8 +363,10 @@ def receive(msg):
355
363
356
364
return receive
357
365
358
- context ["event_emitter" ].add_listener ("User" , receiver ("User" ))
359
- context ["event_emitter" ].add_listener ("User_0" , receiver ("User_0" ))
366
+ # noinspection PyProtectedMember
367
+ add_listener = context ["registry" ]._emitter .add_listener
368
+ add_listener ("User" , receiver ("User" ))
369
+ add_listener ("User_0" , receiver ("User_0" ))
360
370
361
371
user = await context ["registry" ].create (
362
372
firstName = "John" , lastName = "Doe" , tweets = 42 , verified = True
0 commit comments