refactor(db)!: finalize pooled WNDB v2 migration
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
"""Read-only projections backed by the GIS materialized-view query layer."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ..core.database import read, read_all
|
||||
|
||||
|
||||
def _node_coord_rows(
|
||||
rows: list[Any],
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
return {
|
||||
str(row["id"]): {
|
||||
"x": float(row["x"]),
|
||||
"y": float(row["y"]),
|
||||
"type": str(row["node_type"]),
|
||||
}
|
||||
for row in rows
|
||||
}
|
||||
|
||||
|
||||
def get_network_node_coords(name: str) -> dict[str, dict[str, Any]]:
|
||||
"""Return every publishable node with one view-backed query."""
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT id, x, y, node_type
|
||||
FROM gis.network_nodes
|
||||
ORDER BY id
|
||||
""",
|
||||
)
|
||||
return _node_coord_rows(rows)
|
||||
|
||||
|
||||
def get_major_node_coords(
|
||||
name: str, diameter: int
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
"""Return endpoints of pipes above the requested diameter."""
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT n.id, n.x, n.y, n.node_type
|
||||
FROM gis.pipes AS p
|
||||
CROSS JOIN LATERAL (
|
||||
VALUES (p.start_node_id), (p.end_node_id)
|
||||
) AS endpoint(id)
|
||||
JOIN gis.network_nodes AS n ON n.id = endpoint.id
|
||||
WHERE p.diameter > %s
|
||||
GROUP BY n.id, n.x, n.y, n.node_type
|
||||
ORDER BY n.id
|
||||
""",
|
||||
(diameter,),
|
||||
)
|
||||
return _node_coord_rows(rows)
|
||||
|
||||
|
||||
def get_network_link_nodes(name: str) -> list[str]:
|
||||
"""Return every publishable link in the established API wire format."""
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT id, link_type, start_node_id, end_node_id
|
||||
FROM gis.network_links
|
||||
ORDER BY id
|
||||
""",
|
||||
)
|
||||
return [
|
||||
f"{row['id']}:{row['link_type']}:{row['start_node_id']}:{row['end_node_id']}"
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
def get_major_pipe_nodes(name: str, diameter: int) -> list[str]:
|
||||
"""Return large pipes in the established API wire format."""
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT id, start_node_id, end_node_id
|
||||
FROM gis.pipes
|
||||
WHERE diameter > %s
|
||||
ORDER BY id
|
||||
""",
|
||||
(diameter,),
|
||||
)
|
||||
return [
|
||||
f"{row['id']}:pipe:{row['start_node_id']}:{row['end_node_id']}"
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
def get_topology_rows(
|
||||
name: str, node_ids: list[str]
|
||||
) -> tuple[list[Any], list[Any]]:
|
||||
"""Load selected nodes and their internal links with two batch queries."""
|
||||
if not node_ids:
|
||||
return [], []
|
||||
|
||||
nodes = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT n.id,
|
||||
ST_X(g.geom) AS x,
|
||||
ST_Y(g.geom) AS y,
|
||||
n.node_type::text AS node_type
|
||||
FROM network.nodes AS n
|
||||
JOIN gis.node_geometries AS g ON g.node_id = n.id
|
||||
WHERE n.id = ANY(%s)
|
||||
ORDER BY n.id
|
||||
""",
|
||||
(node_ids,),
|
||||
)
|
||||
links = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT l.id,
|
||||
l.start_node_id,
|
||||
l.end_node_id,
|
||||
COALESCE(p.length, 0.0) AS length
|
||||
FROM network.links AS l
|
||||
LEFT JOIN network.pipes AS p ON p.link_id = l.id
|
||||
WHERE l.start_node_id = ANY(%s)
|
||||
AND l.end_node_id = ANY(%s)
|
||||
ORDER BY l.id
|
||||
""",
|
||||
(node_ids, node_ids),
|
||||
)
|
||||
return nodes, links
|
||||
|
||||
|
||||
def get_boundary_link_ids(name: str, node_ids: list[str]) -> list[str]:
|
||||
"""Return links with exactly one endpoint inside the supplied node set."""
|
||||
if not node_ids:
|
||||
return []
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT id
|
||||
FROM network.links
|
||||
WHERE (start_node_id = ANY(%s)) <> (end_node_id = ANY(%s))
|
||||
ORDER BY id
|
||||
""",
|
||||
(node_ids, node_ids),
|
||||
)
|
||||
return [str(row["id"]) for row in rows]
|
||||
|
||||
|
||||
def get_junction_demands(
|
||||
name: str, node_ids: list[str]
|
||||
) -> dict[str, list[dict[str, Any]]]:
|
||||
"""Read authoritative demands for selected junctions from model tables."""
|
||||
if not node_ids:
|
||||
return {}
|
||||
rows = read_all(
|
||||
name,
|
||||
"""
|
||||
SELECT junction_id,
|
||||
sequence_no,
|
||||
base_demand,
|
||||
pattern_id,
|
||||
category
|
||||
FROM network.demands
|
||||
WHERE junction_id = ANY(%s)
|
||||
ORDER BY junction_id, sequence_no
|
||||
""",
|
||||
(node_ids,),
|
||||
)
|
||||
result: dict[str, list[dict[str, Any]]] = {}
|
||||
for row in rows:
|
||||
result.setdefault(str(row["junction_id"]), []).append(
|
||||
{
|
||||
"demand": float(row["base_demand"]),
|
||||
"pattern": row["pattern_id"],
|
||||
"category": row["category"],
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def sum_junction_base_demand(name: str, node_ids: list[str]) -> float:
|
||||
"""Sum selected junction demand from the authoritative model table."""
|
||||
if not node_ids:
|
||||
return 0.0
|
||||
row = read(
|
||||
name,
|
||||
"""
|
||||
SELECT COALESCE(SUM(base_demand), 0.0) AS total_base_demand
|
||||
FROM network.demands
|
||||
WHERE junction_id = ANY(%s)
|
||||
""",
|
||||
(node_ids,),
|
||||
)
|
||||
return float(row["total_base_demand"])
|
||||
Reference in New Issue
Block a user