db.query: Add Query, QueryResult, Queries

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2025-02-02 14:02:21 +01:00
commit 4cc9906055
4 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,4 @@
TOPDIR = ../../../../..
include $(TOPDIR)/make/proj.mk
include $(JWBDIR)/make/py-mod.mk

View file

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
from typing import Any
import abc
from jwutils.log import *
from jwutils.misc import load_classes
from jwutils.Cmds import Cmds
from jwutils.db.DataBase import DataBase
from jwutils.db.query.Query import Query as QueryBase
from jwutils.db.query.QueryResult import QueryResult
from jwutils.db.schema.Schema import Schema
class Queries(abc.ABC): # export
class Query(QueryBase):
def __init__(self: Any, query: QueryBase, name: str, location: str, func: Any):
self.__query = query
self.__func = func
self.__location = location
self.__name = name
# -- implement API
def _run(self, *args, **kwargs) -> QueryResult:
return self.__func(*args, **kwargs)
def _register(self):
raise Exception('Can\'t call register on this object')
def _column_names(self) -> list[str]:
return self.__query.column_names
@property
def name(self):
return self.__name
def __init__(self, db: DataBase) -> None:
assert(isinstance(db, DataBase))
self.__db = db
self.__queries: dict[str, Any] = dict()
def __getitem__(self, name) -> Query:
try:
return self.__queries[name]
except Exception as e:
slog(ERR, f'Failed to retrieve query {name} ({e})')
slog_m(ERR, '\n'.join(self.__queries.keys()))
raise
@property
def db(self) -> DataBase:
return self.__db
@property
def app(self) -> Cmds:
return self.__db.app
def load(self, modules: list[str], cls=QueryBase):
for path in modules:
slog(INFO, f'Loading modules from {path}')
for c in load_classes(path, cls):
c(self).register()
@property
def schema(self) -> Schema:
return self.__db.schema
def add(self, query: QueryBase, query_name: str, location: str, func: Any):
slog(INFO, f'Adding query "{query_name}" on location "{location}"')
assert(isinstance(query_name, str))
assert(isinstance(location, str))
#ret = self.Query(query, func)
ret = self.Query(query, query_name, location, func)
#setattr(ret, 'name', name)
self.__queries[query_name] = ret
self._add(ret)
# To be overriden in case the derived class wants to keep track
def _add(self, query):
pass
# def register(self):
# return self._register()
#
# def query(self, *args, **kwargs):
# return self.app.query(*args, **kwargs)
#
# def pages(self, *args, **kwargs):
# return self.app.pages(*args, **kwargs)
#

View file

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
from typing import Any
import abc
from jwutils.log import *
from jwutils.misc import load_classes
from jwutils.Cmds import Cmds
from jwutils.db.DataBase import DataBase
from jwutils.db.query.QueryResult import QueryResult
#from jwutils.db.query.Queries import Queries
class Query(abc.ABC): # export
def __init__(self, parent: Any) -> None:
self.__parent = parent
# -- pure virtuals
@abc.abstractmethod
def _run(self, *args, **kwargs) -> QueryResult:
raise Exception('Called pure virtual _run()')
@abc.abstractmethod
def _register(self):
raise Exception('Called pure virtual _register()')
@abc.abstractmethod
def _column_names(self) -> list[str]:
raise Exception('Called pure virtual _column()')
# -- used by Queries class
def register(self):
return self._register()
# -- to be used
def _add(self, query_name: str, location: str, func: Any):
return self.__parent.add(self, query_name, location, func)
def run(self, *args, **kwargs) -> QueryResult:
return self._run(*args, **kwargs)
@property
def parent(self):
return self.__parent
@property
def db(self) -> DataBase:
return self.__parent.db
@property
def schema(self):
return self.__parent.db.schema
@property
def app(self) -> Cmds:
return self.__parent.app
@property
def column_names(self) -> list[str]:
return self._column_names()

View file

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
from typing import Any, Union
import abc
from enum import Enum, auto
from jwutils.log import *
from jwutils.Cmds import Cmds
from jwutils.db.DataBase import DataBase
class ResType(Enum): # export
Statement = auto()
Scalars = auto()
One = auto()
First = auto()
Pages = auto()
class QueryResult(abc.ABC): # export
def __init__(self, query: Any) -> None:
self.__query = query
@property
def app(self) -> Cmds:
return self.__query.app
@property
def db(self) -> DataBase:
return self.__query.db
@property
def schema(self):
return self.__query.db.schema
def rows(self) -> list[Any]:
return self._cast(ResType.Scalars)
def pages(self, per_page=20) -> Any:
return self._cast(ResType.Pages, per_page=per_page)
def one(self) -> Any:
return self._cast(ResType.One)
def first(self) -> Any:
return self._cast(ResType.First)
@property
def statement(self) -> Any:
return self._cast(ResType.Statement)
# -- pure virtuals
@abc.abstractmethod
def _cast(self, res_type: ResType, **kwargs) -> Union[Any|list[Any]]:
pass