1from __future__ import annotations
2
3import os
4import subprocess
5from typing import TYPE_CHECKING, Any
6
7if TYPE_CHECKING:
8 from plain.models.backends.base.base import BaseDatabaseWrapper
9
10
11class BaseDatabaseClient:
12 """Encapsulate backend-specific methods for opening a client shell."""
13
14 # This should be a string representing the name of the executable
15 # (e.g., "psql"). Subclasses must override this.
16 executable_name = None
17
18 def __init__(self, connection: BaseDatabaseWrapper) -> None:
19 # connection is an instance of BaseDatabaseWrapper.
20 self.connection = connection
21
22 @classmethod
23 def settings_to_cmd_args_env(
24 cls, settings_dict: dict[str, Any], parameters: list[str]
25 ) -> tuple[list[str], dict[str, str] | None]:
26 raise NotImplementedError(
27 "subclasses of BaseDatabaseClient must provide a "
28 "settings_to_cmd_args_env() method or override a runshell()."
29 )
30
31 def runshell(self, parameters: list[str]) -> None:
32 args, env = self.settings_to_cmd_args_env(
33 self.connection.settings_dict, parameters
34 )
35 env = {**os.environ, **env} if env else None
36 subprocess.run(args, env=env, check=True)