# -*- coding: utf-8 -*- from typing import Optional, Iterable, List, Any # TODO: Need any for many things, as I can't figure out how to avoid circular imports from here import abc from collections import OrderedDict from ...log import * from .ColumnSet import ColumnSet from .DataType import DataType from .CompositeForeignKey import CompositeForeignKey from .Column import Column class Table(abc.ABC): # export def __init__(self, schema, name: str): assert(isinstance(name, str)) self.__schema = schema self.__name = name self.__primary_keys: Optional[Iterable[str]] = None self.__unique_constraints: Optional[List[ColumnSet]] = None self.__foreign_key_constraints: Optional[List[CompositeForeignKey]] = None self.___columns: Optional[OrderedDict[str, Any]] = None self.__nullable_columns: Optional[Iterable[str]] = None self.__non_nullable_columns: Optional[Iterable[str]] = None self.__null_insertible_columns: Optional[Iterable[str]] = None self.__not_null_insertible_columns: Optional[Iterable[str]] = None self.__log_columns: Optional[Iterable[str]] = None self.__column_default: Optional[dict[str, Any]] = None def __repr__(self) -> str: return self.__name @property def __columns(self): if self.___columns is None: ret: OrderedDict[str, Any] = OrderedDict() for name in self._column_names(): ret[name] = Column(self, name, self._column_data_type(name)) self.___columns = ret return self.___columns # -- To be reimplemented @abc.abstractmethod def _column_names(self) -> Iterable[str]: pass @abc.abstractmethod def _log_columns(self) -> Iterable[str]: pass @abc.abstractmethod def _column_data_type(self, name) -> DataType: pass @abc.abstractmethod def _primary_keys(self) -> Iterable[str]: pass @abc.abstractmethod def _auto_increment_columns(self) -> Iterable[str]: pass @abc.abstractmethod def _column_default(self, name) -> Any: pass @abc.abstractmethod def _unique_constraints(self) -> List[List[str]]: pass def _model_name(self) -> Optional[str]: slog(WARNING, f'Returning None model name for table {self.name}') return None # -- To be used def column_default(self, name) -> Any: if self.__column_default is None: ret: dict[str, Any] = dict() for name in self.column_names: ret[name] = self._column_default(name) self.__column_default = ret return self.__column_default[name] @property def columns(self): return self.__columns.values() def column(self, name): return self.__columns[name] @property def column_names(self) -> Iterable[str]: return self.__columns.keys() @property def name(self) -> str: return self.__name @property def schema(self): return self.__schema @property def model_name(self) -> Optional[str]: return self._model_name() @property def primary_keys(self) -> Iterable[str]: if self.__primary_keys is None: self.__primary_keys = self._primary_keys() return self.__primary_keys @property def nullable_columns(self) -> Iterable[str]: if self.__nullable_columns is None: self.__nullable_columns = self._nullable_columns() return self.__nullable_columns @property def non_nullable_columns(self) -> Iterable[str]: if self.__non_nullable_columns is None: ret = [] all_cols = self.column_names nullable_columns = self.nullable_columns for col in all_cols: if col not in nullable_columns: ret.append(col) self.__non_nullable_columns = ret return self.__non_nullable_columns @property def null_insertible_columns(self) -> Iterable[str]: if self.__null_insertible_columns is None: ret: list[str] = [] for col in self.__columns.values(): if col.is_null_insertible: ret.append(col.name) self.__null_insertible_columns = ret return self.__null_insertible_columns @property def not_null_insertible_columns(self) -> Iterable[str]: if self.__not_null_insertible_columns is None: ret: list[str] = [] for col in self.__columns.values(): if not col.is_null_insertible: ret.append(col.name) self.__not_null_insertible_columns = ret return self.__not_null_insertible_columns @property def log_columns(self): if self.__log_columns is None: self.__log_columns = self._log_columns() return self.__log_columns @property def auto_increment_columns(self) -> Iterable[str]: return self._auto_increment_columns() @property def unique_constraints(self) -> List[ColumnSet]: if self.__unique_constraints is None: ret: List[ColumnSet] = [] impl = self._unique_constraints() if impl is not None: for columns in impl: ret.append(ColumnSet(columns=columns)) self.__unique_constraints = ret return self.__unique_constraints @property def foreign_key_constraints(self) -> List[CompositeForeignKey]: if self.__foreign_key_constraints is None: ret: List[Any] = [] for composite_key in self.__schema.foreign_key_constraints: if composite_key.child_table == self: ret.append(composite_key) self.__foreign_key_constraints = ret return self.__foreign_key_constraints