feat: added mysql support

This commit is contained in:
Forden 2020-10-02 14:11:00 +03:00
parent a04efb56dc
commit 305cbf97ee
15 changed files with 89 additions and 52 deletions

2
bot.py
View File

@ -36,7 +36,7 @@ async def init() -> web.Application:
app = web.Application()
subapps: List[str, web.Application] = [
('/health/', web_handlers.health_app),
('/tg/webhooks', web_handlers.tg_updates_app),
('/tg/webhooks/', web_handlers.tg_updates_app),
]
for prefix, subapp in subapps:
subapp['bot'] = bot

View File

@ -1,3 +1,2 @@
from . import db_api
from . import misc
from . import redis
from .db import db_api, redis

View File

@ -1 +1,2 @@
from .mysql import MysqlConnection
from .sqlite import SqliteConnection

View File

@ -0,0 +1 @@
from .storage import MysqlConnection

View File

@ -0,0 +1,83 @@
import asyncio
from typing import Any, Dict, List, Optional, Type, TypeVar, Union
import aiomysql
from loguru import logger
from data import config
from ..basestorage.storage import RawConnection
T = TypeVar("T")
# noinspection DuplicatedCode
class MysqlConnection(RawConnection):
connection_pool = None
@staticmethod
async def __make_request(
sql: str,
params: Union[tuple, List[tuple]] = None,
fetch: bool = False,
mult: bool = False,
retries_count: int = 5
) -> Optional[Union[List[Dict[str, Any]], Dict[str, Any]]]:
if MysqlConnection.connection_pool is None:
MysqlConnection.connection_pool = await aiomysql.create_pool(**config.mysql_info)
async with MysqlConnection.connection_pool.acquire() as conn:
conn: aiomysql.Connection = conn
async with conn.cursor(aiomysql.DictCursor) as cur:
cur: aiomysql.DictCursor = cur
for i in range(retries_count):
try:
if isinstance(params, list):
await cur.executemany(sql, params)
else:
await cur.execute(sql, params)
except (aiomysql.OperationalError, aiomysql.InternalError) as e:
logger.error(f'Found error [{e}] [{sql}] [{params}] retrying [{i}/{retries_count}]')
if 'Deadlock found' in str(e):
await asyncio.sleep(1)
else:
break
if fetch:
if mult:
r = await cur.fetchall()
else:
r = await cur.fetchone()
return r
else:
await conn.commit()
@staticmethod
def _convert_to_model(data: Optional[dict], model: Type[T]) -> Optional[T]:
if data is not None:
return model(**data)
else:
return None
@staticmethod
async def _make_request(
sql: str,
params: Union[tuple, List[tuple]] = None,
fetch: bool = False,
mult: bool = False,
model_type: Type[T] = None
) -> Optional[Union[List[T], T]]:
raw = await MysqlConnection.__make_request(sql, params, fetch, mult)
if raw is None:
if mult:
return []
else:
return None
else:
if mult:
if model_type is not None:
return [MysqlConnection._convert_to_model(i, model_type) for i in raw]
else:
return list(raw)
else:
if model_type is not None:
return MysqlConnection._convert_to_model(raw, model_type)
else:
return raw

View File

View File

@ -1,47 +0,0 @@
import asyncio
from typing import Optional, Dict, Any, Union, List
import aiomysql
from data import config
class RawConnection:
connection_pool = None
@staticmethod
async def _make_request(
sql: str,
params: Union[tuple, List[tuple]] = None,
fetch: bool = False,
mult: bool = False,
retries_count: int = 5
) -> Optional[Union[List[Dict[str, Any]], Dict[str, Any]]]:
if RawConnection.connection_pool is None:
RawConnection.connection_pool = await aiomysql.create_pool(**config.mysql_info)
async with RawConnection.connection_pool.acquire() as conn:
conn: aiomysql.Connection = conn
async with conn.cursor(aiomysql.DictCursor) as cur:
cur: aiomysql.DictCursor = cur
for i in range(retries_count):
try:
if isinstance(params, list):
await cur.executemany(sql, params)
else:
await cur.execute(sql, params)
except aiomysql.OperationalError as e:
if 'Deadlock found' in str(e):
await asyncio.sleep(1)
except aiomysql.InternalError as e:
if 'Deadlock found' in str(e):
await asyncio.sleep(1)
else:
break
if fetch:
if mult:
r = await cur.fetchall()
else:
r = await cur.fetchone()
return r
else:
await conn.commit()

View File

@ -16,4 +16,4 @@ async def execute(req: web.Request) -> web.Response:
return web.Response()
tg_updates_app.add_routes([web.post('/{token}', execute)])
tg_updates_app.add_routes([web.post('/bot/{token}', execute)])