Cybersecurity-Projects/PROJECTS/intermediate/siem-dashboard/backend/app/models/Base.py

73 lines
1.9 KiB
Python

"""
©AngelaMos | 2026
Base.py
"""
from typing import Any, Self
from datetime import datetime, UTC
from mongoengine import (
Document,
DateTimeField,
QuerySet,
)
from app.config import settings
from app.core.errors import NotFoundError
class BaseDocument(Document): # type: ignore[misc]
"""
Abstract base with timestamps and common query helpers
"""
meta = {"abstract": True} # noqa: RUF012
created_at = DateTimeField(default = lambda: datetime.now(UTC))
updated_at = DateTimeField(default = lambda: datetime.now(UTC))
def save(self, *args: Any, **kwargs: Any) -> Any:
"""
Auto-update the updated_at timestamp on every save
"""
self.updated_at = datetime.now(UTC)
return super().save(*args, **kwargs)
@classmethod
def get_by_id(cls, doc_id: str) -> Self:
"""
Fetch by ID or raise NotFoundError
"""
doc = cls.objects(id = doc_id).first()
if doc is None:
raise NotFoundError(f"{cls.__name__} not found")
return doc # type: ignore[no-any-return]
@classmethod
def get_or_none(cls, doc_id: str) -> Self | None:
"""
Fetch by ID or return None
"""
return cls.objects(id = doc_id).first() # type: ignore[no-any-return]
@classmethod
def paginate(
cls,
queryset: QuerySet | None = None,
page: int = 1,
per_page: int = settings.DEFAULT_PAGE_SIZE,
) -> dict[str, Any]:
"""
Return a paginated result dict from any queryset
"""
qs = queryset if queryset is not None else cls.objects
total = qs.count()
offset = (page - 1) * per_page
items = list(qs.skip(offset).limit(per_page))
return {
"items": items,
"total": total,
"page": page,
"per_page": per_page,
"pages": (total + per_page - 1) // per_page,
}