Coverage for .venv/lib/python3.13/site-packages/litellm/proxy/db/check_migration.py: 9%
58 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
1"""Module for checking differences between Prisma schema and database."""
3import os
4import subprocess
5from typing import Final
7from litellm._logging import verbose_logger
10def extract_sql_commands(diff_output: str) -> list[str]:
11 """
12 Extract SQL commands from the Prisma migrate diff output.
13 Args:
14 diff_output (str): The full output from prisma migrate diff.
15 Returns:
16 List[str]: A list of SQL commands extracted from the diff output.
17 """
18 # Split the output into lines and remove empty lines
19 lines: Final = [line.strip() for line in diff_output.split("\n") if line.strip()]
21 sql_commands: Final = []
22 current_command = ""
23 in_sql_block = False
25 for line in lines:
26 if line.startswith("-- "): # Comment line, likely a table operation description
27 if in_sql_block and current_command:
28 sql_commands.append(current_command.strip())
29 current_command = ""
30 in_sql_block = True
31 elif in_sql_block:
32 if line.endswith(";"):
33 current_command += line
34 sql_commands.append(current_command.strip())
35 current_command = ""
36 in_sql_block = False
37 else:
38 current_command += line + " "
40 # Add any remaining command
41 if current_command:
42 sql_commands.append(current_command.strip())
44 return sql_commands
47def check_prisma_schema_diff_helper(db_url: str) -> tuple[bool, list[str]]:
48 """Checks for differences between current database and Prisma schema.
50 Never raises: a diff that cannot be produced, because the runner is missing,
51 because the command failed, or because it outlived its budget, is reported as
52 "no diff" so boot continues.
54 Returns:
55 A tuple containing:
56 - A boolean indicating if differences were found (True) or not (False).
57 - The SQL commands that would close the diff, empty when there is none.
58 """
59 try:
60 from litellm_proxy_extras.prisma_toolchain import (
61 PRISMA_COMMAND_TIMEOUT_ENV_VAR,
62 prisma_command_timeout,
63 run_prisma,
64 )
65 except ImportError as e:
66 print( # noqa: T201 # boot-time operator output, same channel as this helper's other messages
67 f"Skipping the migration diff: litellm-proxy-extras has no Prisma runner. Error: {e}"
68 )
69 return False, []
71 verbose_logger.debug("Checking for Prisma schema diff...")
72 timeout: Final = prisma_command_timeout()
73 try:
74 result: Final = run_prisma(
75 [
76 "prisma",
77 "migrate",
78 "diff",
79 "--from-url",
80 db_url,
81 "--to-schema-datamodel",
82 "./schema.prisma",
83 "--script",
84 ],
85 timeout=timeout,
86 env=os.environ.copy(),
87 )
89 sql_commands: Final = extract_sql_commands(result.stdout)
91 if sql_commands:
92 print("Changes to DB Schema detected") # noqa: T201
93 print("Required SQL commands:") # noqa: T201
94 for command in sql_commands:
95 print(command) # noqa: T201
96 return True, sql_commands
97 else:
98 return False, []
99 except subprocess.TimeoutExpired:
100 print( # noqa: T201 # boot-time operator output, same channel as this helper's other messages
101 f"Timed out after {timeout}s generating the migration diff. "
102 f"Raise {PRISMA_COMMAND_TIMEOUT_ENV_VAR} if this database needs longer."
103 )
104 return False, []
105 except subprocess.CalledProcessError as e:
106 error_message: Final = f"Failed to generate migration diff. Error: {e.stderr}"
107 print(error_message) # noqa: T201
108 return False, []
111def check_prisma_schema_diff(db_url: str | None = None) -> None:
112 """Main function to run the Prisma schema diff check."""
113 if db_url is None:
114 db_url = os.getenv("DATABASE_URL")
115 if db_url is None:
116 raise Exception("DATABASE_URL not set")
117 has_diff, message = check_prisma_schema_diff_helper(db_url)
118 if has_diff:
119 verbose_logger.exception(
120 "🚨🚨🚨 prisma schema out of sync with db. Consider running these sql_commands to sync the two - %s",
121 message,
122 )