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