diff --git a/openbookr/db.py b/openbookr/db.py index 30c9fa0..b0b2e15 100644 --- a/openbookr/db.py +++ b/openbookr/db.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from typing import Iterable ################## # DataBase logic # @@ -7,10 +6,135 @@ from typing import Iterable from openbookr.ABC import IDataBase from openbookr.models import Book +from aiosqlite import connect as sqdb, Connection as DB, Cursor +from enum import Enum +from typing import Any, Iterable + + +class DBColumnsTypes(Enum): + """ + Data types for sqlite table columns + """ + + stroke = "TEXT" + integer_number = "INTEGER" + float_number = "FLOAT" class SQLiteEngine(object): - ... + + db: DB + cursor: Cursor + + @staticmethod + def __getcolumns(columns: dict[str, DBColumnsTypes]) -> str: + """ + Converts dictionary to a string for a sqlite query + + :param columns: Dict["column_title": ColumnType] + :return: Part of sqlite query + """ + keys = tuple(columns.keys()) + values = tuple(columns.values()) + lst = zip(keys, values) + lst = [ + f"{column_title.lower()} {column_type.value}" + for column_title, column_type in lst + ] + return ", ".join(lst) + + def __init__(self, db_path: str) -> None: + self.path = db_path + + async def __aenter__(self) -> "SQLiteEngine": + self.db = sqdb(self.path) + self.cursor = await self.db.cursor() + return self + + async def __aexit__(self, exc_type, exc, tb) -> None: + await self.db.commit() + await self.db.close() + + async def _execute(self, request: str, params: Iterable | None = None) -> None: + """ + Executes sqlite query + + :param request: Query text + :param params: Additional parameters for the request + """ + if params is None: + await self.cursor.execute(request) + return + await self.cursor.execute(request, params) + + async def _create_table( + self, table: str, columns: dict[str, DBColumnsTypes] + ) -> None: + """ + Generates table in the database + + :param table: Name of the table + :param columns: Columns in the table + """ + request = f"CREATE TABLE IF NOT EXISTS {table} (id INTEGER PRIMARY KEY, {self.__getcolumns(columns)})" + await self._execute(request) + + async def _insert(self, table: str, items: dict[str, Any]) -> None: + """ + Inserts data into a field of a database table + + :param table: Name of the table + :param items: Dict["column_title": value] + """ + columns = [title.lower() for title in tuple(items.keys())] + columns = ", ".join(columns) + values = list(items.values()) + request = ( + f"INSERT INTO {table} ({columns}) VALUES ({("?, " * len(values))[:-2]})" + ) + await self._execute(request, values) + + async def _get( + self, + table: str, + column: Iterable[str] | None = None, + where: dict | str | None = None, + order: str | None = None, + ) -> Iterable[Any]: + """ + Returns data from sqlite table + + :param table: Name of the table + :param column: List of the columns titles + :param where: Dict['column_title': value] + :param order: sqlite query order syntax stroke + :return: List of values from table + """ + args: list[Any] | None = None + if column is None: + column = "*" + else: + column = ", ".join(i.lower() for i in column) + request: list[Any] = [f"SELECT {column} FROM {table}"] + if isinstance(where, dict): + args = list(where.values()) + where = ( + f"WHERE {", ".join(tuple(where.keys()))} = ({("?, " * len(args))[:-2]})" + ) + request.append(where) + if order is not None: + order = f"ORDER BY {order}" + request.append(order) + request = [" ".join(request)] + if isinstance(args, list): + request.append(args) + await self.cursor.execute(*request) + return await self.cursor.fetchall() + + async def _delete(self, table: str, where: dict[str, Any]) -> None: + values = list(where.values()) + request = f"DELETE FROM {table} WHERE {", ".join(tuple(where.keys()))} = ({("?, " * len(values))[:-2]})" + await self._execute(request, values) class SQlite(IDataBase, SQLiteEngine): diff --git a/requirements.txt b/requirements.txt index a43e6d4..2822438 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +aiosqlite==0.20.0 annotated-types==0.7.0 pydantic==2.8.2 pydantic_core==2.20.1 diff --git a/setup.py b/setup.py index 4e4f19d..78f7560 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,6 @@ setup( author="trueold89", author_email="trueold89@orudo.ru", description="", - install_requires=[], + install_requires=["pydanctic==2.8.2", "aiosqlite==0.20.0"], packages=["openbookr"], )