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.
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
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])});"
|
||||
Reference in New Issue
Block a user