-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgateway.py
More file actions
49 lines (35 loc) · 1.64 KB
/
Copy pathgateway.py
File metadata and controls
49 lines (35 loc) · 1.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
"""The mini-project: one expensive connection, three kinds of mediation.
The stack, outside-in: metering observes everything (including denials),
protection guards by role, laziness defers the expensive connect until a
query actually runs. This composition over one subject is what a single
``cached_property`` cannot express -- and the reason the pattern survives.
"""
from __future__ import annotations
from patterns.structural.proxy.pattern import LazyProxy, MeteringProxy, ProtectionProxy
READ_ONLY_ATTRS = frozenset({"query", "connected"})
class WarehouseConnection:
"""The real subject; pretend ``__init__`` dials a distant warehouse."""
instances_connected = 0
def __init__(self, dsn: str) -> None:
type(self).instances_connected += 1
self.dsn = dsn
self.connected = True
self.queries_run: list[str] = []
def query(self, sql: str) -> list[str]:
self.queries_run.append(sql)
return [f"row for {sql!r}"]
def drop_table(self, name: str) -> str:
return f"dropped {name}"
def allow_for_role(role: str) -> frozenset[str]:
"""Analyst sees the read-only surface; admin sees everything."""
return (
frozenset({"query", "connected", "drop_table", "dsn", "queries_run"})
if role == "admin"
else READ_ONLY_ATTRS
)
def build_gateway(dsn: str, *, role: str) -> MeteringProxy:
"""Stack the three proxies over one lazily-built connection."""
allowed = allow_for_role(role)
lazy = LazyProxy(lambda: WarehouseConnection(dsn))
guarded = ProtectionProxy(lazy, lambda name: name in allowed or name == "is_built")
return MeteringProxy(guarded)