fix: 校验报工归属索引唯一性

This commit is contained in:
souplearn 2026-07-25 02:50:06 +08:00
parent c64229ab78
commit 66777fa174

View File

@ -55,6 +55,7 @@ REQUIRED_FOREIGN_KEYS = {
"report_id": ("production_reports", "id", "CASCADE"),
"report_item_id": ("production_report_items", "id", "CASCADE"),
}
IndexMetadata = dict[str, tuple[str, ...] | int]
def quote_identifier(identifier: str) -> str:
@ -102,11 +103,11 @@ def existing_columns(conn) -> dict[str, dict[str, str | None]]:
}
def existing_indexes(conn) -> dict[str, tuple[str, ...]]:
def existing_indexes(conn) -> dict[str, IndexMetadata]:
rows = conn.execute(
text(
"""
SELECT index_name, column_name
SELECT index_name, non_unique, column_name
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = :table_name
@ -115,10 +116,17 @@ def existing_indexes(conn) -> dict[str, tuple[str, ...]]:
),
{"table_name": TABLE_NAME},
).all()
indexes: dict[str, list[str]] = {}
for index_name, column_name in rows:
indexes.setdefault(index_name, []).append(column_name)
return {index_name: tuple(columns) for index_name, columns in indexes.items()}
indexes: dict[str, dict[str, object]] = {}
for index_name, non_unique, column_name in rows:
metadata = indexes.setdefault(index_name, {"columns": [], "non_unique": int(non_unique)})
metadata["columns"].append(column_name)
return {
index_name: {
"columns": tuple(metadata["columns"]),
"non_unique": metadata["non_unique"],
}
for index_name, metadata in indexes.items()
}
def existing_foreign_keys(conn) -> dict[str, tuple[str, str, str]]:
@ -141,9 +149,9 @@ def existing_foreign_keys(conn) -> dict[str, tuple[str, str, str]]:
return {row[0]: (row[1], row[2], row[3]) for row in rows}
def find_equivalent_index(indexes: dict[str, tuple[str, ...]], columns: tuple[str, ...]) -> str | None:
for index_name, index_columns in indexes.items():
if index_name != "PRIMARY" and index_columns == columns:
def find_equivalent_index(indexes: dict[str, IndexMetadata], columns: tuple[str, ...]) -> str | None:
for index_name, metadata in indexes.items():
if index_name != "PRIMARY" and metadata["columns"] == columns and metadata["non_unique"] == 1:
return index_name
return None
@ -179,10 +187,16 @@ def cleanup_duplicate_fk_indexes(conn) -> None:
indexes = existing_indexes(conn)
duplicates = [
index_name
for index_name, columns in indexes.items()
for index_name, metadata in indexes.items()
if (
(columns == ("report_id",) and index_name != "idx_report_allocations_report")
or (columns == ("report_item_id",) and index_name != "idx_report_allocations_item")
metadata["non_unique"] == 1
and (
(metadata["columns"] == ("report_id",) and index_name != "idx_report_allocations_report")
or (
metadata["columns"] == ("report_item_id",)
and index_name != "idx_report_allocations_item"
)
)
)
]
for index_name in duplicates:
@ -300,19 +314,33 @@ def verify_schema(conn) -> None:
raise RuntimeError(f"{TABLE_NAME} missing indexes: {', '.join(missing_indexes)}")
wrong_indexes = [
f"{index_name}({', '.join(indexes[index_name])})"
f"{index_name}({', '.join(indexes[index_name]['columns'])})"
for index_name, columns in REQUIRED_INDEXES.items()
if indexes.get(index_name) != columns
if indexes.get(index_name, {}).get("columns") != columns
]
if wrong_indexes:
raise RuntimeError(f"{TABLE_NAME} incompatible indexes: {', '.join(wrong_indexes)}")
unique_required_indexes = [
index_name
for index_name in REQUIRED_INDEXES
if indexes[index_name]["non_unique"] != 1
]
if unique_required_indexes:
raise RuntimeError(f"{TABLE_NAME} required indexes are unique: {', '.join(unique_required_indexes)}")
duplicate_single_column_indexes = [
index_name
for index_name, columns in indexes.items()
for index_name, metadata in indexes.items()
if (
(columns == ("report_id",) and index_name != "idx_report_allocations_report")
or (columns == ("report_item_id",) and index_name != "idx_report_allocations_item")
metadata["non_unique"] == 1
and (
(metadata["columns"] == ("report_id",) and index_name != "idx_report_allocations_report")
or (
metadata["columns"] == ("report_item_id",)
and index_name != "idx_report_allocations_item"
)
)
)
]
if duplicate_single_column_indexes:
@ -320,6 +348,22 @@ def verify_schema(conn) -> None:
f"{TABLE_NAME} duplicate FK indexes: {', '.join(sorted(duplicate_single_column_indexes))}"
)
unique_single_column_indexes = [
index_name
for index_name, metadata in indexes.items()
if (
metadata["non_unique"] != 1
and (
metadata["columns"] == ("report_id",)
or metadata["columns"] == ("report_item_id",)
)
)
]
if unique_single_column_indexes:
raise RuntimeError(
f"{TABLE_NAME} unique FK indexes are incompatible: {', '.join(sorted(unique_single_column_indexes))}"
)
foreign_keys = existing_foreign_keys(conn)
missing_foreign_keys = [
column