Files
doorman/backend-services/utils/async_db.py
2025-12-10 23:09:05 -05:00

52 lines
1.7 KiB
Python

"""
Async DB helpers that transparently handle Motor (async) and in-memory/PyMongo (sync).
These wrappers detect whether a collection method is coroutine-based and either await it
directly (Motor) or run the sync call in a thread (to avoid blocking the event loop).
"""
from __future__ import annotations
import asyncio
import inspect
from typing import Any
async def db_find_one(collection: Any, query: dict[str, Any]) -> dict[str, Any] | None:
fn = collection.find_one
if inspect.iscoroutinefunction(fn):
return await fn(query)
return await asyncio.to_thread(fn, query)
async def db_insert_one(collection: Any, doc: dict[str, Any]) -> Any:
fn = collection.insert_one
if inspect.iscoroutinefunction(fn):
return await fn(doc)
return await asyncio.to_thread(fn, doc)
async def db_update_one(collection: Any, query: dict[str, Any], update: dict[str, Any]) -> Any:
fn = collection.update_one
if inspect.iscoroutinefunction(fn):
return await fn(query, update)
return await asyncio.to_thread(fn, query, update)
async def db_delete_one(collection: Any, query: dict[str, Any]) -> Any:
fn = collection.delete_one
if inspect.iscoroutinefunction(fn):
return await fn(query)
return await asyncio.to_thread(fn, query)
async def db_find_list(collection: Any, query: dict[str, Any]) -> list[dict[str, Any]]:
find = collection.find
cursor = find(query)
to_list = getattr(cursor, 'to_list', None)
if callable(to_list):
if inspect.iscoroutinefunction(to_list):
return await to_list(length=None)
return await asyncio.to_thread(to_list, None)
return await asyncio.to_thread(lambda: list(cursor))