fix the enrollement-carryover balance
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 49s
Tests / PHPUnit (push) Successful in 1m21s

This commit is contained in:
root
2026-09-09 21:40:01 -04:00
parent 2d5b151234
commit 36e8ffe56d
12 changed files with 1365 additions and 39 deletions
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
import re
import sys
from collections import defaultdict
from pathlib import Path
# Matches common SQL statements containing a table name.
TABLE_PATTERNS = [
re.compile(
r'^\s*CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"\[]?([^`"\]\s(.]+)',
re.IGNORECASE,
),
re.compile(
r'^\s*INSERT\s+INTO\s+[`"\[]?([^`"\]\s(.]+)',
re.IGNORECASE,
),
re.compile(
r'^\s*UPDATE\s+[`"\[]?([^`"\]\s(.]+)',
re.IGNORECASE,
),
re.compile(
r'^\s*ALTER\s+TABLE\s+[`"\[]?([^`"\]\s(.]+)',
re.IGNORECASE,
),
re.compile(
r'^\s*DELETE\s+FROM\s+[`"\[]?([^`"\]\s(.]+)',
re.IGNORECASE,
),
]
def extract_table_name(line):
"""Return table name if the line starts a recognizable table statement."""
for pattern in TABLE_PATTERNS:
match = pattern.search(line)
if match:
return match.group(1)
return None
def normalize_line(line):
"""
Normalize a line for comparison.
Removes leading/trailing whitespace but otherwise leaves SQL intact.
"""
return line.strip()
def parse_sql_file(filename):
"""
Parse SQL into table -> list of (line_number, original_line).
Once a table-related statement is detected, following lines are associated
with that table until another table statement begins.
"""
tables = defaultdict(list)
current_table = None
with open(filename, "r", encoding="utf-8", errors="replace") as f:
for line_number, line in enumerate(f, start=1):
table = extract_table_name(line)
if table:
current_table = table
if current_table:
cleaned = normalize_line(line)
# Ignore completely blank lines.
if cleaned:
tables[current_table].append(
(line_number, line.rstrip("\n"))
)
return tables
def line_multiset(lines):
"""
Convert lines into:
normalized_line -> list of occurrences
Keeping occurrences means duplicate INSERT rows are handled correctly.
"""
result = defaultdict(list)
for line_number, text in lines:
result[normalize_line(text)].append((line_number, text))
return result
def compare_table(table, lines1, lines2, file1, file2):
data1 = line_multiset(lines1)
data2 = line_multiset(lines2)
all_lines = sorted(set(data1) | set(data2))
only_file1 = []
only_file2 = []
for normalized in all_lines:
occurrences1 = data1.get(normalized, [])
occurrences2 = data2.get(normalized, [])
common_count = min(len(occurrences1), len(occurrences2))
only_file1.extend(occurrences1[common_count:])
only_file2.extend(occurrences2[common_count:])
if not only_file1 and not only_file2:
return False
print()
print("=" * 100)
print(f"TABLE: {table}")
print("=" * 100)
if only_file1:
print(f"\nOnly in {file1}:")
for line_number, text in only_file1:
print(f" Line {line_number}: {text}")
if only_file2:
print(f"\nOnly in {file2}:")
for line_number, text in only_file2:
print(f" Line {line_number}: {text}")
return True
def compare_sql_files(file1, file2):
tables1 = parse_sql_file(file1)
tables2 = parse_sql_file(file2)
all_tables = sorted(set(tables1) | set(tables2))
print(f"Comparing:")
print(f" File 1: {file1}")
print(f" File 2: {file2}")
print()
differences = 0
for table in all_tables:
if table not in tables1:
print()
print("=" * 100)
print(f"TABLE: {table}")
print("=" * 100)
print(f"Table exists only in {file2}")
differences += 1
continue
if table not in tables2:
print()
print("=" * 100)
print(f"TABLE: {table}")
print("=" * 100)
print(f"Table exists only in {file1}")
differences += 1
continue
if compare_table(
table,
tables1[table],
tables2[table],
file1,
file2,
):
differences += 1
print()
print("=" * 100)
if differences == 0:
print("No table differences found.")
else:
print(f"{differences} table(s) contain differences.")
def main():
if len(sys.argv) != 3:
script = Path(sys.argv[0]).name
print(f"Usage: python {script} file1.sql file2.sql")
sys.exit(1)
file1 = sys.argv[1]
file2 = sys.argv[2]
if not Path(file1).is_file():
print(f"File not found: {file1}")
sys.exit(1)
if not Path(file2).is_file():
print(f"File not found: {file2}")
sys.exit(1)
compare_sql_files(file1, file2)
if __name__ == "__main__":
main()