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.
128 lines
4.1 KiB
Python
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])});"
|