Plain is headed towards 1.0! Subscribe for development updates →

 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)