Skip to content

Commit 9fa8827

Browse files
committed
Make user registry example a bit cleaner
Move the event emitter into the registry so that mutation events are triggered by all registry changes.
1 parent 01d228a commit 9fa8827

File tree

1 file changed

+54
-44
lines changed

1 file changed

+54
-44
lines changed

tests/test_user_registry.py

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
GraphQLInt,
2525
GraphQLNonNull,
2626
GraphQLObjectType,
27-
GraphQLResolveInfo,
2827
GraphQLSchema,
2928
GraphQLString,
3029
)
@@ -43,42 +42,61 @@ class User(NamedTuple):
4342
verified: bool = False
4443

4544

45+
class MutationEnum(Enum):
46+
"""Mutation event type"""
47+
48+
CREATED = "created"
49+
UPDATED = "updated"
50+
DELETED = "deleted"
51+
52+
4653
class UserRegistry:
4754
""""Simulation of a user registry with asynchronous database backend access."""
4855

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()
5359

54-
async def get(self, id_):
60+
async def get(self, id_: str) -> User:
61+
"""Get a user object from the registry"""
5562
await sleep(0)
56-
return self.registry.get(id_)
63+
return self._registry.get(id_)
5764

58-
async def create(self, **kwargs):
65+
async def create(self, **kwargs) -> User:
66+
"""Get a user object in the registry"""
5967
await sleep(0)
60-
id_ = str(len(self.registry))
68+
id_ = str(len(self._registry))
6169
user = User(id=id_, **kwargs)
62-
self.registry[id_] = user
70+
self._registry[id_] = user
71+
self.emit_event(MutationEnum.CREATED, user)
6372
return user
6473

65-
async def update(self, id_, **kwargs):
74+
async def update(self, id_: str, **kwargs) -> User:
75+
"""Update a user object in the registry"""
6676
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)
6981
return user
7082

71-
async def delete(self, id_):
83+
async def delete(self, id_: str) -> User:
84+
"""Update a user object in the registry"""
7285
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
7489

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
7596

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)
82100

83101

84102
mutation_type = GraphQLEnumType("MutationType", MutationEnum)
@@ -110,16 +128,6 @@ class MutationEnum(Enum):
110128
)
111129

112130

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-
123131
async def resolve_user(_root, info, **args):
124132
"""Resolver function for fetching a user object"""
125133
return await info.context["registry"].get(args["id"])
@@ -128,15 +136,13 @@ async def resolve_user(_root, info, **args):
128136
async def resolve_create_user(_root, info, data):
129137
"""Resolver function for creating a user object"""
130138
user = await info.context["registry"].create(**data)
131-
emit_user_mutation_event(info, MutationEnum.CREATED, user)
132139
return user
133140

134141

135142
# noinspection PyShadowingBuiltins
136143
async def resolve_update_user(_root, info, id, data):
137144
"""Resolver function for updating a user object"""
138145
user = await info.context["registry"].update(id, **data)
139-
emit_user_mutation_event(info, MutationEnum.UPDATED, user)
140146
return user
141147

142148

@@ -145,16 +151,14 @@ async def resolve_delete_user(_root, info, id):
145151
"""Resolver function for deleting a user object"""
146152
user = await info.context["registry"].get(id)
147153
await info.context["registry"].delete(user.id)
148-
emit_user_mutation_event(info, MutationEnum.DELETED, user)
149154
return True
150155

151156

152157
# noinspection PyShadowingBuiltins
153158
async def subscribe_user(_root, info, id=None):
154159
"""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:
158162
yield msg
159163

160164

@@ -210,7 +214,7 @@ async def resolve_subscription_user(event, info, id):
210214

211215
@fixture
212216
def context():
213-
return {"event_emitter": EventEmitter(), "registry": UserRegistry()}
217+
return {"registry": UserRegistry()}
214218

215219

216220
def describe_query():
@@ -256,8 +260,10 @@ def receive(msg):
256260

257261
return receive
258262

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"))
261267

262268
query = """
263269
mutation ($userData: UserInputType!) {
@@ -301,8 +307,10 @@ def receive(msg):
301307

302308
return receive
303309

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"))
306314

307315
user = await context["registry"].create(
308316
firstName="John", lastName="Doe", tweets=42, verified=True
@@ -355,8 +363,10 @@ def receive(msg):
355363

356364
return receive
357365

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"))
360370

361371
user = await context["registry"].create(
362372
firstName="John", lastName="Doe", tweets=42, verified=True

0 commit comments

Comments
 (0)