Files
TJWaterServerBinary/app/native/wndb/gis/regions.py
jiang fa188af0b1 refactor(db)!: adopt project-routed pooled databases
Reorganize WNDB by responsibility and remove legacy scheme endpoints.\n\nRoute analysis and time-series access through project pools, preserve transactional realtime replacement, and refresh GIS materialized views after writes.\n\nAdd database architecture documentation, live pooling coverage, API contract updates, and executable container verification.\n\nBREAKING CHANGE: legacy scheme APIs and flat app.native.wndb module imports are removed.
2026-08-25 18:35:05 +08:00

128 lines
4.1 KiB
Python

from typing import Any
from ..core.database import (
ChangeSet,
DatabaseCommand,
execute_command,
g_add_prefix,
g_delete_prefix,
g_update_prefix,
sql_literal,
try_read,
)
from .region_geometry import from_postgis_polygon, to_postgis_polygon
def get_region_schema(name: str) -> dict[str, dict[str, Any]]:
return {
"id": {"type": "str", "optional": False, "readonly": True},
"region_type": {"type": "str", "optional": False, "readonly": False},
"boundary": {"type": "tuple_list", "optional": False, "readonly": False},
}
def get_region(name: str, id: str) -> dict[str, Any]:
row = try_read(
name,
"select id, region_type, st_astext(boundary) as boundary_geom "
"from gis.regions where id = %s",
(id,),
)
if row is None:
return {}
return {
"id": str(row["id"]),
"region_type": str(row["region_type"]),
"boundary": from_postgis_polygon(str(row["boundary_geom"])),
}
def _valid_boundary(boundary: list[Any]) -> bool:
return len(boundary) >= 4 and boundary[0] == boundary[-1]
def _set_region(name: str, cs: ChangeSet) -> DatabaseCommand:
region_id = cs.operations[0]["id"]
old = get_region(name, region_id)
new = old | {
key: cs.operations[0][key]
for key in ("region_type", "boundary")
if key in cs.operations[0]
}
statement = (
"update gis.regions set "
f"region_type = {sql_literal(new['region_type'])}, "
f"boundary = st_geomfromtext({sql_literal(to_postgis_polygon(new['boundary']))}, 900914) "
f"where id = {sql_literal(region_id)};"
)
return DatabaseCommand(
statement,
[g_update_prefix | {"type": "region"} | new],
)
def set_region(name: str, cs: ChangeSet) -> ChangeSet:
operation = cs.operations[0]
if "id" not in operation or get_region(name, operation["id"]) == {}:
return ChangeSet()
if "boundary" in operation and not _valid_boundary(operation["boundary"]):
return ChangeSet()
return execute_command(name, _set_region(name, cs))
def _add_region(name: str, cs: ChangeSet) -> DatabaseCommand:
operation = cs.operations[0]
region_id = operation["id"]
region_type = str(operation.get("region_type", "none"))
boundary = operation["boundary"]
statement = (
"insert into gis.regions (id, region_type, boundary) values "
f"({sql_literal(region_id)}, {sql_literal(region_type)}, "
f"st_geomfromtext({sql_literal(to_postgis_polygon(boundary))}, 900914));"
)
value = {"type": "region", "id": region_id, "region_type": region_type, "boundary": boundary}
return DatabaseCommand(
statement,
[g_add_prefix | value],
)
def add_region(name: str, cs: ChangeSet) -> ChangeSet:
operation = cs.operations[0]
if "id" not in operation or "boundary" not in operation:
return ChangeSet()
if not _valid_boundary(operation["boundary"]):
return ChangeSet()
if get_region(name, operation["id"]) != {}:
return ChangeSet()
return execute_command(name, _add_region(name, cs))
def _delete_region(name: str, cs: ChangeSet) -> DatabaseCommand:
region_id = cs.operations[0]["id"]
statement = f"delete from gis.regions where id = {sql_literal(region_id)};"
return DatabaseCommand(
statement,
[g_delete_prefix | {"type": "region", "id": region_id}],
)
def delete_region(name: str, cs: ChangeSet) -> ChangeSet:
if "id" not in cs.operations[0] or get_region(name, cs.operations[0]["id"]) == {}:
return ChangeSet()
return execute_command(name, _delete_region(name, cs))
def inp_in_region(line: str) -> str:
tokens = line.split()
return f"insert into gis.regions (id, region_type) values ({sql_literal(tokens[0])}, {sql_literal(tokens[1])});"
def inp_in_bound(line: str) -> str:
return line.split()[0]
def inp_in_regionnodes(line: str) -> str:
tokens = line.split()
return f"insert into gis.region_nodes (region_id, node_id) values ({sql_literal(tokens[0])}, {sql_literal(tokens[1])});"