fix: 校验报工归属索引唯一性
This commit is contained in:
parent
c64229ab78
commit
66777fa174
@ -55,6 +55,7 @@ REQUIRED_FOREIGN_KEYS = {
|
|||||||
"report_id": ("production_reports", "id", "CASCADE"),
|
"report_id": ("production_reports", "id", "CASCADE"),
|
||||||
"report_item_id": ("production_report_items", "id", "CASCADE"),
|
"report_item_id": ("production_report_items", "id", "CASCADE"),
|
||||||
}
|
}
|
||||||
|
IndexMetadata = dict[str, tuple[str, ...] | int]
|
||||||
|
|
||||||
|
|
||||||
def quote_identifier(identifier: str) -> str:
|
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(
|
rows = conn.execute(
|
||||||
text(
|
text(
|
||||||
"""
|
"""
|
||||||
SELECT index_name, column_name
|
SELECT index_name, non_unique, column_name
|
||||||
FROM information_schema.statistics
|
FROM information_schema.statistics
|
||||||
WHERE table_schema = DATABASE()
|
WHERE table_schema = DATABASE()
|
||||||
AND table_name = :table_name
|
AND table_name = :table_name
|
||||||
@ -115,10 +116,17 @@ def existing_indexes(conn) -> dict[str, tuple[str, ...]]:
|
|||||||
),
|
),
|
||||||
{"table_name": TABLE_NAME},
|
{"table_name": TABLE_NAME},
|
||||||
).all()
|
).all()
|
||||||
indexes: dict[str, list[str]] = {}
|
indexes: dict[str, dict[str, object]] = {}
|
||||||
for index_name, column_name in rows:
|
for index_name, non_unique, column_name in rows:
|
||||||
indexes.setdefault(index_name, []).append(column_name)
|
metadata = indexes.setdefault(index_name, {"columns": [], "non_unique": int(non_unique)})
|
||||||
return {index_name: tuple(columns) for index_name, columns in indexes.items()}
|
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]]:
|
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}
|
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:
|
def find_equivalent_index(indexes: dict[str, IndexMetadata], columns: tuple[str, ...]) -> str | None:
|
||||||
for index_name, index_columns in indexes.items():
|
for index_name, metadata in indexes.items():
|
||||||
if index_name != "PRIMARY" and index_columns == columns:
|
if index_name != "PRIMARY" and metadata["columns"] == columns and metadata["non_unique"] == 1:
|
||||||
return index_name
|
return index_name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -179,10 +187,16 @@ def cleanup_duplicate_fk_indexes(conn) -> None:
|
|||||||
indexes = existing_indexes(conn)
|
indexes = existing_indexes(conn)
|
||||||
duplicates = [
|
duplicates = [
|
||||||
index_name
|
index_name
|
||||||
for index_name, columns in indexes.items()
|
for index_name, metadata in indexes.items()
|
||||||
if (
|
if (
|
||||||
(columns == ("report_id",) and index_name != "idx_report_allocations_report")
|
metadata["non_unique"] == 1
|
||||||
or (columns == ("report_item_id",) and index_name != "idx_report_allocations_item")
|
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:
|
for index_name in duplicates:
|
||||||
@ -300,19 +314,33 @@ def verify_schema(conn) -> None:
|
|||||||
raise RuntimeError(f"{TABLE_NAME} missing indexes: {', '.join(missing_indexes)}")
|
raise RuntimeError(f"{TABLE_NAME} missing indexes: {', '.join(missing_indexes)}")
|
||||||
|
|
||||||
wrong_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()
|
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:
|
if wrong_indexes:
|
||||||
raise RuntimeError(f"{TABLE_NAME} incompatible indexes: {', '.join(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 = [
|
duplicate_single_column_indexes = [
|
||||||
index_name
|
index_name
|
||||||
for index_name, columns in indexes.items()
|
for index_name, metadata in indexes.items()
|
||||||
if (
|
if (
|
||||||
(columns == ("report_id",) and index_name != "idx_report_allocations_report")
|
metadata["non_unique"] == 1
|
||||||
or (columns == ("report_item_id",) and index_name != "idx_report_allocations_item")
|
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:
|
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))}"
|
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)
|
foreign_keys = existing_foreign_keys(conn)
|
||||||
missing_foreign_keys = [
|
missing_foreign_keys = [
|
||||||
column
|
column
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user