Coverage for src/lexigram/graphql/events.py: 100%

23 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""GraphQL lifecycle domain events. 

2 

3Typed :class:`~lexigram.contracts.domain.events.DomainEvent` subclasses 

4published to the :class:`~lexigram.contracts.events.EventBusProtocol` during 

5GraphQL operation execution and schema lifecycle. Consumers subscribe to 

6specific event types via the bus rather than through ad-hoc hook registrations. 

7 

8Example:: 

9 

10 from lexigram.contracts.events import EventBusProtocol 

11 from lexigram.graphql.events import AfterExecuteEvent 

12 

13 class QueryLogger: 

14 async def handle(self, event: AfterExecuteEvent) -> None: 

15 logger.info("query_completed", operation=event.execution_context.operation_name) 

16 

17 bus.subscribe(AfterExecuteEvent, QueryLogger()) 

18""" 

19 

20from __future__ import annotations 

21 

22from dataclasses import dataclass 

23from typing import TYPE_CHECKING, Any 

24 

25from lexigram.contracts.domain.events import DomainEvent 

26 

27if TYPE_CHECKING: 

28 from lexigram.graphql.core.execution import ExecutionContextProtocol 

29 

30 

31@dataclass(frozen=True, init=False) 

32class BeforeExecuteEvent(DomainEvent): 

33 """Emitted immediately before a GraphQL operation is sent to Strawberry. 

34 

35 Subscribers may inspect the execution context (query, variables, user) but 

36 must NOT modify it — the event is immutable by design. 

37 """ 

38 

39 execution_context: ExecutionContextProtocol 

40 

41 

42@dataclass(frozen=True, init=False) 

43class AfterExecuteEvent(DomainEvent): 

44 """Emitted after a GraphQL operation completes successfully. 

45 

46 Contains the execution context with timing information and the raw response. 

47 """ 

48 

49 execution_context: ExecutionContextProtocol 

50 result: Any 

51 

52 

53@dataclass(frozen=True, init=False) 

54class OnErrorEvent(DomainEvent): 

55 """Emitted when a GraphQL operation encounters an unhandled exception. 

56 

57 This is fired for infrastructure-level errors (timeouts, executor crashes), 

58 not for user-facing field errors which are part of the normal GraphQL response. 

59 """ 

60 

61 execution_context: ExecutionContextProtocol 

62 error: Exception 

63 

64 

65@dataclass(frozen=True, init=False) 

66class SchemaBuiltEvent(DomainEvent): 

67 """Emitted after the GraphQL schema is successfully built. 

68 

69 Consumers may inspect type counts for observability and diagnostics. 

70 """ 

71 

72 type_count: int 

73 

74 

75@dataclass(frozen=True, init=False) 

76class SubscriptionStartedEvent(DomainEvent): 

77 """Emitted when a GraphQL subscription is established. 

78 

79 Provides the subscription identifier and operation name for tracking 

80 and auditing long-lived connections. 

81 """ 

82 

83 subscription_id: str 

84 operation: str 

85 

86 

87__all__ = [ 

88 "AfterExecuteEvent", 

89 "BeforeExecuteEvent", 

90 "OnErrorEvent", 

91 "SchemaBuiltEvent", 

92 "SubscriptionStartedEvent", 

93]