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:
+210
-574
@@ -1,43 +1,23 @@
|
||||
import ast
|
||||
import json
|
||||
from datetime import date, datetime
|
||||
from typing import Any
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import geopandas as gpd
|
||||
import pandas as pd
|
||||
import psycopg
|
||||
from sqlalchemy import create_engine
|
||||
from psycopg.types.json import Jsonb
|
||||
|
||||
from app.infra.db.project_routing import get_project_pgconn_string
|
||||
from app.native.wndb.core.connection import project_connection
|
||||
from app.services.time_api import parse_utc_time
|
||||
|
||||
|
||||
# 2025/03/23
|
||||
def scheme_name_exists(name: str, scheme_name: str) -> bool:
|
||||
"""
|
||||
判断传入的 scheme_name 是否已存在于 scheme_list 表中,用于输入框判断
|
||||
:param name: 数据库名称
|
||||
:param scheme_name: 需要判断的方案名称
|
||||
:return: 如果存在返回 True,否则返回 False
|
||||
"""
|
||||
try:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT COUNT(*) FROM scheme_list WHERE scheme_name = %s",
|
||||
(scheme_name,),
|
||||
)
|
||||
result = cur.fetchone()
|
||||
if result is not None and result[0] > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"查询 scheme_name 时出错:{e}")
|
||||
return False
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"select exists(select 1 from analysis.runs where name = %s)",
|
||||
(scheme_name,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return bool(row and row[0])
|
||||
|
||||
|
||||
# 2025/03/23
|
||||
def store_scheme_info(
|
||||
name: str,
|
||||
scheme_name: str,
|
||||
@@ -45,202 +25,165 @@ def store_scheme_info(
|
||||
username: str,
|
||||
scheme_start_time: datetime | str,
|
||||
scheme_detail: dict,
|
||||
):
|
||||
"""
|
||||
将一条方案记录插入 scheme_list 表中
|
||||
:param name: 数据库名称
|
||||
:param scheme_name: 方案名称
|
||||
:param scheme_type: 方案类型
|
||||
:param username: MetaDB 中的用户名快照
|
||||
:param scheme_start_time: 带时区的方案起始时间;写入前统一转换为 UTC
|
||||
:param scheme_detail: 方案详情(字典,会转换为 JSON)
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
sql = """
|
||||
INSERT INTO scheme_list (scheme_name, scheme_type, username, scheme_start_time, scheme_detail)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
"""
|
||||
# 将字典转换为 JSON 字符串
|
||||
scheme_detail_json = json.dumps(scheme_detail)
|
||||
normalized_scheme_start_time = parse_utc_time(
|
||||
scheme_start_time, field_name="scheme_start_time"
|
||||
)
|
||||
cur.execute(
|
||||
sql,
|
||||
(
|
||||
scheme_name,
|
||||
scheme_type,
|
||||
username,
|
||||
normalized_scheme_start_time,
|
||||
scheme_detail_json,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
print("方案信息存储成功!")
|
||||
except Exception as e:
|
||||
print(f"存储方案信息时出错:{e}")
|
||||
) -> UUID:
|
||||
"""Create one completed, immutable analysis run."""
|
||||
return create_analysis_run(
|
||||
name=name,
|
||||
scheme_name=scheme_name,
|
||||
scheme_type=scheme_type,
|
||||
username=username,
|
||||
scheme_start_time=scheme_start_time,
|
||||
scheme_detail=scheme_detail,
|
||||
status="completed",
|
||||
)
|
||||
|
||||
|
||||
# 2025/03/23
|
||||
def delete_scheme_info(name: str, scheme_name: str) -> None:
|
||||
"""
|
||||
从 scheme_list 表中删除指定的方案
|
||||
:param name: 数据库名称
|
||||
:param scheme_name: 要删除的方案名称
|
||||
"""
|
||||
try:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
# 使用参数化查询删除方案记录
|
||||
cur.execute(
|
||||
"DELETE FROM scheme_list WHERE scheme_name = %s", (scheme_name,)
|
||||
)
|
||||
conn.commit()
|
||||
print(f"方案 {scheme_name} 删除成功!")
|
||||
except Exception as e:
|
||||
print(f"删除方案时出错:{e}")
|
||||
def create_analysis_run(
|
||||
name: str,
|
||||
scheme_name: str,
|
||||
scheme_type: str,
|
||||
username: str,
|
||||
scheme_start_time: datetime | str,
|
||||
scheme_detail: dict,
|
||||
*,
|
||||
status: str = "running",
|
||||
) -> UUID:
|
||||
"""Create a distinct execution record; names are labels, not identities."""
|
||||
started_at = parse_utc_time(scheme_start_time, field_name="scheme_start_time")
|
||||
run_id = uuid4()
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
insert into analysis.runs
|
||||
(run_id, name, run_type, created_by, created_at, started_at, status, parameters)
|
||||
values (%s, %s, %s, %s, now(), %s, %s, %s)
|
||||
""",
|
||||
(
|
||||
run_id,
|
||||
scheme_name,
|
||||
scheme_type,
|
||||
username,
|
||||
started_at,
|
||||
status,
|
||||
Jsonb(scheme_detail),
|
||||
),
|
||||
)
|
||||
return run_id
|
||||
|
||||
|
||||
def update_analysis_run(
|
||||
name: str,
|
||||
run_id: UUID,
|
||||
*,
|
||||
status: str,
|
||||
username: str,
|
||||
scheme_detail: dict,
|
||||
) -> None:
|
||||
"""Update lifecycle state and metadata for one execution identity."""
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
update analysis.runs
|
||||
set created_by = %s, status = %s, parameters = %s
|
||||
where run_id = %s
|
||||
""",
|
||||
(username, status, Jsonb(scheme_detail), run_id),
|
||||
)
|
||||
if cur.rowcount != 1:
|
||||
raise LookupError(f"analysis run {run_id} does not exist")
|
||||
|
||||
|
||||
def _run_row(row: dict[str, Any]) -> dict[str, Any]:
|
||||
parameters = row.get("parameters") if isinstance(row.get("parameters"), dict) else {}
|
||||
return {
|
||||
"run_id": row["run_id"],
|
||||
"name": row["name"],
|
||||
"run_type": row["run_type"],
|
||||
"created_by": row["created_by"],
|
||||
"created_at": row["created_at"],
|
||||
"started_at": row["started_at"],
|
||||
"status": row["status"],
|
||||
"parameters": parameters,
|
||||
}
|
||||
|
||||
|
||||
def _list_runs(
|
||||
name: str,
|
||||
run_type: str | None = None,
|
||||
query_date: date | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
clauses: list[str] = []
|
||||
params: list[Any] = []
|
||||
if run_type:
|
||||
clauses.append("run_type = %s")
|
||||
params.append(run_type)
|
||||
if query_date is not None:
|
||||
clauses.append("created_at::date = %s")
|
||||
params.append(query_date)
|
||||
where = f"where {' and '.join(clauses)}" if clauses else ""
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
f"select run_id, name, run_type, created_by, created_at, started_at, status, parameters from analysis.runs {where} order by created_at desc",
|
||||
params,
|
||||
)
|
||||
return [_run_row(row) for row in cur.fetchall()]
|
||||
|
||||
|
||||
# 2025/03/23
|
||||
def query_scheme_list(
|
||||
name: str,
|
||||
scheme_type: str | None = None,
|
||||
query_date: date | None = None,
|
||||
) -> list:
|
||||
"""
|
||||
查询pg数据库中的scheme_list,按照 create_time 降序排列,离现在时间最近的记录排在最前面
|
||||
:param name: 项目名称(数据库名称)
|
||||
:param scheme_type: 方案类型;为空时返回全部类型
|
||||
:param query_date: 查询日期;为空时不按日期过滤
|
||||
:return: 返回查询结果的所有行
|
||||
"""
|
||||
try:
|
||||
# 动态替换数据库名称
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
# 连接到 PostgreSQL 数据库(这里是数据库 "bb")
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
if scheme_type and query_date is not None:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT *
|
||||
FROM scheme_list
|
||||
WHERE scheme_type = %s AND DATE(create_time) = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type, query_date),
|
||||
)
|
||||
elif scheme_type:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT *
|
||||
FROM scheme_list
|
||||
WHERE scheme_type = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type,),
|
||||
)
|
||||
elif query_date is not None:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT *
|
||||
FROM scheme_list
|
||||
WHERE DATE(create_time) = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(query_date,),
|
||||
)
|
||||
else:
|
||||
cur.execute("SELECT * FROM scheme_list ORDER BY create_time DESC")
|
||||
rows = cur.fetchall()
|
||||
return rows
|
||||
|
||||
except Exception as e:
|
||||
print(f"查询错误:{e}")
|
||||
) -> list[dict[str, Any]]:
|
||||
return _list_runs(name, scheme_type, query_date)
|
||||
|
||||
|
||||
def _filter_scheme_detail_scope(
|
||||
result: dict,
|
||||
def _get_run_by_name(
|
||||
name: str,
|
||||
scheme_type: str | None = None,
|
||||
) -> dict:
|
||||
if not result:
|
||||
return {}
|
||||
if scheme_type and result.get("scheme_type") != scheme_type:
|
||||
return {}
|
||||
network = result.get("network")
|
||||
if network not in (None, name):
|
||||
return {}
|
||||
return result
|
||||
run_name: str,
|
||||
run_type: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
params: list[Any] = [run_name]
|
||||
type_clause = ""
|
||||
if run_type:
|
||||
type_clause = "and run_type = %s"
|
||||
params.append(run_type)
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
f"""
|
||||
select run_id, name, run_type, created_by, created_at, started_at,
|
||||
status, parameters
|
||||
from analysis.runs
|
||||
where name = %s {type_clause}
|
||||
order by created_at desc
|
||||
limit 1
|
||||
""",
|
||||
params,
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return _run_row(row) if row else {}
|
||||
|
||||
|
||||
def get_analysis_run(name: str, run_id: UUID) -> dict[str, Any]:
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
select run_id, name, run_type, created_by, created_at, started_at,
|
||||
status, parameters
|
||||
from analysis.runs
|
||||
where run_id = %s
|
||||
""",
|
||||
(run_id,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
return _run_row(row) if row else {}
|
||||
|
||||
|
||||
def query_scheme_detail(
|
||||
name: str,
|
||||
scheme_name: str,
|
||||
scheme_type: str | None = None,
|
||||
) -> dict:
|
||||
if scheme_type == "dma_leak_identification":
|
||||
return _filter_scheme_detail_scope(
|
||||
query_leakage_identify_scheme_detail(name, scheme_name),
|
||||
name,
|
||||
scheme_type,
|
||||
)
|
||||
if scheme_type == "burst_detection":
|
||||
return _filter_scheme_detail_scope(
|
||||
query_burst_detection_scheme_detail(name, scheme_name),
|
||||
name,
|
||||
scheme_type,
|
||||
)
|
||||
if scheme_type == "burst_location":
|
||||
return _filter_scheme_detail_scope(
|
||||
query_burst_location_scheme_detail(name, scheme_name),
|
||||
name,
|
||||
scheme_type,
|
||||
)
|
||||
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
if scheme_type:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_name = %s AND scheme_type = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name, scheme_type),
|
||||
)
|
||||
else:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_name = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if row is None:
|
||||
return {}
|
||||
detail = row[6] if isinstance(row[6], dict) else {}
|
||||
return _filter_scheme_detail_scope({
|
||||
"scheme_id": row[0],
|
||||
"scheme_name": row[1],
|
||||
"scheme_type": row[2],
|
||||
"username": row[3],
|
||||
"create_time": row[4],
|
||||
"scheme_start_time": row[5],
|
||||
"scheme_detail": detail,
|
||||
"network": detail.get("network"),
|
||||
"result_payload": detail.get("result_payload", {}),
|
||||
}, name, scheme_type)
|
||||
) -> dict[str, Any]:
|
||||
return _get_run_by_name(name, scheme_name, scheme_type)
|
||||
|
||||
|
||||
def store_leakage_identify_result(
|
||||
@@ -255,42 +198,51 @@ def store_leakage_identify_result(
|
||||
run_status: str = "completed",
|
||||
error_message: str | None = None,
|
||||
) -> None:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO public.leakage_identify_result
|
||||
(
|
||||
scheme_name, network, run_status, error_message,
|
||||
sensor_nodes, result_rows, node_area_map, areas, drawing_payload
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s::jsonb, %s::jsonb, %s::jsonb, %s::jsonb, %s::jsonb)
|
||||
ON CONFLICT (scheme_name)
|
||||
DO UPDATE SET
|
||||
network = EXCLUDED.network,
|
||||
run_status = EXCLUDED.run_status,
|
||||
error_message = EXCLUDED.error_message,
|
||||
sensor_nodes = EXCLUDED.sensor_nodes,
|
||||
result_rows = EXCLUDED.result_rows,
|
||||
node_area_map = EXCLUDED.node_area_map,
|
||||
areas = EXCLUDED.areas,
|
||||
drawing_payload = EXCLUDED.drawing_payload,
|
||||
created_at = NOW();
|
||||
""",
|
||||
(
|
||||
scheme_name,
|
||||
network,
|
||||
run_status,
|
||||
error_message,
|
||||
json.dumps(sensor_nodes),
|
||||
json.dumps(result_rows),
|
||||
json.dumps(node_area_map),
|
||||
json.dumps(areas),
|
||||
json.dumps(drawing_payload or {}),
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
run = _get_run_by_name(name, scheme_name, "dma_leak_identification")
|
||||
if not run:
|
||||
raise LookupError(f"analysis run {scheme_name!r} does not exist")
|
||||
payload = {
|
||||
"network": network,
|
||||
"run_status": run_status,
|
||||
"error_message": error_message,
|
||||
"sensor_nodes": sensor_nodes,
|
||||
"rows": result_rows,
|
||||
"node_area_map": node_area_map,
|
||||
"areas": areas,
|
||||
"drawing_payload": drawing_payload or {},
|
||||
}
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"insert into analysis.results (run_id, result_type, payload) values (%s, 'leakage_identification', %s)",
|
||||
(run["run_id"], Jsonb(payload)),
|
||||
)
|
||||
|
||||
|
||||
def _list_typed_runs(
|
||||
name: str,
|
||||
network: str,
|
||||
run_type: str,
|
||||
query_date: date | None,
|
||||
) -> list[dict[str, Any]]:
|
||||
rows = _list_runs(name, run_type, query_date)
|
||||
return [
|
||||
row
|
||||
for row in rows
|
||||
if not network or row["parameters"].get("network") in (None, network)
|
||||
]
|
||||
|
||||
|
||||
def _typed_run_detail(name: str, run_name: str, run_type: str) -> dict[str, Any]:
|
||||
run = _get_run_by_name(name, run_name, run_type)
|
||||
if not run:
|
||||
return {}
|
||||
with project_connection(name) as conn, conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"select result_type, payload, created_at from analysis.results where run_id = %s order by created_at, result_id",
|
||||
(run["run_id"],),
|
||||
)
|
||||
results = [dict(row) for row in cur.fetchall()]
|
||||
return run | {"results": results}
|
||||
|
||||
|
||||
def query_leakage_identify_schemes(
|
||||
@@ -298,100 +250,12 @@ def query_leakage_identify_schemes(
|
||||
network: str,
|
||||
scheme_type: str = "dma_leak_identification",
|
||||
query_date: date | None = None,
|
||||
) -> list[dict]:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
if query_date is None:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type,),
|
||||
)
|
||||
else:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s AND DATE(create_time) = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type, query_date),
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
result = []
|
||||
for row in rows:
|
||||
detail = row[6] if isinstance(row[6], dict) else {}
|
||||
if network and detail.get("network") not in (None, network):
|
||||
continue
|
||||
result.append(
|
||||
{
|
||||
"scheme_id": row[0],
|
||||
"scheme_name": row[1],
|
||||
"scheme_type": row[2],
|
||||
"username": row[3],
|
||||
"create_time": row[4],
|
||||
"scheme_start_time": row[5],
|
||||
"scheme_detail": detail,
|
||||
}
|
||||
)
|
||||
return result
|
||||
) -> list[dict[str, Any]]:
|
||||
return _list_typed_runs(name, network, scheme_type, query_date)
|
||||
|
||||
|
||||
def query_leakage_identify_scheme_detail(name: str, scheme_name: str) -> dict:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_name = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name,),
|
||||
)
|
||||
base_row = cur.fetchone()
|
||||
if base_row is None:
|
||||
return {}
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT network, created_at, run_status, error_message, sensor_nodes, result_rows, node_area_map, areas, drawing_payload
|
||||
FROM public.leakage_identify_result
|
||||
WHERE scheme_name = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name,),
|
||||
)
|
||||
result_row = cur.fetchone()
|
||||
if result_row is None:
|
||||
return {}
|
||||
return {
|
||||
"scheme_id": base_row[0],
|
||||
"scheme_name": base_row[1],
|
||||
"scheme_type": base_row[2],
|
||||
"username": base_row[3],
|
||||
"create_time": base_row[4],
|
||||
"scheme_start_time": base_row[5],
|
||||
"scheme_detail": base_row[6] if isinstance(base_row[6], dict) else {},
|
||||
"network": result_row[0],
|
||||
"result_created_at": result_row[1],
|
||||
"run_status": result_row[2],
|
||||
"error_message": result_row[3],
|
||||
"sensor_nodes": result_row[4] if isinstance(result_row[4], list) else [],
|
||||
"rows": result_row[5] if isinstance(result_row[5], list) else [],
|
||||
"node_area_map": result_row[6] if isinstance(result_row[6], dict) else {},
|
||||
"areas": result_row[7] if isinstance(result_row[7], list) else [],
|
||||
"drawing_payload": (
|
||||
result_row[8]
|
||||
if isinstance(result_row[8], dict)
|
||||
else {"type": "FeatureCollection", "features": []}
|
||||
),
|
||||
}
|
||||
def query_leakage_identify_scheme_detail(name: str, scheme_name: str) -> dict[str, Any]:
|
||||
return _typed_run_detail(name, scheme_name, "dma_leak_identification")
|
||||
|
||||
|
||||
def query_burst_location_schemes(
|
||||
@@ -399,78 +263,12 @@ def query_burst_location_schemes(
|
||||
network: str,
|
||||
scheme_type: str = "burst_location",
|
||||
query_date: date | None = None,
|
||||
) -> list[dict]:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
if query_date is None:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type,),
|
||||
)
|
||||
else:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s AND DATE(create_time) = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type, query_date),
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
result = []
|
||||
for row in rows:
|
||||
detail = row[6] if isinstance(row[6], dict) else {}
|
||||
if network and detail.get("network") not in (None, network):
|
||||
continue
|
||||
result.append(
|
||||
{
|
||||
"scheme_id": row[0],
|
||||
"scheme_name": row[1],
|
||||
"scheme_type": row[2],
|
||||
"username": row[3],
|
||||
"create_time": row[4],
|
||||
"scheme_start_time": row[5],
|
||||
"scheme_detail": detail,
|
||||
}
|
||||
)
|
||||
return result
|
||||
) -> list[dict[str, Any]]:
|
||||
return _list_typed_runs(name, network, scheme_type, query_date)
|
||||
|
||||
|
||||
def query_burst_location_scheme_detail(name: str, scheme_name: str) -> dict:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_name = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name,),
|
||||
)
|
||||
base_row = cur.fetchone()
|
||||
if base_row is None:
|
||||
return {}
|
||||
detail = base_row[6] if isinstance(base_row[6], dict) else {}
|
||||
return {
|
||||
"scheme_id": base_row[0],
|
||||
"scheme_name": base_row[1],
|
||||
"scheme_type": base_row[2],
|
||||
"username": base_row[3],
|
||||
"create_time": base_row[4],
|
||||
"scheme_start_time": base_row[5],
|
||||
"scheme_detail": detail,
|
||||
"network": detail.get("network"),
|
||||
"result_payload": detail.get("result_payload", {}),
|
||||
}
|
||||
def query_burst_location_scheme_detail(name: str, scheme_name: str) -> dict[str, Any]:
|
||||
return _typed_run_detail(name, scheme_name, "burst_location")
|
||||
|
||||
|
||||
def query_burst_detection_schemes(
|
||||
@@ -478,171 +276,9 @@ def query_burst_detection_schemes(
|
||||
network: str,
|
||||
scheme_type: str = "burst_detection",
|
||||
query_date: date | None = None,
|
||||
) -> list[dict]:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
if query_date is None:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type,),
|
||||
)
|
||||
else:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_type = %s AND DATE(create_time) = %s
|
||||
ORDER BY create_time DESC
|
||||
""",
|
||||
(scheme_type, query_date),
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
result = []
|
||||
for row in rows:
|
||||
detail = row[6] if isinstance(row[6], dict) else {}
|
||||
if network and detail.get("network") not in (None, network):
|
||||
continue
|
||||
result.append(
|
||||
{
|
||||
"scheme_id": row[0],
|
||||
"scheme_name": row[1],
|
||||
"scheme_type": row[2],
|
||||
"username": row[3],
|
||||
"create_time": row[4],
|
||||
"scheme_start_time": row[5],
|
||||
"scheme_detail": detail,
|
||||
}
|
||||
)
|
||||
return result
|
||||
) -> list[dict[str, Any]]:
|
||||
return _list_typed_runs(name, network, scheme_type, query_date)
|
||||
|
||||
|
||||
def query_burst_detection_scheme_detail(name: str, scheme_name: str) -> dict:
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail
|
||||
FROM public.scheme_list
|
||||
WHERE scheme_name = %s
|
||||
LIMIT 1
|
||||
""",
|
||||
(scheme_name,),
|
||||
)
|
||||
base_row = cur.fetchone()
|
||||
if base_row is None:
|
||||
return {}
|
||||
detail = base_row[6] if isinstance(base_row[6], dict) else {}
|
||||
return {
|
||||
"scheme_id": base_row[0],
|
||||
"scheme_name": base_row[1],
|
||||
"scheme_type": base_row[2],
|
||||
"username": base_row[3],
|
||||
"create_time": base_row[4],
|
||||
"scheme_start_time": base_row[5],
|
||||
"scheme_detail": detail,
|
||||
"network": detail.get("network"),
|
||||
"result_payload": detail.get("result_payload", {}),
|
||||
}
|
||||
|
||||
|
||||
# 2025/03/23
|
||||
def upload_shp_to_pg(name: str, table_name: str, role: str, shp_file_path: str):
|
||||
"""
|
||||
将 Shapefile 文件上传到 PostgreSQL 数据库
|
||||
:param name: 项目名称(数据库名称)
|
||||
:param table_name: 创建表的名字
|
||||
:param role: 数据库角色名,位于c盘user中查看
|
||||
:param shp_file_path: shp文件的路径
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
# 动态连接到指定的数据库
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
# 读取 Shapefile 文件
|
||||
gdf = gpd.read_file(shp_file_path)
|
||||
|
||||
# 检查投影坐标系(CRS),并确保是 EPSG:4326
|
||||
if gdf.crs.to_string() != "EPSG:4490":
|
||||
gdf = gdf.to_crs(epsg=4490)
|
||||
|
||||
# 使用 GeoDataFrame 的 .to_postgis 方法将数据写入 PostgreSQL
|
||||
# 需要在数据库中提前安装 PostGIS 扩展
|
||||
engine = create_engine(f"postgresql+psycopg2://{role}:@127.0.0.1/{name}")
|
||||
gdf.to_postgis(
|
||||
table_name, engine, if_exists="replace", index=True, index_label="id"
|
||||
)
|
||||
|
||||
print(
|
||||
f"Shapefile 文件成功上传到 PostgreSQL 数据库 '{name}' 的表 '{table_name}'."
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"上传 Shapefile 到 PostgreSQL 时出错:{e}")
|
||||
|
||||
|
||||
def submit_risk_probability_result(name: str, result_file_path: str) -> None:
|
||||
"""
|
||||
将管网风险评估结果导入pg数据库
|
||||
:param name: 项目名称(数据库名称)
|
||||
:param result_file_path: 结果文件路径
|
||||
:return:
|
||||
"""
|
||||
# 自动检测文件编码
|
||||
# with open({result_file_path}, 'rb') as file:
|
||||
# raw_data = file.read()
|
||||
# detected = chardet.detect(raw_data)
|
||||
# file_encoding = detected['encoding']
|
||||
# print(f"检测到的文件编码:{file_encoding}")
|
||||
|
||||
try:
|
||||
# 动态替换数据库名称
|
||||
conn_string = get_project_pgconn_string(db_name=name)
|
||||
|
||||
# 连接到 PostgreSQL 数据库
|
||||
with psycopg.connect(conn_string) as conn:
|
||||
with conn.cursor() as cur:
|
||||
# 检查 scada_info 表是否为空
|
||||
cur.execute("SELECT COUNT(*) FROM pipe_risk_probability;")
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
if count > 0:
|
||||
print("pipe_risk_probability表中已有数据,正在清空记录...")
|
||||
cur.execute("DELETE FROM pipe_risk_probability;")
|
||||
print("表记录已清空。")
|
||||
|
||||
# 读取Excel并转换x/y列为列表
|
||||
df = pd.read_excel(result_file_path, sheet_name="Sheet1")
|
||||
df["x"] = df["x"].apply(ast.literal_eval)
|
||||
df["y"] = df["y"].apply(ast.literal_eval)
|
||||
|
||||
# 批量插入数据
|
||||
for index, row in df.iterrows():
|
||||
insert_query = """
|
||||
INSERT INTO pipe_risk_probability
|
||||
(pipeID, pipeage, risk_probability_now, x, y)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
"""
|
||||
cur.execute(
|
||||
insert_query,
|
||||
(
|
||||
row["pipeID"],
|
||||
row["pipeage"],
|
||||
row["risk_probability_now"],
|
||||
row["x"], # 直接传递列表
|
||||
row["y"], # 同上
|
||||
),
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
print("风险评估结果导入成功")
|
||||
|
||||
except Exception as e:
|
||||
print(f"导入时出错:{e}")
|
||||
def query_burst_detection_scheme_detail(name: str, scheme_name: str) -> dict[str, Any]:
|
||||
return _typed_run_detail(name, scheme_name, "burst_detection")
|
||||
|
||||
Reference in New Issue
Block a user