|
1 | | -import enum |
| 1 | +from collections.abc import Mapping |
2 | 2 | from dataclasses import dataclass, field, replace |
3 | | -from typing import Any |
| 3 | +from typing import Protocol, runtime_checkable |
4 | 4 |
|
5 | | -__all__ = ("Flow", "FlowKind") |
| 5 | +__all__ = ("Flow", "FlowProtocol") |
6 | 6 |
|
7 | 7 |
|
8 | | -@enum.unique |
9 | | -class FlowKind(str, enum.Enum): |
10 | | - """Transport-neutral flow shape.""" |
| 8 | +@runtime_checkable |
| 9 | +class FlowProtocol(Protocol): |
| 10 | + """Transport-neutral flow contract accepted by routers and brokers.""" |
11 | 11 |
|
12 | | - QUEUE = "queue" |
13 | | - TOPIC = "topic" |
14 | | - STREAM = "stream" |
| 12 | + name: str |
| 13 | + |
| 14 | + def broker_options(self, broker_name: str) -> Mapping[str, object]: |
| 15 | + """Return options relevant for a concrete broker implementation.""" |
| 16 | + ... |
15 | 17 |
|
16 | 18 |
|
17 | 19 | @dataclass(frozen=True, slots=True) |
18 | 20 | class Flow: |
19 | | - """Transport-neutral publish or subscribe address. |
20 | | -
|
21 | | - Plain flows are intentionally generic. Every broker may interpret a flow |
22 | | - using its own defaults: queue name, topic, stream, channel, list key, or any |
23 | | - other transport address. |
| 21 | + """Generic transport-neutral flow address. |
24 | 22 |
|
25 | | - Broker packages can subclass this value object to expose transport-specific |
26 | | - details while still accepting plain Flow instances. |
| 23 | + Broker packages can provide their own flow objects that implement |
| 24 | + FlowProtocol, for example RabbitQueue, KafkaTopic, NatsSubject or RedisQueue. |
| 25 | + This generic value object is intentionally small and works as a common |
| 26 | + fallback for brokers that only need a named address with optional metadata. |
27 | 27 | """ |
28 | 28 |
|
29 | 29 | name: str |
30 | | - kind: FlowKind = FlowKind.QUEUE |
31 | | - options: dict[str, Any] = field( |
| 30 | + options: Mapping[str, object] = field( |
32 | 31 | default_factory=dict, |
33 | 32 | compare=False, |
34 | 33 | hash=False, |
35 | 34 | ) |
36 | 35 |
|
37 | | - @classmethod |
38 | | - def queue(cls, name: str, **options: Any) -> "Flow": |
39 | | - """Create a queue-like flow.""" |
40 | | - return cls(name=name, kind=FlowKind.QUEUE, options=options) |
41 | | - |
42 | | - @classmethod |
43 | | - def topic(cls, name: str, **options: Any) -> "Flow": |
44 | | - """Create a topic-like flow.""" |
45 | | - return cls(name=name, kind=FlowKind.TOPIC, options=options) |
46 | | - |
47 | | - @classmethod |
48 | | - def stream(cls, name: str, **options: Any) -> "Flow": |
49 | | - """Create a stream-like flow.""" |
50 | | - return cls(name=name, kind=FlowKind.STREAM, options=options) |
51 | | - |
52 | | - def with_options(self, **options: Any) -> "Flow": |
| 36 | + def with_options(self, **options: object) -> "Flow": |
53 | 37 | """Return the same flow with additional generic options.""" |
54 | 38 | return replace(self, options={**self.options, **options}) |
55 | 39 |
|
56 | | - def broker_options(self, broker_name: str) -> dict[str, Any]: |
| 40 | + def broker_options(self, broker_name: str) -> Mapping[str, object]: |
57 | 41 | """Return transport options for broker-specific implementations.""" |
58 | 42 | return dict(self.options) |
0 commit comments