schema: Continue

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2025-02-04 10:27:38 +01:00
commit 173ff0ef5a
2 changed files with 70 additions and 27 deletions

View file

@ -49,6 +49,10 @@ class Schema(abc.ABC): # export
def _access_defining_columns(self): def _access_defining_columns(self):
pass pass
@abc.abstractmethod
def _model_module_search_paths(self) -> list[tuple[str, type]]:
pass
# ------ API to be called # ------ API to be called
def __len__(self): def __len__(self):
@ -99,3 +103,7 @@ class Schema(abc.ABC): # export
def columns(self, table_name: str) -> Iterable[Column]: def columns(self, table_name: str) -> Iterable[Column]:
return self.__tables[table_name].columns return self.__tables[table_name].columns
@property
def model_module_search_paths(self) -> list[tuple[str, type]]:
return self._model_module_search_paths()

View file

@ -4,8 +4,10 @@ from typing import Optional, Iterable, Any # TODO: Need any for many things, as
import abc import abc
from collections import OrderedDict from collections import OrderedDict
from urllib.parse import quote_plus
from ...log import * from ...log import *
from ...misc import load_class
from .ColumnSet import ColumnSet from .ColumnSet import ColumnSet
from .DataType import DataType from .DataType import DataType
@ -32,10 +34,11 @@ class Table(abc.ABC): # export
self.__log_columns: Optional[Iterable[str]] = None self.__log_columns: Optional[Iterable[str]] = None
self.__display_columns: Optional[Iterable[str]] = None self.__display_columns: Optional[Iterable[str]] = None
self.__column_default: Optional[dict[str, Any]] = None self.__column_default: Optional[dict[str, Any]] = None
self.__base_location: Optional[Iterable[str]] = None self.__base_location_rule: Optional[Iterable[str]] = None
self.__location: Optional[Iterable[str]] = None self.__location_rule: Optional[Iterable[str]] = None
self.__row_location: Optional[Iterable[str]] = None self.__row_location_rule: Optional[Iterable[str]] = None
self.__foreign_keys_to_parent_table: Optional[OrderedDict[str, Any]] = None self.__foreign_keys_to_parent_table: Optional[OrderedDict[str, Any]] = None
self.__model_class: Optional[Any] = None
@property @property
def __columns(self) -> OrderedDict[str, Any]: def __columns(self) -> OrderedDict[str, Any]:
@ -101,7 +104,8 @@ class Table(abc.ABC): # export
@abc.abstractmethod @abc.abstractmethod
def _display_columns(self) -> Iterable[str]: def _display_columns(self) -> Iterable[str]:
return self._primary_keys() return None
#return self._primary_keys()
@abc.abstractmethod @abc.abstractmethod
def _nullable_columns(self) -> Iterable[str]: def _nullable_columns(self) -> Iterable[str]:
@ -123,29 +127,31 @@ class Table(abc.ABC): # export
slog(WARNING, f'Returning None model name for table {self.name}') slog(WARNING, f'Returning None model name for table {self.name}')
return None return None
def _model_class(self) -> Optional[Any]: def _model_module_search_paths(self) -> list[tuple[str, type]]:
slog(WARNING, f'Returning None model class for table {self.name}') return self.schema.model_module_search_paths # Fall back to Schema-global default
throw(ERR, "Not implemented")
return None
@abc.abstractmethod @abc.abstractmethod
def _query_name(self) -> str: def _query_name(self) -> str:
return self.__name return 'tbl/' + self.__name
@abc.abstractmethod
def _row_query_name(self) -> str:
return 'row/' + self.__name
# -- common URL schema for all data # -- common URL schema for all data
def _base_location(self) -> Optional[str]: def _base_location_rule(self) -> Optional[str]:
return f'/{self.name}' return f'/{self.name}'
def _location(self) -> Optional[str]: def _location_rule(self) -> Optional[str]:
ret = '' ret = ''
for col in self.__schema.access_defining_columns: for col in self.__schema.access_defining_columns:
if col in self.primary_keys: if col in self.primary_keys:
ret += f'/<{col}>' ret += f'/<{col}>'
ret += '/' + self.base_location ret += self.base_location_rule
return ret return ret
def _row_location(self) -> Optional[str]: def _row_location_rule(self) -> Optional[str]:
ret = self._location() ret = self._location_rule()
if ret is not None: if ret is not None:
for col in self.primary_keys: for col in self.primary_keys:
if col not in self.__schema.access_defining_columns: if col not in self.__schema.access_defining_columns:
@ -185,26 +191,55 @@ class Table(abc.ABC): # export
def model_name(self) -> Optional[str]: def model_name(self) -> Optional[str]:
return self._model_name() return self._model_name()
@property
def model_class(self) -> Any:
if self.__model_class is None:
pattern = r'^' + self.model_name + '$'
for module_path, base_class in self._model_module_search_paths():
ret = load_class(module_path, base_class, class_name_filter=pattern)
if ret is not None:
self.__model_class = ret
break
else:
throw(ERR, f'No model class found for model {self.model_name}')
return self.__model_class
def query_name(self) -> str: def query_name(self) -> str:
return self._query_name() return self._query_name()
@property def row_query_name(self) -> str:
def base_location(self): return self._row_query_name()
if self.__base_location is None:
self.__base_location = self._base_location()
return self.__base_location
@property @property
def location(self): def base_location_rule(self):
if self.__location is None: if self.__base_location_rule is None:
self.__location = self._base_location() self.__base_location_rule = self._base_location_rule()
return self.__location return self.__base_location_rule
@property @property
def row_location(self): def location_rule(self):
if self.__row_location is None: if self.__location_rule is None:
self.__row_location = self._row_location() self.__location_rule = self._location_rule()
return self.__row_location return self.__location_rule
def location(self, *args, **kwargs):
ret = self.location_rule
for token, val in kwargs.items(): # FIXME: Poor man's row location assembly
ret = re.sub(f'<{token}>', quote_plus(quote_plus(str(val))), ret)
return ret
@property
def row_location_rule(self):
if self.__row_location_rule is None:
self.__row_location_rule = self._row_location_rule()
return self.__row_location_rule
def row_location(self, *args, **kwargs):
ret = self.row_location_rule
for col in self.primary_keys:
if col in kwargs: # FIXME: Poor man's row location assembly
ret = re.sub(f'<{col}>', quote_plus(quote_plus(str(kwargs[col]))), ret)
return ret
@property @property
def primary_keys(self) -> Iterable[str]: def primary_keys(self) -> Iterable[str]: