diff --git a/freenit/__init__.py b/freenit/__init__.py index 0af2a4a..90c13ab 100644 --- a/freenit/__init__.py +++ b/freenit/__init__.py @@ -1 +1 @@ -__version__ = "0.3.25" +__version__ = "0.3.26" diff --git a/freenit/api/__init__.py b/freenit/api/__init__.py index bf90b88..b787b48 100644 --- a/freenit/api/__init__.py +++ b/freenit/api/__init__.py @@ -5,6 +5,7 @@ import freenit.api.mail import freenit.api.mailinglist import freenit.api.omemo +import freenit.api.project import freenit.api.role import freenit.api.sieve import freenit.api.theme diff --git a/freenit/api/project.py b/freenit/api/project.py new file mode 100644 index 0000000..fa64686 --- /dev/null +++ b/freenit/api/project.py @@ -0,0 +1,483 @@ +from datetime import datetime + +import oxyde +import pydantic +from fastapi import Depends, Header, HTTPException + +from freenit.api.router import route +from freenit.decorators import description +from freenit.models.pagination import Page, paginate +from freenit.models.project import ( + Board, + BoardOptional, + Column, + ColumnOptional, + Project, + ProjectOptional, + Task, + TaskOptional, +) +from freenit.models.user import User +from freenit.permissions import project_perms + +tags = ["project"] + + +# --------------------------------------------------------------------------- +# Request / response schemas +# --------------------------------------------------------------------------- + + +class ProjectCreate(pydantic.BaseModel): + name: str + description: str | None = None + + +class ProjectResponse(pydantic.BaseModel): + model_config = pydantic.ConfigDict(from_attributes=True) + + id: int + name: str + description: str | None = None + created_by_id: int | None = None + created_at: datetime | None = None + updated_at: datetime | None = None + + +class BoardCreate(pydantic.BaseModel): + name: str + description: str | None = None + + +class BoardResponse(pydantic.BaseModel): + model_config = pydantic.ConfigDict(from_attributes=True) + + id: int + project_id: int + name: str + description: str | None = None + created_at: datetime | None = None + updated_at: datetime | None = None + + +class ColumnCreate(pydantic.BaseModel): + name: str + position: int | None = None + + +class ColumnResponse(pydantic.BaseModel): + model_config = pydantic.ConfigDict(from_attributes=True) + + id: int + board_id: int + name: str + position: int + created_at: datetime | None = None + updated_at: datetime | None = None + + +class TaskCreate(pydantic.BaseModel): + title: str + description: str | None = None + position: int | None = None + assignee_id: int | None = None + parent_id: int | None = None + + +class TaskResponse(pydantic.BaseModel): + model_config = pydantic.ConfigDict(from_attributes=True) + + id: int + column_id: int + title: str + description: str | None = None + position: int + assignee_id: int | None = None + parent_id: int | None = None + created_at: datetime | None = None + updated_at: datetime | None = None + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +async def _get_project(id: int) -> Project: + try: + return await Project.objects.get(id=id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such project") + + +async def _get_board(id: int) -> Board: + try: + return await Board.objects.get(id=id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such board") + + +async def _get_column(id: int) -> Column: + try: + return await Column.objects.get(id=id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such column") + + +async def _get_task(id: int) -> Task: + try: + return await Task.objects.get(id=id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such task") + + +async def _next_position(model, filter_kwargs: dict) -> int: + """Return the next available position for a child model query.""" + existing = await model.objects.filter(**filter_kwargs).all() + if not existing: + return 0 + return max((getattr(item, "position", 0) for item in existing), default=0) + 1 + + +async def _validate_assignee(assignee_id: int | None) -> None: + if assignee_id is None: + return + if User.dbtype() != "sql": + raise HTTPException( + status_code=400, + detail="Task assignment is not supported with LDAP users", + ) + try: + await User.objects.get(id=assignee_id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such assignee") + + +async def _validate_parent(parent_id: int | None, task_id: int | None = None) -> None: + if parent_id is None: + return + if task_id is not None and parent_id == task_id: + raise HTTPException(status_code=400, detail="Task cannot be its own parent") + try: + await Task.objects.get(id=parent_id) + except oxyde.NotFoundError: + raise HTTPException(status_code=404, detail="No such parent task") + + +async def _check_project_name_unique(name: str, exclude_id: int | None = None) -> None: + existing = await Project.objects.filter(name=name).all() + if any(item.id != exclude_id for item in existing): + raise HTTPException(status_code=409, detail="Project name already exists") + + +async def _check_board_name_unique( + project_id: int, name: str, exclude_id: int | None = None +) -> None: + existing = await Board.objects.filter(project_id=project_id, name=name).all() + if any(item.id != exclude_id for item in existing): + raise HTTPException( + status_code=409, detail="Board name already exists in this project" + ) + + +async def _check_column_name_unique( + board_id: int, name: str, exclude_id: int | None = None +) -> None: + existing = await Column.objects.filter(board_id=board_id, name=name).all() + if any(item.id != exclude_id for item in existing): + raise HTTPException( + status_code=409, detail="Column name already exists in this board" + ) + + +# --------------------------------------------------------------------------- +# Projects +# --------------------------------------------------------------------------- + + +@route("/projects", tags=tags) +class ProjectListAPI: + @staticmethod + @description("Get projects") + async def get( + page: int = Header(default=1), + perpage: int = Header(default=10), + _: User = Depends(project_perms), + ) -> Page[ProjectResponse]: + return await paginate(Project.objects, page, perpage) + + @staticmethod + @description("Create project") + async def post( + data: ProjectCreate, + user: User = Depends(project_perms), + ) -> ProjectResponse: + await _check_project_name_unique(data.name) + now = datetime.utcnow() + project = await Project.objects.create( + name=data.name, + description=data.description, + created_by_id=getattr(user, "id", None), + created_at=now, + updated_at=now, + ) + return ProjectResponse.model_validate(project) + + +@route("/projects/{id}", tags=tags) +class ProjectDetailAPI: + @staticmethod + async def get(id: int, _: User = Depends(project_perms)) -> ProjectResponse: + project = await _get_project(id) + return ProjectResponse.model_validate(project) + + @staticmethod + async def patch( + id: int, + data: ProjectOptional, + _: User = Depends(project_perms), + ) -> ProjectResponse: + project = await _get_project(id) + if data.name: + await _check_project_name_unique(data.name, exclude_id=id) + await project.patch(data) + return ProjectResponse.model_validate(project) + + @staticmethod + async def delete(id: int, _: User = Depends(project_perms)) -> ProjectResponse: + project = await _get_project(id) + await project.delete() + return ProjectResponse.model_validate(project) + + +# --------------------------------------------------------------------------- +# Boards +# --------------------------------------------------------------------------- + + +@route("/projects/{project_id}/boards", tags=tags) +class ProjectBoardListAPI: + @staticmethod + @description("Get project boards") + async def get( + project_id: int, + page: int = Header(default=1), + perpage: int = Header(default=10), + _: User = Depends(project_perms), + ) -> Page[BoardResponse]: + await _get_project(project_id) + return await paginate( + Board.objects.filter(project_id=project_id), + page, + perpage, + ) + + @staticmethod + @description("Create board") + async def post( + project_id: int, + data: BoardCreate, + _: User = Depends(project_perms), + ) -> BoardResponse: + await _get_project(project_id) + await _check_board_name_unique(project_id, data.name) + now = datetime.utcnow() + board = await Board.objects.create( + project_id=project_id, + name=data.name, + description=data.description, + created_at=now, + updated_at=now, + ) + return BoardResponse.model_validate(board) + + +@route("/boards/{id}", tags=tags) +class BoardDetailAPI: + @staticmethod + async def get(id: int, _: User = Depends(project_perms)) -> BoardResponse: + board = await _get_board(id) + return BoardResponse.model_validate(board) + + @staticmethod + async def patch( + id: int, + data: BoardOptional, + _: User = Depends(project_perms), + ) -> BoardResponse: + board = await _get_board(id) + if data.name: + await _check_board_name_unique(board.project_id, data.name, exclude_id=id) + await board.patch(data) + return BoardResponse.model_validate(board) + + @staticmethod + async def delete(id: int, _: User = Depends(project_perms)) -> BoardResponse: + board = await _get_board(id) + await board.delete() + return BoardResponse.model_validate(board) + + +# --------------------------------------------------------------------------- +# Columns +# --------------------------------------------------------------------------- + + +@route("/boards/{board_id}/columns", tags=tags) +class BoardColumnListAPI: + @staticmethod + @description("Get board columns") + async def get( + board_id: int, + page: int = Header(default=1), + perpage: int = Header(default=10), + _: User = Depends(project_perms), + ) -> Page[ColumnResponse]: + await _get_board(board_id) + return await paginate( + Column.objects.filter(board_id=board_id).order_by("position"), + page, + perpage, + ) + + @staticmethod + @description("Create column") + async def post( + board_id: int, + data: ColumnCreate, + _: User = Depends(project_perms), + ) -> ColumnResponse: + await _get_board(board_id) + await _check_column_name_unique(board_id, data.name) + position = data.position + if position is None: + position = await _next_position(Column, {"board_id": board_id}) + now = datetime.utcnow() + column = await Column.objects.create( + board_id=board_id, + name=data.name, + position=position, + created_at=now, + updated_at=now, + ) + return ColumnResponse.model_validate(column) + + +@route("/columns/{id}", tags=tags) +class ColumnDetailAPI: + @staticmethod + async def get(id: int, _: User = Depends(project_perms)) -> ColumnResponse: + column = await _get_column(id) + return ColumnResponse.model_validate(column) + + @staticmethod + async def patch( + id: int, + data: ColumnOptional, + _: User = Depends(project_perms), + ) -> ColumnResponse: + column = await _get_column(id) + if data.name: + await _check_column_name_unique(column.board_id, data.name, exclude_id=id) + await column.patch(data) + return ColumnResponse.model_validate(column) + + @staticmethod + async def delete(id: int, _: User = Depends(project_perms)) -> ColumnResponse: + column = await _get_column(id) + await column.delete() + return ColumnResponse.model_validate(column) + + +# --------------------------------------------------------------------------- +# Tasks +# --------------------------------------------------------------------------- + + +@route("/columns/{column_id}/tasks", tags=tags) +class ColumnTaskListAPI: + @staticmethod + @description("Get column tasks") + async def get( + column_id: int, + page: int = Header(default=1), + perpage: int = Header(default=10), + _: User = Depends(project_perms), + ) -> Page[TaskResponse]: + await _get_column(column_id) + return await paginate( + Task.objects.filter(column_id=column_id).order_by("position"), + page, + perpage, + ) + + @staticmethod + @description("Create task") + async def post( + column_id: int, + data: TaskCreate, + _: User = Depends(project_perms), + ) -> TaskResponse: + await _get_column(column_id) + await _validate_assignee(data.assignee_id) + await _validate_parent(data.parent_id) + position = data.position + if position is None: + position = await _next_position(Task, {"column_id": column_id}) + now = datetime.utcnow() + task = await Task.objects.create( + column_id=column_id, + title=data.title, + description=data.description, + position=position, + assignee_id=data.assignee_id, + parent_id=data.parent_id, + created_at=now, + updated_at=now, + ) + return TaskResponse.model_validate(task) + + +@route("/tasks/{id}", tags=tags) +class TaskDetailAPI: + @staticmethod + async def get(id: int, _: User = Depends(project_perms)) -> TaskResponse: + task = await _get_task(id) + return TaskResponse.model_validate(task) + + @staticmethod + async def patch( + id: int, + data: TaskOptional, + _: User = Depends(project_perms), + ) -> TaskResponse: + task = await _get_task(id) + update = data.model_dump(exclude_none=True) + + if "column_id" in update: + await _get_column(update["column_id"]) + task.column_id = update.pop("column_id") + + if "assignee_id" in update: + await _validate_assignee(update["assignee_id"]) + task.assignee_id = update.pop("assignee_id") + + if "parent_id" in update: + await _validate_parent(update["parent_id"], task_id=id) + task.parent_id = update.pop("parent_id") + + for key, value in update.items(): + setattr(task, key, value) + + task.updated_at = datetime.utcnow() + await task.save( + update_fields=set(update.keys()) + | {"column_id", "assignee_id", "parent_id", "updated_at"} + ) + return TaskResponse.model_validate(task) + + @staticmethod + async def delete(id: int, _: User = Depends(project_perms)) -> TaskResponse: + task = await _get_task(id) + await task.delete() + return TaskResponse.model_validate(task) diff --git a/freenit/base_config.py b/freenit/base_config.py index f6f854d..4b0c9dd 100644 --- a/freenit/base_config.py +++ b/freenit/base_config.py @@ -140,6 +140,7 @@ class BaseConfig: role = "freenit.models.sql.role" theme = "freenit.models.sql.theme" mailinglist = "freenit.models.sql.mailinglist" + project = "freenit.models.sql.project" theme_name = "Freenit" meta = None auth = Auth() diff --git a/freenit/models/project.py b/freenit/models/project.py new file mode 100644 index 0000000..f6be4e3 --- /dev/null +++ b/freenit/models/project.py @@ -0,0 +1,15 @@ +from freenit.config import getConfig + +config = getConfig() +project = config.get_model("project") + +Project = project.Project +Board = project.Board +Column = project.Column +Task = project.Task +ProjectOptional = project.ProjectOptional +BoardOptional = project.BoardOptional +ColumnOptional = project.ColumnOptional +TaskOptional = project.TaskOptional +NotFoundError = project.NotFoundError +IntegrityError = project.IntegrityError diff --git a/freenit/models/sql/base.pyi b/freenit/models/sql/base.pyi index 56dc07c..5c1a8c1 100644 --- a/freenit/models/sql/base.pyi +++ b/freenit/models/sql/base.pyi @@ -10,9 +10,7 @@ from oxyde import Model from oxyde.queries import Query, QueryManager from __future__ import annotations -from datetime import datetime from typing import ClassVar -from uuid import uuid4 import oxyde import pydantic from fastapi import HTTPException @@ -2707,2310 +2705,3 @@ class ThemeManager(QueryManager[Theme]): """Bulk update objects.""" ... - -class MailingList(Model): - class Meta: - is_table: bool - table_name: str - id: int | None - name: str - address: EmailStr - distribution_address: EmailStr - archive_address: EmailStr - description: str | None - public: bool - archive_enabled: bool - moderation_enabled: bool - principal_id: int | None - inbox_principal_id: int | None - archive_principal_id: int | None - created_at: datetime | None - updated_at: datetime | None - objects: ClassVar["MailingListManager"] - - -class MailingListQuery(Query[MailingList]): - """Type-safe Query for MailingList model.""" - - # Query building methods (sync, return Query) - - def filter( - self, - *args: Any, - address: EmailStr | None = None, - address__in: list[EmailStr] | None = None, - address__isnull: bool | None = None, - archive_address: EmailStr | None = None, - archive_address__in: list[EmailStr] | None = None, - archive_address__isnull: bool | None = None, - archive_enabled: bool | None = None, - archive_enabled__in: list[bool] | None = None, - archive_enabled__isnull: bool | None = None, - archive_principal_id: int | None = None, - archive_principal_id__gt: int | None = None, - archive_principal_id__gte: int | None = None, - archive_principal_id__lt: int | None = None, - archive_principal_id__lte: int | None = None, - archive_principal_id__between: tuple[int, int] | None = None, - archive_principal_id__range: int | None = None, - archive_principal_id__in: list[int] | None = None, - archive_principal_id__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - description: str | None = None, - description__contains: str | None = None, - description__icontains: str | None = None, - description__startswith: str | None = None, - description__istartswith: str | None = None, - description__endswith: str | None = None, - description__iendswith: str | None = None, - description__iexact: str | None = None, - description__in: list[str] | None = None, - description__isnull: bool | None = None, - distribution_address: EmailStr | None = None, - distribution_address__in: list[EmailStr] | None = None, - distribution_address__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - inbox_principal_id: int | None = None, - inbox_principal_id__gt: int | None = None, - inbox_principal_id__gte: int | None = None, - inbox_principal_id__lt: int | None = None, - inbox_principal_id__lte: int | None = None, - inbox_principal_id__between: tuple[int, int] | None = None, - inbox_principal_id__range: int | None = None, - inbox_principal_id__in: list[int] | None = None, - inbox_principal_id__isnull: bool | None = None, - moderation_enabled: bool | None = None, - moderation_enabled__in: list[bool] | None = None, - moderation_enabled__isnull: bool | None = None, - name: str | None = None, - name__contains: str | None = None, - name__icontains: str | None = None, - name__startswith: str | None = None, - name__istartswith: str | None = None, - name__endswith: str | None = None, - name__iendswith: str | None = None, - name__iexact: str | None = None, - name__in: list[str] | None = None, - name__isnull: bool | None = None, - principal_id: int | None = None, - principal_id__gt: int | None = None, - principal_id__gte: int | None = None, - principal_id__lt: int | None = None, - principal_id__lte: int | None = None, - principal_id__between: tuple[int, int] | None = None, - principal_id__range: int | None = None, - principal_id__in: list[int] | None = None, - principal_id__isnull: bool | None = None, - public: bool | None = None, - public__in: list[bool] | None = None, - public__isnull: bool | None = None, - updated_at: datetime | None = None, - updated_at__gt: datetime | None = None, - updated_at__gte: datetime | None = None, - updated_at__lt: datetime | None = None, - updated_at__lte: datetime | None = None, - updated_at__between: tuple[datetime, datetime] | None = None, - updated_at__range: datetime | None = None, - updated_at__year: int | None = None, - updated_at__month: int | None = None, - updated_at__day: int | None = None, - updated_at__in: list[datetime] | None = None, - updated_at__isnull: bool | None = None, - ) -> "MailingListQuery": - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - address: EmailStr | None = None, - address__in: list[EmailStr] | None = None, - address__isnull: bool | None = None, - archive_address: EmailStr | None = None, - archive_address__in: list[EmailStr] | None = None, - archive_address__isnull: bool | None = None, - archive_enabled: bool | None = None, - archive_enabled__in: list[bool] | None = None, - archive_enabled__isnull: bool | None = None, - archive_principal_id: int | None = None, - archive_principal_id__gt: int | None = None, - archive_principal_id__gte: int | None = None, - archive_principal_id__lt: int | None = None, - archive_principal_id__lte: int | None = None, - archive_principal_id__between: tuple[int, int] | None = None, - archive_principal_id__range: int | None = None, - archive_principal_id__in: list[int] | None = None, - archive_principal_id__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - description: str | None = None, - description__contains: str | None = None, - description__icontains: str | None = None, - description__startswith: str | None = None, - description__istartswith: str | None = None, - description__endswith: str | None = None, - description__iendswith: str | None = None, - description__iexact: str | None = None, - description__in: list[str] | None = None, - description__isnull: bool | None = None, - distribution_address: EmailStr | None = None, - distribution_address__in: list[EmailStr] | None = None, - distribution_address__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - inbox_principal_id: int | None = None, - inbox_principal_id__gt: int | None = None, - inbox_principal_id__gte: int | None = None, - inbox_principal_id__lt: int | None = None, - inbox_principal_id__lte: int | None = None, - inbox_principal_id__between: tuple[int, int] | None = None, - inbox_principal_id__range: int | None = None, - inbox_principal_id__in: list[int] | None = None, - inbox_principal_id__isnull: bool | None = None, - moderation_enabled: bool | None = None, - moderation_enabled__in: list[bool] | None = None, - moderation_enabled__isnull: bool | None = None, - name: str | None = None, - name__contains: str | None = None, - name__icontains: str | None = None, - name__startswith: str | None = None, - name__istartswith: str | None = None, - name__endswith: str | None = None, - name__iendswith: str | None = None, - name__iexact: str | None = None, - name__in: list[str] | None = None, - name__isnull: bool | None = None, - principal_id: int | None = None, - principal_id__gt: int | None = None, - principal_id__gte: int | None = None, - principal_id__lt: int | None = None, - principal_id__lte: int | None = None, - principal_id__between: tuple[int, int] | None = None, - principal_id__range: int | None = None, - principal_id__in: list[int] | None = None, - principal_id__isnull: bool | None = None, - public: bool | None = None, - public__in: list[bool] | None = None, - public__isnull: bool | None = None, - updated_at: datetime | None = None, - updated_at__gt: datetime | None = None, - updated_at__gte: datetime | None = None, - updated_at__lt: datetime | None = None, - updated_at__lte: datetime | None = None, - updated_at__between: tuple[datetime, datetime] | None = None, - updated_at__range: datetime | None = None, - updated_at__year: int | None = None, - updated_at__month: int | None = None, - updated_at__day: int | None = None, - updated_at__in: list[datetime] | None = None, - updated_at__isnull: bool | None = None, - ) -> "MailingListQuery": - """Exclude objects matching field lookups.""" - ... - - def order_by(self, *fields: Literal["address", "-address", "archive_address", "-archive_address", "archive_enabled", "-archive_enabled", "archive_principal_id", "-archive_principal_id", "created_at", "-created_at", "description", "-description", "distribution_address", "-distribution_address", "id", "-id", "inbox_principal_id", "-inbox_principal_id", "moderation_enabled", "-moderation_enabled", "name", "-name", "principal_id", "-principal_id", "public", "-public", "updated_at", "-updated_at"]) -> "MailingListQuery": # type: ignore[override] - """Order results by fields.""" - ... - - def limit(self, n: int) -> "MailingListQuery": - """Limit number of results.""" - ... - - def offset(self, n: int) -> "MailingListQuery": - """Skip first n results.""" - ... - - def distinct(self, value: bool = True) -> "MailingListQuery": - """Return distinct results.""" - ... - - def select(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] - """Select specific fields.""" - ... - - def join(self, *paths: str) -> "MailingListQuery": - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> "MailingListQuery": - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> "MailingListQuery": - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> "MailingListQuery": - """Add FOR SHARE lock to query.""" - ... - - def annotate(self, **annotations: Any) -> "MailingListQuery": - """Add computed fields using aggregate functions.""" - ... - - def group_by(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] - """Add GROUP BY clause.""" - ... - - def having(self, *q_exprs: Any, **kwargs: Any) -> "MailingListQuery": - """Add HAVING clause for filtering grouped results.""" - ... - - def values(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"], flat: bool = False) -> "MailingListQuery": # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - # Terminal methods (async, execute query) - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> list[MailingList]: - """Execute query and return all results.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> MailingList | None: - """Execute query and return first result.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> MailingList | None: - """Execute query and return last result.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count matching objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def update( # type: ignore[override] - self, - *, - client: Any | None = None, - using: str | None = None, - **values: Any, - ) -> int: - """Update matching objects.""" - ... - - async def increment( - self, - field: str, - by: int | float = 1, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Atomically increment a field value.""" - ... - - async def delete( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Delete matching objects.""" - ... - -class MailingListManager(QueryManager[MailingList]): - """Type-safe Manager for MailingList model.""" - - # Query building methods (sync, return Query) - - def query(self) -> MailingListQuery: - """Return a Query builder for this model.""" - ... - - def filter( - self, - *args: Any, - address: EmailStr | None = None, - address__in: list[EmailStr] | None = None, - address__isnull: bool | None = None, - archive_address: EmailStr | None = None, - archive_address__in: list[EmailStr] | None = None, - archive_address__isnull: bool | None = None, - archive_enabled: bool | None = None, - archive_enabled__in: list[bool] | None = None, - archive_enabled__isnull: bool | None = None, - archive_principal_id: int | None = None, - archive_principal_id__gt: int | None = None, - archive_principal_id__gte: int | None = None, - archive_principal_id__lt: int | None = None, - archive_principal_id__lte: int | None = None, - archive_principal_id__between: tuple[int, int] | None = None, - archive_principal_id__range: int | None = None, - archive_principal_id__in: list[int] | None = None, - archive_principal_id__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - description: str | None = None, - description__contains: str | None = None, - description__icontains: str | None = None, - description__startswith: str | None = None, - description__istartswith: str | None = None, - description__endswith: str | None = None, - description__iendswith: str | None = None, - description__iexact: str | None = None, - description__in: list[str] | None = None, - description__isnull: bool | None = None, - distribution_address: EmailStr | None = None, - distribution_address__in: list[EmailStr] | None = None, - distribution_address__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - inbox_principal_id: int | None = None, - inbox_principal_id__gt: int | None = None, - inbox_principal_id__gte: int | None = None, - inbox_principal_id__lt: int | None = None, - inbox_principal_id__lte: int | None = None, - inbox_principal_id__between: tuple[int, int] | None = None, - inbox_principal_id__range: int | None = None, - inbox_principal_id__in: list[int] | None = None, - inbox_principal_id__isnull: bool | None = None, - moderation_enabled: bool | None = None, - moderation_enabled__in: list[bool] | None = None, - moderation_enabled__isnull: bool | None = None, - name: str | None = None, - name__contains: str | None = None, - name__icontains: str | None = None, - name__startswith: str | None = None, - name__istartswith: str | None = None, - name__endswith: str | None = None, - name__iendswith: str | None = None, - name__iexact: str | None = None, - name__in: list[str] | None = None, - name__isnull: bool | None = None, - principal_id: int | None = None, - principal_id__gt: int | None = None, - principal_id__gte: int | None = None, - principal_id__lt: int | None = None, - principal_id__lte: int | None = None, - principal_id__between: tuple[int, int] | None = None, - principal_id__range: int | None = None, - principal_id__in: list[int] | None = None, - principal_id__isnull: bool | None = None, - public: bool | None = None, - public__in: list[bool] | None = None, - public__isnull: bool | None = None, - updated_at: datetime | None = None, - updated_at__gt: datetime | None = None, - updated_at__gte: datetime | None = None, - updated_at__lt: datetime | None = None, - updated_at__lte: datetime | None = None, - updated_at__between: tuple[datetime, datetime] | None = None, - updated_at__range: datetime | None = None, - updated_at__year: int | None = None, - updated_at__month: int | None = None, - updated_at__day: int | None = None, - updated_at__in: list[datetime] | None = None, - updated_at__isnull: bool | None = None, - ) -> MailingListQuery: - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - address: EmailStr | None = None, - address__in: list[EmailStr] | None = None, - address__isnull: bool | None = None, - archive_address: EmailStr | None = None, - archive_address__in: list[EmailStr] | None = None, - archive_address__isnull: bool | None = None, - archive_enabled: bool | None = None, - archive_enabled__in: list[bool] | None = None, - archive_enabled__isnull: bool | None = None, - archive_principal_id: int | None = None, - archive_principal_id__gt: int | None = None, - archive_principal_id__gte: int | None = None, - archive_principal_id__lt: int | None = None, - archive_principal_id__lte: int | None = None, - archive_principal_id__between: tuple[int, int] | None = None, - archive_principal_id__range: int | None = None, - archive_principal_id__in: list[int] | None = None, - archive_principal_id__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - description: str | None = None, - description__contains: str | None = None, - description__icontains: str | None = None, - description__startswith: str | None = None, - description__istartswith: str | None = None, - description__endswith: str | None = None, - description__iendswith: str | None = None, - description__iexact: str | None = None, - description__in: list[str] | None = None, - description__isnull: bool | None = None, - distribution_address: EmailStr | None = None, - distribution_address__in: list[EmailStr] | None = None, - distribution_address__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - inbox_principal_id: int | None = None, - inbox_principal_id__gt: int | None = None, - inbox_principal_id__gte: int | None = None, - inbox_principal_id__lt: int | None = None, - inbox_principal_id__lte: int | None = None, - inbox_principal_id__between: tuple[int, int] | None = None, - inbox_principal_id__range: int | None = None, - inbox_principal_id__in: list[int] | None = None, - inbox_principal_id__isnull: bool | None = None, - moderation_enabled: bool | None = None, - moderation_enabled__in: list[bool] | None = None, - moderation_enabled__isnull: bool | None = None, - name: str | None = None, - name__contains: str | None = None, - name__icontains: str | None = None, - name__startswith: str | None = None, - name__istartswith: str | None = None, - name__endswith: str | None = None, - name__iendswith: str | None = None, - name__iexact: str | None = None, - name__in: list[str] | None = None, - name__isnull: bool | None = None, - principal_id: int | None = None, - principal_id__gt: int | None = None, - principal_id__gte: int | None = None, - principal_id__lt: int | None = None, - principal_id__lte: int | None = None, - principal_id__between: tuple[int, int] | None = None, - principal_id__range: int | None = None, - principal_id__in: list[int] | None = None, - principal_id__isnull: bool | None = None, - public: bool | None = None, - public__in: list[bool] | None = None, - public__isnull: bool | None = None, - updated_at: datetime | None = None, - updated_at__gt: datetime | None = None, - updated_at__gte: datetime | None = None, - updated_at__lt: datetime | None = None, - updated_at__lte: datetime | None = None, - updated_at__between: tuple[datetime, datetime] | None = None, - updated_at__range: datetime | None = None, - updated_at__year: int | None = None, - updated_at__month: int | None = None, - updated_at__day: int | None = None, - updated_at__in: list[datetime] | None = None, - updated_at__isnull: bool | None = None, - ) -> MailingListQuery: - """Exclude objects matching field lookups.""" - ... - - def values(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> MailingListQuery: # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"], flat: bool = False) -> MailingListQuery: # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - def distinct(self, distinct: bool = True) -> MailingListQuery: - """Return distinct results.""" - ... - - def join(self, *paths: str) -> MailingListQuery: - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> MailingListQuery: - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> MailingListQuery: - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> MailingListQuery: - """Add FOR SHARE lock to query.""" - ... - - # Terminal methods (async, execute query) - - async def get( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> MailingList: - """Get single object matching lookups.""" - ... - - async def get_or_none( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> MailingList | None: - """Get object or None if not found.""" - ... - - async def get_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[MailingList, bool]: - """Get object or create if not found. Returns (object, created).""" - ... - - async def update_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[MailingList, bool]: - """Get object, create if missing, or update it when defaults are provided.""" - ... - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - mode: str = "models", - ) -> list[MailingList]: - """Get all objects.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> MailingList | None: - """Get first object.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> MailingList | None: - """Get last object.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count all objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def create( # type: ignore[override] - self, - *, - instance: MailingList | None = None, - client: Any | None = None, - using: str | None = None, - address: EmailStr | None = None, - archive_address: EmailStr | None = None, - archive_enabled: bool | None = None, - archive_principal_id: int | None = None, - created_at: datetime | None = None, - description: str | None = None, - distribution_address: EmailStr | None = None, - id: int | None = None, - inbox_principal_id: int | None = None, - moderation_enabled: bool | None = None, - name: str | None = None, - principal_id: int | None = None, - public: bool | None = None, - updated_at: datetime | None = None, - ) -> MailingList: - """Create new object.""" - ... - - async def bulk_create( # type: ignore[override] - self, - objects: list[MailingList], - *, - batch_size: int | None = None, - client: Any | None = None, - using: str | None = None, - ) -> list[MailingList]: - """Bulk create objects.""" - ... - - async def bulk_update( # type: ignore[override] - self, - objects: list[MailingList], - fields: list[str], - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Bulk update objects.""" - ... - - -class PendingSubscriber(Model): - class Meta: - is_table: bool - table_name: str - id: int | None - mailing_list: MailingList | None - email: EmailStr - token: str - action: str - created_at: datetime | None - mailing_list_id: int | None - objects: ClassVar["PendingSubscriberManager"] - - -class PendingSubscriberQuery(Query[PendingSubscriber]): - """Type-safe Query for PendingSubscriber model.""" - - # Query building methods (sync, return Query) - - def filter( - self, - *args: Any, - action: str | None = None, - action__contains: str | None = None, - action__icontains: str | None = None, - action__startswith: str | None = None, - action__istartswith: str | None = None, - action__endswith: str | None = None, - action__iendswith: str | None = None, - action__iexact: str | None = None, - action__in: list[str] | None = None, - action__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - email: EmailStr | None = None, - email__in: list[EmailStr] | None = None, - email__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - token: str | None = None, - token__contains: str | None = None, - token__icontains: str | None = None, - token__startswith: str | None = None, - token__istartswith: str | None = None, - token__endswith: str | None = None, - token__iendswith: str | None = None, - token__iexact: str | None = None, - token__in: list[str] | None = None, - token__isnull: bool | None = None, - ) -> "PendingSubscriberQuery": - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - action: str | None = None, - action__contains: str | None = None, - action__icontains: str | None = None, - action__startswith: str | None = None, - action__istartswith: str | None = None, - action__endswith: str | None = None, - action__iendswith: str | None = None, - action__iexact: str | None = None, - action__in: list[str] | None = None, - action__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - email: EmailStr | None = None, - email__in: list[EmailStr] | None = None, - email__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - token: str | None = None, - token__contains: str | None = None, - token__icontains: str | None = None, - token__startswith: str | None = None, - token__istartswith: str | None = None, - token__endswith: str | None = None, - token__iendswith: str | None = None, - token__iexact: str | None = None, - token__in: list[str] | None = None, - token__isnull: bool | None = None, - ) -> "PendingSubscriberQuery": - """Exclude objects matching field lookups.""" - ... - - def order_by(self, *fields: Literal["action", "-action", "created_at", "-created_at", "email", "-email", "id", "-id", "mailing_list", "-mailing_list", "mailing_list_id", "-mailing_list_id", "token", "-token"]) -> "PendingSubscriberQuery": # type: ignore[override] - """Order results by fields.""" - ... - - def limit(self, n: int) -> "PendingSubscriberQuery": - """Limit number of results.""" - ... - - def offset(self, n: int) -> "PendingSubscriberQuery": - """Skip first n results.""" - ... - - def distinct(self, value: bool = True) -> "PendingSubscriberQuery": - """Return distinct results.""" - ... - - def select(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] - """Select specific fields.""" - ... - - def join(self, *paths: str) -> "PendingSubscriberQuery": - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> "PendingSubscriberQuery": - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> "PendingSubscriberQuery": - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> "PendingSubscriberQuery": - """Add FOR SHARE lock to query.""" - ... - - def annotate(self, **annotations: Any) -> "PendingSubscriberQuery": - """Add computed fields using aggregate functions.""" - ... - - def group_by(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] - """Add GROUP BY clause.""" - ... - - def having(self, *q_exprs: Any, **kwargs: Any) -> "PendingSubscriberQuery": - """Add HAVING clause for filtering grouped results.""" - ... - - def values(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"], flat: bool = False) -> "PendingSubscriberQuery": # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - # Terminal methods (async, execute query) - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> list[PendingSubscriber]: - """Execute query and return all results.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> PendingSubscriber | None: - """Execute query and return first result.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> PendingSubscriber | None: - """Execute query and return last result.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count matching objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def update( # type: ignore[override] - self, - *, - client: Any | None = None, - using: str | None = None, - **values: Any, - ) -> int: - """Update matching objects.""" - ... - - async def increment( - self, - field: str, - by: int | float = 1, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Atomically increment a field value.""" - ... - - async def delete( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Delete matching objects.""" - ... - -class PendingSubscriberManager(QueryManager[PendingSubscriber]): - """Type-safe Manager for PendingSubscriber model.""" - - # Query building methods (sync, return Query) - - def query(self) -> PendingSubscriberQuery: - """Return a Query builder for this model.""" - ... - - def filter( - self, - *args: Any, - action: str | None = None, - action__contains: str | None = None, - action__icontains: str | None = None, - action__startswith: str | None = None, - action__istartswith: str | None = None, - action__endswith: str | None = None, - action__iendswith: str | None = None, - action__iexact: str | None = None, - action__in: list[str] | None = None, - action__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - email: EmailStr | None = None, - email__in: list[EmailStr] | None = None, - email__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - token: str | None = None, - token__contains: str | None = None, - token__icontains: str | None = None, - token__startswith: str | None = None, - token__istartswith: str | None = None, - token__endswith: str | None = None, - token__iendswith: str | None = None, - token__iexact: str | None = None, - token__in: list[str] | None = None, - token__isnull: bool | None = None, - ) -> PendingSubscriberQuery: - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - action: str | None = None, - action__contains: str | None = None, - action__icontains: str | None = None, - action__startswith: str | None = None, - action__istartswith: str | None = None, - action__endswith: str | None = None, - action__iendswith: str | None = None, - action__iexact: str | None = None, - action__in: list[str] | None = None, - action__isnull: bool | None = None, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - email: EmailStr | None = None, - email__in: list[EmailStr] | None = None, - email__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - token: str | None = None, - token__contains: str | None = None, - token__icontains: str | None = None, - token__startswith: str | None = None, - token__istartswith: str | None = None, - token__endswith: str | None = None, - token__iendswith: str | None = None, - token__iexact: str | None = None, - token__in: list[str] | None = None, - token__isnull: bool | None = None, - ) -> PendingSubscriberQuery: - """Exclude objects matching field lookups.""" - ... - - def values(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> PendingSubscriberQuery: # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"], flat: bool = False) -> PendingSubscriberQuery: # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - def distinct(self, distinct: bool = True) -> PendingSubscriberQuery: - """Return distinct results.""" - ... - - def join(self, *paths: str) -> PendingSubscriberQuery: - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> PendingSubscriberQuery: - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> PendingSubscriberQuery: - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> PendingSubscriberQuery: - """Add FOR SHARE lock to query.""" - ... - - # Terminal methods (async, execute query) - - async def get( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> PendingSubscriber: - """Get single object matching lookups.""" - ... - - async def get_or_none( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> PendingSubscriber | None: - """Get object or None if not found.""" - ... - - async def get_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[PendingSubscriber, bool]: - """Get object or create if not found. Returns (object, created).""" - ... - - async def update_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[PendingSubscriber, bool]: - """Get object, create if missing, or update it when defaults are provided.""" - ... - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - mode: str = "models", - ) -> list[PendingSubscriber]: - """Get all objects.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> PendingSubscriber | None: - """Get first object.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> PendingSubscriber | None: - """Get last object.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count all objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def create( # type: ignore[override] - self, - *, - instance: PendingSubscriber | None = None, - client: Any | None = None, - using: str | None = None, - action: str | None = None, - created_at: datetime | None = None, - email: EmailStr | None = None, - id: int | None = None, - mailing_list: MailingList | None = None, - mailing_list_id: int | None = None, - token: str | None = None, - ) -> PendingSubscriber: - """Create new object.""" - ... - - async def bulk_create( # type: ignore[override] - self, - objects: list[PendingSubscriber], - *, - batch_size: int | None = None, - client: Any | None = None, - using: str | None = None, - ) -> list[PendingSubscriber]: - """Bulk create objects.""" - ... - - async def bulk_update( # type: ignore[override] - self, - objects: list[PendingSubscriber], - fields: list[str], - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Bulk update objects.""" - ... - - -class ModerationMessage(Model): - class Meta: - is_table: bool - table_name: str - id: int | None - mailing_list: MailingList | None - message_id: str | None - subject: str | None - sender: EmailStr | None - sent_at: datetime | None - text_body: str | None - html_body: str | None - status: str - created_at: datetime | None - decided_at: datetime | None - mailing_list_id: int | None - objects: ClassVar["ModerationMessageManager"] - - -class ModerationMessageQuery(Query[ModerationMessage]): - """Type-safe Query for ModerationMessage model.""" - - # Query building methods (sync, return Query) - - def filter( - self, - *args: Any, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - decided_at: datetime | None = None, - decided_at__gt: datetime | None = None, - decided_at__gte: datetime | None = None, - decided_at__lt: datetime | None = None, - decided_at__lte: datetime | None = None, - decided_at__between: tuple[datetime, datetime] | None = None, - decided_at__range: datetime | None = None, - decided_at__year: int | None = None, - decided_at__month: int | None = None, - decided_at__day: int | None = None, - decided_at__in: list[datetime] | None = None, - decided_at__isnull: bool | None = None, - html_body: str | None = None, - html_body__contains: str | None = None, - html_body__icontains: str | None = None, - html_body__startswith: str | None = None, - html_body__istartswith: str | None = None, - html_body__endswith: str | None = None, - html_body__iendswith: str | None = None, - html_body__iexact: str | None = None, - html_body__in: list[str] | None = None, - html_body__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - message_id: str | None = None, - message_id__contains: str | None = None, - message_id__icontains: str | None = None, - message_id__startswith: str | None = None, - message_id__istartswith: str | None = None, - message_id__endswith: str | None = None, - message_id__iendswith: str | None = None, - message_id__iexact: str | None = None, - message_id__in: list[str] | None = None, - message_id__isnull: bool | None = None, - sender: EmailStr | None = None, - sender__in: list[EmailStr] | None = None, - sender__isnull: bool | None = None, - sent_at: datetime | None = None, - sent_at__gt: datetime | None = None, - sent_at__gte: datetime | None = None, - sent_at__lt: datetime | None = None, - sent_at__lte: datetime | None = None, - sent_at__between: tuple[datetime, datetime] | None = None, - sent_at__range: datetime | None = None, - sent_at__year: int | None = None, - sent_at__month: int | None = None, - sent_at__day: int | None = None, - sent_at__in: list[datetime] | None = None, - sent_at__isnull: bool | None = None, - status: str | None = None, - status__contains: str | None = None, - status__icontains: str | None = None, - status__startswith: str | None = None, - status__istartswith: str | None = None, - status__endswith: str | None = None, - status__iendswith: str | None = None, - status__iexact: str | None = None, - status__in: list[str] | None = None, - status__isnull: bool | None = None, - subject: str | None = None, - subject__contains: str | None = None, - subject__icontains: str | None = None, - subject__startswith: str | None = None, - subject__istartswith: str | None = None, - subject__endswith: str | None = None, - subject__iendswith: str | None = None, - subject__iexact: str | None = None, - subject__in: list[str] | None = None, - subject__isnull: bool | None = None, - text_body: str | None = None, - text_body__contains: str | None = None, - text_body__icontains: str | None = None, - text_body__startswith: str | None = None, - text_body__istartswith: str | None = None, - text_body__endswith: str | None = None, - text_body__iendswith: str | None = None, - text_body__iexact: str | None = None, - text_body__in: list[str] | None = None, - text_body__isnull: bool | None = None, - ) -> "ModerationMessageQuery": - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - decided_at: datetime | None = None, - decided_at__gt: datetime | None = None, - decided_at__gte: datetime | None = None, - decided_at__lt: datetime | None = None, - decided_at__lte: datetime | None = None, - decided_at__between: tuple[datetime, datetime] | None = None, - decided_at__range: datetime | None = None, - decided_at__year: int | None = None, - decided_at__month: int | None = None, - decided_at__day: int | None = None, - decided_at__in: list[datetime] | None = None, - decided_at__isnull: bool | None = None, - html_body: str | None = None, - html_body__contains: str | None = None, - html_body__icontains: str | None = None, - html_body__startswith: str | None = None, - html_body__istartswith: str | None = None, - html_body__endswith: str | None = None, - html_body__iendswith: str | None = None, - html_body__iexact: str | None = None, - html_body__in: list[str] | None = None, - html_body__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - message_id: str | None = None, - message_id__contains: str | None = None, - message_id__icontains: str | None = None, - message_id__startswith: str | None = None, - message_id__istartswith: str | None = None, - message_id__endswith: str | None = None, - message_id__iendswith: str | None = None, - message_id__iexact: str | None = None, - message_id__in: list[str] | None = None, - message_id__isnull: bool | None = None, - sender: EmailStr | None = None, - sender__in: list[EmailStr] | None = None, - sender__isnull: bool | None = None, - sent_at: datetime | None = None, - sent_at__gt: datetime | None = None, - sent_at__gte: datetime | None = None, - sent_at__lt: datetime | None = None, - sent_at__lte: datetime | None = None, - sent_at__between: tuple[datetime, datetime] | None = None, - sent_at__range: datetime | None = None, - sent_at__year: int | None = None, - sent_at__month: int | None = None, - sent_at__day: int | None = None, - sent_at__in: list[datetime] | None = None, - sent_at__isnull: bool | None = None, - status: str | None = None, - status__contains: str | None = None, - status__icontains: str | None = None, - status__startswith: str | None = None, - status__istartswith: str | None = None, - status__endswith: str | None = None, - status__iendswith: str | None = None, - status__iexact: str | None = None, - status__in: list[str] | None = None, - status__isnull: bool | None = None, - subject: str | None = None, - subject__contains: str | None = None, - subject__icontains: str | None = None, - subject__startswith: str | None = None, - subject__istartswith: str | None = None, - subject__endswith: str | None = None, - subject__iendswith: str | None = None, - subject__iexact: str | None = None, - subject__in: list[str] | None = None, - subject__isnull: bool | None = None, - text_body: str | None = None, - text_body__contains: str | None = None, - text_body__icontains: str | None = None, - text_body__startswith: str | None = None, - text_body__istartswith: str | None = None, - text_body__endswith: str | None = None, - text_body__iendswith: str | None = None, - text_body__iexact: str | None = None, - text_body__in: list[str] | None = None, - text_body__isnull: bool | None = None, - ) -> "ModerationMessageQuery": - """Exclude objects matching field lookups.""" - ... - - def order_by(self, *fields: Literal["created_at", "-created_at", "decided_at", "-decided_at", "html_body", "-html_body", "id", "-id", "mailing_list", "-mailing_list", "mailing_list_id", "-mailing_list_id", "message_id", "-message_id", "sender", "-sender", "sent_at", "-sent_at", "status", "-status", "subject", "-subject", "text_body", "-text_body"]) -> "ModerationMessageQuery": # type: ignore[override] - """Order results by fields.""" - ... - - def limit(self, n: int) -> "ModerationMessageQuery": - """Limit number of results.""" - ... - - def offset(self, n: int) -> "ModerationMessageQuery": - """Skip first n results.""" - ... - - def distinct(self, value: bool = True) -> "ModerationMessageQuery": - """Return distinct results.""" - ... - - def select(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] - """Select specific fields.""" - ... - - def join(self, *paths: str) -> "ModerationMessageQuery": - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> "ModerationMessageQuery": - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> "ModerationMessageQuery": - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> "ModerationMessageQuery": - """Add FOR SHARE lock to query.""" - ... - - def annotate(self, **annotations: Any) -> "ModerationMessageQuery": - """Add computed fields using aggregate functions.""" - ... - - def group_by(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] - """Add GROUP BY clause.""" - ... - - def having(self, *q_exprs: Any, **kwargs: Any) -> "ModerationMessageQuery": - """Add HAVING clause for filtering grouped results.""" - ... - - def values(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"], flat: bool = False) -> "ModerationMessageQuery": # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - # Terminal methods (async, execute query) - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> list[ModerationMessage]: - """Execute query and return all results.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> ModerationMessage | None: - """Execute query and return first result.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> ModerationMessage | None: - """Execute query and return last result.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count matching objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def update( # type: ignore[override] - self, - *, - client: Any | None = None, - using: str | None = None, - **values: Any, - ) -> int: - """Update matching objects.""" - ... - - async def increment( - self, - field: str, - by: int | float = 1, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Atomically increment a field value.""" - ... - - async def delete( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Delete matching objects.""" - ... - -class ModerationMessageManager(QueryManager[ModerationMessage]): - """Type-safe Manager for ModerationMessage model.""" - - # Query building methods (sync, return Query) - - def query(self) -> ModerationMessageQuery: - """Return a Query builder for this model.""" - ... - - def filter( - self, - *args: Any, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - decided_at: datetime | None = None, - decided_at__gt: datetime | None = None, - decided_at__gte: datetime | None = None, - decided_at__lt: datetime | None = None, - decided_at__lte: datetime | None = None, - decided_at__between: tuple[datetime, datetime] | None = None, - decided_at__range: datetime | None = None, - decided_at__year: int | None = None, - decided_at__month: int | None = None, - decided_at__day: int | None = None, - decided_at__in: list[datetime] | None = None, - decided_at__isnull: bool | None = None, - html_body: str | None = None, - html_body__contains: str | None = None, - html_body__icontains: str | None = None, - html_body__startswith: str | None = None, - html_body__istartswith: str | None = None, - html_body__endswith: str | None = None, - html_body__iendswith: str | None = None, - html_body__iexact: str | None = None, - html_body__in: list[str] | None = None, - html_body__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - message_id: str | None = None, - message_id__contains: str | None = None, - message_id__icontains: str | None = None, - message_id__startswith: str | None = None, - message_id__istartswith: str | None = None, - message_id__endswith: str | None = None, - message_id__iendswith: str | None = None, - message_id__iexact: str | None = None, - message_id__in: list[str] | None = None, - message_id__isnull: bool | None = None, - sender: EmailStr | None = None, - sender__in: list[EmailStr] | None = None, - sender__isnull: bool | None = None, - sent_at: datetime | None = None, - sent_at__gt: datetime | None = None, - sent_at__gte: datetime | None = None, - sent_at__lt: datetime | None = None, - sent_at__lte: datetime | None = None, - sent_at__between: tuple[datetime, datetime] | None = None, - sent_at__range: datetime | None = None, - sent_at__year: int | None = None, - sent_at__month: int | None = None, - sent_at__day: int | None = None, - sent_at__in: list[datetime] | None = None, - sent_at__isnull: bool | None = None, - status: str | None = None, - status__contains: str | None = None, - status__icontains: str | None = None, - status__startswith: str | None = None, - status__istartswith: str | None = None, - status__endswith: str | None = None, - status__iendswith: str | None = None, - status__iexact: str | None = None, - status__in: list[str] | None = None, - status__isnull: bool | None = None, - subject: str | None = None, - subject__contains: str | None = None, - subject__icontains: str | None = None, - subject__startswith: str | None = None, - subject__istartswith: str | None = None, - subject__endswith: str | None = None, - subject__iendswith: str | None = None, - subject__iexact: str | None = None, - subject__in: list[str] | None = None, - subject__isnull: bool | None = None, - text_body: str | None = None, - text_body__contains: str | None = None, - text_body__icontains: str | None = None, - text_body__startswith: str | None = None, - text_body__istartswith: str | None = None, - text_body__endswith: str | None = None, - text_body__iendswith: str | None = None, - text_body__iexact: str | None = None, - text_body__in: list[str] | None = None, - text_body__isnull: bool | None = None, - ) -> ModerationMessageQuery: - """Filter by Q-expressions or field lookups.""" - ... - - def exclude( - self, - *args: Any, - created_at: datetime | None = None, - created_at__gt: datetime | None = None, - created_at__gte: datetime | None = None, - created_at__lt: datetime | None = None, - created_at__lte: datetime | None = None, - created_at__between: tuple[datetime, datetime] | None = None, - created_at__range: datetime | None = None, - created_at__year: int | None = None, - created_at__month: int | None = None, - created_at__day: int | None = None, - created_at__in: list[datetime] | None = None, - created_at__isnull: bool | None = None, - decided_at: datetime | None = None, - decided_at__gt: datetime | None = None, - decided_at__gte: datetime | None = None, - decided_at__lt: datetime | None = None, - decided_at__lte: datetime | None = None, - decided_at__between: tuple[datetime, datetime] | None = None, - decided_at__range: datetime | None = None, - decided_at__year: int | None = None, - decided_at__month: int | None = None, - decided_at__day: int | None = None, - decided_at__in: list[datetime] | None = None, - decided_at__isnull: bool | None = None, - html_body: str | None = None, - html_body__contains: str | None = None, - html_body__icontains: str | None = None, - html_body__startswith: str | None = None, - html_body__istartswith: str | None = None, - html_body__endswith: str | None = None, - html_body__iendswith: str | None = None, - html_body__iexact: str | None = None, - html_body__in: list[str] | None = None, - html_body__isnull: bool | None = None, - id: int | None = None, - id__gt: int | None = None, - id__gte: int | None = None, - id__lt: int | None = None, - id__lte: int | None = None, - id__between: tuple[int, int] | None = None, - id__range: int | None = None, - id__in: list[int] | None = None, - id__isnull: bool | None = None, - mailing_list: MailingList | None = None, - mailing_list__in: list[MailingList] | None = None, - mailing_list__isnull: bool | None = None, - mailing_list_id: int | None = None, - mailing_list_id__gt: int | None = None, - mailing_list_id__gte: int | None = None, - mailing_list_id__lt: int | None = None, - mailing_list_id__lte: int | None = None, - mailing_list_id__between: tuple[int, int] | None = None, - mailing_list_id__range: int | None = None, - mailing_list_id__in: list[int] | None = None, - mailing_list_id__isnull: bool | None = None, - message_id: str | None = None, - message_id__contains: str | None = None, - message_id__icontains: str | None = None, - message_id__startswith: str | None = None, - message_id__istartswith: str | None = None, - message_id__endswith: str | None = None, - message_id__iendswith: str | None = None, - message_id__iexact: str | None = None, - message_id__in: list[str] | None = None, - message_id__isnull: bool | None = None, - sender: EmailStr | None = None, - sender__in: list[EmailStr] | None = None, - sender__isnull: bool | None = None, - sent_at: datetime | None = None, - sent_at__gt: datetime | None = None, - sent_at__gte: datetime | None = None, - sent_at__lt: datetime | None = None, - sent_at__lte: datetime | None = None, - sent_at__between: tuple[datetime, datetime] | None = None, - sent_at__range: datetime | None = None, - sent_at__year: int | None = None, - sent_at__month: int | None = None, - sent_at__day: int | None = None, - sent_at__in: list[datetime] | None = None, - sent_at__isnull: bool | None = None, - status: str | None = None, - status__contains: str | None = None, - status__icontains: str | None = None, - status__startswith: str | None = None, - status__istartswith: str | None = None, - status__endswith: str | None = None, - status__iendswith: str | None = None, - status__iexact: str | None = None, - status__in: list[str] | None = None, - status__isnull: bool | None = None, - subject: str | None = None, - subject__contains: str | None = None, - subject__icontains: str | None = None, - subject__startswith: str | None = None, - subject__istartswith: str | None = None, - subject__endswith: str | None = None, - subject__iendswith: str | None = None, - subject__iexact: str | None = None, - subject__in: list[str] | None = None, - subject__isnull: bool | None = None, - text_body: str | None = None, - text_body__contains: str | None = None, - text_body__icontains: str | None = None, - text_body__startswith: str | None = None, - text_body__istartswith: str | None = None, - text_body__endswith: str | None = None, - text_body__iendswith: str | None = None, - text_body__iexact: str | None = None, - text_body__in: list[str] | None = None, - text_body__isnull: bool | None = None, - ) -> ModerationMessageQuery: - """Exclude objects matching field lookups.""" - ... - - def values(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> ModerationMessageQuery: # type: ignore[override] - """Return dicts instead of models.""" - ... - - def values_list(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"], flat: bool = False) -> ModerationMessageQuery: # type: ignore[override] - """Return tuples/values instead of models.""" - ... - - def distinct(self, distinct: bool = True) -> ModerationMessageQuery: - """Return distinct results.""" - ... - - def join(self, *paths: str) -> ModerationMessageQuery: - """Perform LEFT JOIN for relations.""" - ... - - def prefetch(self, *paths: str) -> ModerationMessageQuery: - """Prefetch related objects (separate queries).""" - ... - - def for_update(self) -> ModerationMessageQuery: - """Add FOR UPDATE lock to query.""" - ... - - def for_share(self) -> ModerationMessageQuery: - """Add FOR SHARE lock to query.""" - ... - - # Terminal methods (async, execute query) - - async def get( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> ModerationMessage: - """Get single object matching lookups.""" - ... - - async def get_or_none( - self, - *, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> ModerationMessage | None: - """Get object or None if not found.""" - ... - - async def get_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[ModerationMessage, bool]: - """Get object or create if not found. Returns (object, created).""" - ... - - async def update_or_create( - self, - *, - defaults: dict[str, Any] | None = None, - client: Any | None = None, - using: str | None = None, - **filters: Any, - ) -> tuple[ModerationMessage, bool]: - """Get object, create if missing, or update it when defaults are provided.""" - ... - - async def all( - self, - *, - client: Any | None = None, - using: str | None = None, - mode: str = "models", - ) -> list[ModerationMessage]: - """Get all objects.""" - ... - - async def first( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> ModerationMessage | None: - """Get first object.""" - ... - - async def last( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> ModerationMessage | None: - """Get last object.""" - ... - - async def count( - self, - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Count all objects.""" - ... - - async def sum( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate sum of field values.""" - ... - - async def avg( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Calculate average of field values.""" - ... - - async def max( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get maximum field value.""" - ... - - async def min( - self, - field: str, - *, - client: Any | None = None, - using: str | None = None, - ) -> Any: - """Get minimum field value.""" - ... - - async def create( # type: ignore[override] - self, - *, - instance: ModerationMessage | None = None, - client: Any | None = None, - using: str | None = None, - created_at: datetime | None = None, - decided_at: datetime | None = None, - html_body: str | None = None, - id: int | None = None, - mailing_list: MailingList | None = None, - mailing_list_id: int | None = None, - message_id: str | None = None, - sender: EmailStr | None = None, - sent_at: datetime | None = None, - status: str | None = None, - subject: str | None = None, - text_body: str | None = None, - ) -> ModerationMessage: - """Create new object.""" - ... - - async def bulk_create( # type: ignore[override] - self, - objects: list[ModerationMessage], - *, - batch_size: int | None = None, - client: Any | None = None, - using: str | None = None, - ) -> list[ModerationMessage]: - """Bulk create objects.""" - ... - - async def bulk_update( # type: ignore[override] - self, - objects: list[ModerationMessage], - fields: list[str], - *, - client: Any | None = None, - using: str | None = None, - ) -> int: - """Bulk update objects.""" - ... - diff --git a/freenit/models/sql/mailinglist.pyi b/freenit/models/sql/mailinglist.pyi new file mode 100644 index 0000000..2d95309 --- /dev/null +++ b/freenit/models/sql/mailinglist.pyi @@ -0,0 +1,2324 @@ +# Auto-generated by oxyde generate-stubs +# DO NOT EDIT - This file will be overwritten + +from typing import Any, ClassVar, Literal +from datetime import datetime, date, time +from decimal import Decimal +from uuid import UUID + +from oxyde import Model +from oxyde.queries import Query, QueryManager + +from __future__ import annotations +from datetime import datetime +from uuid import uuid4 +import oxyde +import pydantic +from freenit.models.sql.base import OxydeBaseModel + +class MailingList(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + name: str + address: EmailStr + distribution_address: EmailStr + archive_address: EmailStr + description: str | None + public: bool + archive_enabled: bool + moderation_enabled: bool + principal_id: int | None + inbox_principal_id: int | None + archive_principal_id: int | None + created_at: datetime | None + updated_at: datetime | None + objects: ClassVar["MailingListManager"] + + +class MailingListQuery(Query[MailingList]): + """Type-safe Query for MailingList model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + address: EmailStr | None = None, + address__in: list[EmailStr] | None = None, + address__isnull: bool | None = None, + archive_address: EmailStr | None = None, + archive_address__in: list[EmailStr] | None = None, + archive_address__isnull: bool | None = None, + archive_enabled: bool | None = None, + archive_enabled__in: list[bool] | None = None, + archive_enabled__isnull: bool | None = None, + archive_principal_id: int | None = None, + archive_principal_id__gt: int | None = None, + archive_principal_id__gte: int | None = None, + archive_principal_id__lt: int | None = None, + archive_principal_id__lte: int | None = None, + archive_principal_id__between: tuple[int, int] | None = None, + archive_principal_id__range: int | None = None, + archive_principal_id__in: list[int] | None = None, + archive_principal_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + distribution_address: EmailStr | None = None, + distribution_address__in: list[EmailStr] | None = None, + distribution_address__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + inbox_principal_id: int | None = None, + inbox_principal_id__gt: int | None = None, + inbox_principal_id__gte: int | None = None, + inbox_principal_id__lt: int | None = None, + inbox_principal_id__lte: int | None = None, + inbox_principal_id__between: tuple[int, int] | None = None, + inbox_principal_id__range: int | None = None, + inbox_principal_id__in: list[int] | None = None, + inbox_principal_id__isnull: bool | None = None, + moderation_enabled: bool | None = None, + moderation_enabled__in: list[bool] | None = None, + moderation_enabled__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + principal_id: int | None = None, + principal_id__gt: int | None = None, + principal_id__gte: int | None = None, + principal_id__lt: int | None = None, + principal_id__lte: int | None = None, + principal_id__between: tuple[int, int] | None = None, + principal_id__range: int | None = None, + principal_id__in: list[int] | None = None, + principal_id__isnull: bool | None = None, + public: bool | None = None, + public__in: list[bool] | None = None, + public__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "MailingListQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + address: EmailStr | None = None, + address__in: list[EmailStr] | None = None, + address__isnull: bool | None = None, + archive_address: EmailStr | None = None, + archive_address__in: list[EmailStr] | None = None, + archive_address__isnull: bool | None = None, + archive_enabled: bool | None = None, + archive_enabled__in: list[bool] | None = None, + archive_enabled__isnull: bool | None = None, + archive_principal_id: int | None = None, + archive_principal_id__gt: int | None = None, + archive_principal_id__gte: int | None = None, + archive_principal_id__lt: int | None = None, + archive_principal_id__lte: int | None = None, + archive_principal_id__between: tuple[int, int] | None = None, + archive_principal_id__range: int | None = None, + archive_principal_id__in: list[int] | None = None, + archive_principal_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + distribution_address: EmailStr | None = None, + distribution_address__in: list[EmailStr] | None = None, + distribution_address__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + inbox_principal_id: int | None = None, + inbox_principal_id__gt: int | None = None, + inbox_principal_id__gte: int | None = None, + inbox_principal_id__lt: int | None = None, + inbox_principal_id__lte: int | None = None, + inbox_principal_id__between: tuple[int, int] | None = None, + inbox_principal_id__range: int | None = None, + inbox_principal_id__in: list[int] | None = None, + inbox_principal_id__isnull: bool | None = None, + moderation_enabled: bool | None = None, + moderation_enabled__in: list[bool] | None = None, + moderation_enabled__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + principal_id: int | None = None, + principal_id__gt: int | None = None, + principal_id__gte: int | None = None, + principal_id__lt: int | None = None, + principal_id__lte: int | None = None, + principal_id__between: tuple[int, int] | None = None, + principal_id__range: int | None = None, + principal_id__in: list[int] | None = None, + principal_id__isnull: bool | None = None, + public: bool | None = None, + public__in: list[bool] | None = None, + public__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "MailingListQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["address", "-address", "archive_address", "-archive_address", "archive_enabled", "-archive_enabled", "archive_principal_id", "-archive_principal_id", "created_at", "-created_at", "description", "-description", "distribution_address", "-distribution_address", "id", "-id", "inbox_principal_id", "-inbox_principal_id", "moderation_enabled", "-moderation_enabled", "name", "-name", "principal_id", "-principal_id", "public", "-public", "updated_at", "-updated_at"]) -> "MailingListQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "MailingListQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "MailingListQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "MailingListQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "MailingListQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "MailingListQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "MailingListQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "MailingListQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "MailingListQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "MailingListQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> "MailingListQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"], flat: bool = False) -> "MailingListQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[MailingList]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> MailingList | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> MailingList | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class MailingListManager(QueryManager[MailingList]): + """Type-safe Manager for MailingList model.""" + + # Query building methods (sync, return Query) + + def query(self) -> MailingListQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + address: EmailStr | None = None, + address__in: list[EmailStr] | None = None, + address__isnull: bool | None = None, + archive_address: EmailStr | None = None, + archive_address__in: list[EmailStr] | None = None, + archive_address__isnull: bool | None = None, + archive_enabled: bool | None = None, + archive_enabled__in: list[bool] | None = None, + archive_enabled__isnull: bool | None = None, + archive_principal_id: int | None = None, + archive_principal_id__gt: int | None = None, + archive_principal_id__gte: int | None = None, + archive_principal_id__lt: int | None = None, + archive_principal_id__lte: int | None = None, + archive_principal_id__between: tuple[int, int] | None = None, + archive_principal_id__range: int | None = None, + archive_principal_id__in: list[int] | None = None, + archive_principal_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + distribution_address: EmailStr | None = None, + distribution_address__in: list[EmailStr] | None = None, + distribution_address__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + inbox_principal_id: int | None = None, + inbox_principal_id__gt: int | None = None, + inbox_principal_id__gte: int | None = None, + inbox_principal_id__lt: int | None = None, + inbox_principal_id__lte: int | None = None, + inbox_principal_id__between: tuple[int, int] | None = None, + inbox_principal_id__range: int | None = None, + inbox_principal_id__in: list[int] | None = None, + inbox_principal_id__isnull: bool | None = None, + moderation_enabled: bool | None = None, + moderation_enabled__in: list[bool] | None = None, + moderation_enabled__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + principal_id: int | None = None, + principal_id__gt: int | None = None, + principal_id__gte: int | None = None, + principal_id__lt: int | None = None, + principal_id__lte: int | None = None, + principal_id__between: tuple[int, int] | None = None, + principal_id__range: int | None = None, + principal_id__in: list[int] | None = None, + principal_id__isnull: bool | None = None, + public: bool | None = None, + public__in: list[bool] | None = None, + public__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> MailingListQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + address: EmailStr | None = None, + address__in: list[EmailStr] | None = None, + address__isnull: bool | None = None, + archive_address: EmailStr | None = None, + archive_address__in: list[EmailStr] | None = None, + archive_address__isnull: bool | None = None, + archive_enabled: bool | None = None, + archive_enabled__in: list[bool] | None = None, + archive_enabled__isnull: bool | None = None, + archive_principal_id: int | None = None, + archive_principal_id__gt: int | None = None, + archive_principal_id__gte: int | None = None, + archive_principal_id__lt: int | None = None, + archive_principal_id__lte: int | None = None, + archive_principal_id__between: tuple[int, int] | None = None, + archive_principal_id__range: int | None = None, + archive_principal_id__in: list[int] | None = None, + archive_principal_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + distribution_address: EmailStr | None = None, + distribution_address__in: list[EmailStr] | None = None, + distribution_address__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + inbox_principal_id: int | None = None, + inbox_principal_id__gt: int | None = None, + inbox_principal_id__gte: int | None = None, + inbox_principal_id__lt: int | None = None, + inbox_principal_id__lte: int | None = None, + inbox_principal_id__between: tuple[int, int] | None = None, + inbox_principal_id__range: int | None = None, + inbox_principal_id__in: list[int] | None = None, + inbox_principal_id__isnull: bool | None = None, + moderation_enabled: bool | None = None, + moderation_enabled__in: list[bool] | None = None, + moderation_enabled__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + principal_id: int | None = None, + principal_id__gt: int | None = None, + principal_id__gte: int | None = None, + principal_id__lt: int | None = None, + principal_id__lte: int | None = None, + principal_id__between: tuple[int, int] | None = None, + principal_id__range: int | None = None, + principal_id__in: list[int] | None = None, + principal_id__isnull: bool | None = None, + public: bool | None = None, + public__in: list[bool] | None = None, + public__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> MailingListQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"]) -> MailingListQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["address", "archive_address", "archive_enabled", "archive_principal_id", "created_at", "description", "distribution_address", "id", "inbox_principal_id", "moderation_enabled", "name", "principal_id", "public", "updated_at"], flat: bool = False) -> MailingListQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> MailingListQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> MailingListQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> MailingListQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> MailingListQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> MailingListQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> MailingList: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> MailingList | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[MailingList, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[MailingList, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[MailingList]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> MailingList | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> MailingList | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: MailingList | None = None, + client: Any | None = None, + using: str | None = None, + address: EmailStr | None = None, + archive_address: EmailStr | None = None, + archive_enabled: bool | None = None, + archive_principal_id: int | None = None, + created_at: datetime | None = None, + description: str | None = None, + distribution_address: EmailStr | None = None, + id: int | None = None, + inbox_principal_id: int | None = None, + moderation_enabled: bool | None = None, + name: str | None = None, + principal_id: int | None = None, + public: bool | None = None, + updated_at: datetime | None = None, + ) -> MailingList: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[MailingList], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[MailingList]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[MailingList], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + + +class PendingSubscriber(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + mailing_list: MailingList | None + email: EmailStr + token: str + action: str + created_at: datetime | None + mailing_list_id: int | None + objects: ClassVar["PendingSubscriberManager"] + + +class PendingSubscriberQuery(Query[PendingSubscriber]): + """Type-safe Query for PendingSubscriber model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + action: str | None = None, + action__contains: str | None = None, + action__icontains: str | None = None, + action__startswith: str | None = None, + action__istartswith: str | None = None, + action__endswith: str | None = None, + action__iendswith: str | None = None, + action__iexact: str | None = None, + action__in: list[str] | None = None, + action__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + email: EmailStr | None = None, + email__in: list[EmailStr] | None = None, + email__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + token: str | None = None, + token__contains: str | None = None, + token__icontains: str | None = None, + token__startswith: str | None = None, + token__istartswith: str | None = None, + token__endswith: str | None = None, + token__iendswith: str | None = None, + token__iexact: str | None = None, + token__in: list[str] | None = None, + token__isnull: bool | None = None, + ) -> "PendingSubscriberQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + action: str | None = None, + action__contains: str | None = None, + action__icontains: str | None = None, + action__startswith: str | None = None, + action__istartswith: str | None = None, + action__endswith: str | None = None, + action__iendswith: str | None = None, + action__iexact: str | None = None, + action__in: list[str] | None = None, + action__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + email: EmailStr | None = None, + email__in: list[EmailStr] | None = None, + email__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + token: str | None = None, + token__contains: str | None = None, + token__icontains: str | None = None, + token__startswith: str | None = None, + token__istartswith: str | None = None, + token__endswith: str | None = None, + token__iendswith: str | None = None, + token__iexact: str | None = None, + token__in: list[str] | None = None, + token__isnull: bool | None = None, + ) -> "PendingSubscriberQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["action", "-action", "created_at", "-created_at", "email", "-email", "id", "-id", "mailing_list", "-mailing_list", "mailing_list_id", "-mailing_list_id", "token", "-token"]) -> "PendingSubscriberQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "PendingSubscriberQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "PendingSubscriberQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "PendingSubscriberQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "PendingSubscriberQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "PendingSubscriberQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "PendingSubscriberQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "PendingSubscriberQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "PendingSubscriberQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "PendingSubscriberQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> "PendingSubscriberQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"], flat: bool = False) -> "PendingSubscriberQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[PendingSubscriber]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> PendingSubscriber | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> PendingSubscriber | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class PendingSubscriberManager(QueryManager[PendingSubscriber]): + """Type-safe Manager for PendingSubscriber model.""" + + # Query building methods (sync, return Query) + + def query(self) -> PendingSubscriberQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + action: str | None = None, + action__contains: str | None = None, + action__icontains: str | None = None, + action__startswith: str | None = None, + action__istartswith: str | None = None, + action__endswith: str | None = None, + action__iendswith: str | None = None, + action__iexact: str | None = None, + action__in: list[str] | None = None, + action__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + email: EmailStr | None = None, + email__in: list[EmailStr] | None = None, + email__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + token: str | None = None, + token__contains: str | None = None, + token__icontains: str | None = None, + token__startswith: str | None = None, + token__istartswith: str | None = None, + token__endswith: str | None = None, + token__iendswith: str | None = None, + token__iexact: str | None = None, + token__in: list[str] | None = None, + token__isnull: bool | None = None, + ) -> PendingSubscriberQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + action: str | None = None, + action__contains: str | None = None, + action__icontains: str | None = None, + action__startswith: str | None = None, + action__istartswith: str | None = None, + action__endswith: str | None = None, + action__iendswith: str | None = None, + action__iexact: str | None = None, + action__in: list[str] | None = None, + action__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + email: EmailStr | None = None, + email__in: list[EmailStr] | None = None, + email__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + token: str | None = None, + token__contains: str | None = None, + token__icontains: str | None = None, + token__startswith: str | None = None, + token__istartswith: str | None = None, + token__endswith: str | None = None, + token__iendswith: str | None = None, + token__iexact: str | None = None, + token__in: list[str] | None = None, + token__isnull: bool | None = None, + ) -> PendingSubscriberQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"]) -> PendingSubscriberQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["action", "created_at", "email", "id", "mailing_list", "mailing_list_id", "token"], flat: bool = False) -> PendingSubscriberQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> PendingSubscriberQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> PendingSubscriberQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> PendingSubscriberQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> PendingSubscriberQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> PendingSubscriberQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> PendingSubscriber: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> PendingSubscriber | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[PendingSubscriber, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[PendingSubscriber, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[PendingSubscriber]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> PendingSubscriber | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> PendingSubscriber | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: PendingSubscriber | None = None, + client: Any | None = None, + using: str | None = None, + action: str | None = None, + created_at: datetime | None = None, + email: EmailStr | None = None, + id: int | None = None, + mailing_list: MailingList | None = None, + mailing_list_id: int | None = None, + token: str | None = None, + ) -> PendingSubscriber: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[PendingSubscriber], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[PendingSubscriber]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[PendingSubscriber], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + + +class ModerationMessage(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + mailing_list: MailingList | None + message_id: str | None + subject: str | None + sender: EmailStr | None + sent_at: datetime | None + text_body: str | None + html_body: str | None + status: str + created_at: datetime | None + decided_at: datetime | None + mailing_list_id: int | None + objects: ClassVar["ModerationMessageManager"] + + +class ModerationMessageQuery(Query[ModerationMessage]): + """Type-safe Query for ModerationMessage model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + decided_at: datetime | None = None, + decided_at__gt: datetime | None = None, + decided_at__gte: datetime | None = None, + decided_at__lt: datetime | None = None, + decided_at__lte: datetime | None = None, + decided_at__between: tuple[datetime, datetime] | None = None, + decided_at__range: datetime | None = None, + decided_at__year: int | None = None, + decided_at__month: int | None = None, + decided_at__day: int | None = None, + decided_at__in: list[datetime] | None = None, + decided_at__isnull: bool | None = None, + html_body: str | None = None, + html_body__contains: str | None = None, + html_body__icontains: str | None = None, + html_body__startswith: str | None = None, + html_body__istartswith: str | None = None, + html_body__endswith: str | None = None, + html_body__iendswith: str | None = None, + html_body__iexact: str | None = None, + html_body__in: list[str] | None = None, + html_body__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + message_id: str | None = None, + message_id__contains: str | None = None, + message_id__icontains: str | None = None, + message_id__startswith: str | None = None, + message_id__istartswith: str | None = None, + message_id__endswith: str | None = None, + message_id__iendswith: str | None = None, + message_id__iexact: str | None = None, + message_id__in: list[str] | None = None, + message_id__isnull: bool | None = None, + sender: EmailStr | None = None, + sender__in: list[EmailStr] | None = None, + sender__isnull: bool | None = None, + sent_at: datetime | None = None, + sent_at__gt: datetime | None = None, + sent_at__gte: datetime | None = None, + sent_at__lt: datetime | None = None, + sent_at__lte: datetime | None = None, + sent_at__between: tuple[datetime, datetime] | None = None, + sent_at__range: datetime | None = None, + sent_at__year: int | None = None, + sent_at__month: int | None = None, + sent_at__day: int | None = None, + sent_at__in: list[datetime] | None = None, + sent_at__isnull: bool | None = None, + status: str | None = None, + status__contains: str | None = None, + status__icontains: str | None = None, + status__startswith: str | None = None, + status__istartswith: str | None = None, + status__endswith: str | None = None, + status__iendswith: str | None = None, + status__iexact: str | None = None, + status__in: list[str] | None = None, + status__isnull: bool | None = None, + subject: str | None = None, + subject__contains: str | None = None, + subject__icontains: str | None = None, + subject__startswith: str | None = None, + subject__istartswith: str | None = None, + subject__endswith: str | None = None, + subject__iendswith: str | None = None, + subject__iexact: str | None = None, + subject__in: list[str] | None = None, + subject__isnull: bool | None = None, + text_body: str | None = None, + text_body__contains: str | None = None, + text_body__icontains: str | None = None, + text_body__startswith: str | None = None, + text_body__istartswith: str | None = None, + text_body__endswith: str | None = None, + text_body__iendswith: str | None = None, + text_body__iexact: str | None = None, + text_body__in: list[str] | None = None, + text_body__isnull: bool | None = None, + ) -> "ModerationMessageQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + decided_at: datetime | None = None, + decided_at__gt: datetime | None = None, + decided_at__gte: datetime | None = None, + decided_at__lt: datetime | None = None, + decided_at__lte: datetime | None = None, + decided_at__between: tuple[datetime, datetime] | None = None, + decided_at__range: datetime | None = None, + decided_at__year: int | None = None, + decided_at__month: int | None = None, + decided_at__day: int | None = None, + decided_at__in: list[datetime] | None = None, + decided_at__isnull: bool | None = None, + html_body: str | None = None, + html_body__contains: str | None = None, + html_body__icontains: str | None = None, + html_body__startswith: str | None = None, + html_body__istartswith: str | None = None, + html_body__endswith: str | None = None, + html_body__iendswith: str | None = None, + html_body__iexact: str | None = None, + html_body__in: list[str] | None = None, + html_body__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + message_id: str | None = None, + message_id__contains: str | None = None, + message_id__icontains: str | None = None, + message_id__startswith: str | None = None, + message_id__istartswith: str | None = None, + message_id__endswith: str | None = None, + message_id__iendswith: str | None = None, + message_id__iexact: str | None = None, + message_id__in: list[str] | None = None, + message_id__isnull: bool | None = None, + sender: EmailStr | None = None, + sender__in: list[EmailStr] | None = None, + sender__isnull: bool | None = None, + sent_at: datetime | None = None, + sent_at__gt: datetime | None = None, + sent_at__gte: datetime | None = None, + sent_at__lt: datetime | None = None, + sent_at__lte: datetime | None = None, + sent_at__between: tuple[datetime, datetime] | None = None, + sent_at__range: datetime | None = None, + sent_at__year: int | None = None, + sent_at__month: int | None = None, + sent_at__day: int | None = None, + sent_at__in: list[datetime] | None = None, + sent_at__isnull: bool | None = None, + status: str | None = None, + status__contains: str | None = None, + status__icontains: str | None = None, + status__startswith: str | None = None, + status__istartswith: str | None = None, + status__endswith: str | None = None, + status__iendswith: str | None = None, + status__iexact: str | None = None, + status__in: list[str] | None = None, + status__isnull: bool | None = None, + subject: str | None = None, + subject__contains: str | None = None, + subject__icontains: str | None = None, + subject__startswith: str | None = None, + subject__istartswith: str | None = None, + subject__endswith: str | None = None, + subject__iendswith: str | None = None, + subject__iexact: str | None = None, + subject__in: list[str] | None = None, + subject__isnull: bool | None = None, + text_body: str | None = None, + text_body__contains: str | None = None, + text_body__icontains: str | None = None, + text_body__startswith: str | None = None, + text_body__istartswith: str | None = None, + text_body__endswith: str | None = None, + text_body__iendswith: str | None = None, + text_body__iexact: str | None = None, + text_body__in: list[str] | None = None, + text_body__isnull: bool | None = None, + ) -> "ModerationMessageQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["created_at", "-created_at", "decided_at", "-decided_at", "html_body", "-html_body", "id", "-id", "mailing_list", "-mailing_list", "mailing_list_id", "-mailing_list_id", "message_id", "-message_id", "sender", "-sender", "sent_at", "-sent_at", "status", "-status", "subject", "-subject", "text_body", "-text_body"]) -> "ModerationMessageQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "ModerationMessageQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "ModerationMessageQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "ModerationMessageQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "ModerationMessageQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "ModerationMessageQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "ModerationMessageQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "ModerationMessageQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "ModerationMessageQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "ModerationMessageQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> "ModerationMessageQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"], flat: bool = False) -> "ModerationMessageQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[ModerationMessage]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> ModerationMessage | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> ModerationMessage | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class ModerationMessageManager(QueryManager[ModerationMessage]): + """Type-safe Manager for ModerationMessage model.""" + + # Query building methods (sync, return Query) + + def query(self) -> ModerationMessageQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + decided_at: datetime | None = None, + decided_at__gt: datetime | None = None, + decided_at__gte: datetime | None = None, + decided_at__lt: datetime | None = None, + decided_at__lte: datetime | None = None, + decided_at__between: tuple[datetime, datetime] | None = None, + decided_at__range: datetime | None = None, + decided_at__year: int | None = None, + decided_at__month: int | None = None, + decided_at__day: int | None = None, + decided_at__in: list[datetime] | None = None, + decided_at__isnull: bool | None = None, + html_body: str | None = None, + html_body__contains: str | None = None, + html_body__icontains: str | None = None, + html_body__startswith: str | None = None, + html_body__istartswith: str | None = None, + html_body__endswith: str | None = None, + html_body__iendswith: str | None = None, + html_body__iexact: str | None = None, + html_body__in: list[str] | None = None, + html_body__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + message_id: str | None = None, + message_id__contains: str | None = None, + message_id__icontains: str | None = None, + message_id__startswith: str | None = None, + message_id__istartswith: str | None = None, + message_id__endswith: str | None = None, + message_id__iendswith: str | None = None, + message_id__iexact: str | None = None, + message_id__in: list[str] | None = None, + message_id__isnull: bool | None = None, + sender: EmailStr | None = None, + sender__in: list[EmailStr] | None = None, + sender__isnull: bool | None = None, + sent_at: datetime | None = None, + sent_at__gt: datetime | None = None, + sent_at__gte: datetime | None = None, + sent_at__lt: datetime | None = None, + sent_at__lte: datetime | None = None, + sent_at__between: tuple[datetime, datetime] | None = None, + sent_at__range: datetime | None = None, + sent_at__year: int | None = None, + sent_at__month: int | None = None, + sent_at__day: int | None = None, + sent_at__in: list[datetime] | None = None, + sent_at__isnull: bool | None = None, + status: str | None = None, + status__contains: str | None = None, + status__icontains: str | None = None, + status__startswith: str | None = None, + status__istartswith: str | None = None, + status__endswith: str | None = None, + status__iendswith: str | None = None, + status__iexact: str | None = None, + status__in: list[str] | None = None, + status__isnull: bool | None = None, + subject: str | None = None, + subject__contains: str | None = None, + subject__icontains: str | None = None, + subject__startswith: str | None = None, + subject__istartswith: str | None = None, + subject__endswith: str | None = None, + subject__iendswith: str | None = None, + subject__iexact: str | None = None, + subject__in: list[str] | None = None, + subject__isnull: bool | None = None, + text_body: str | None = None, + text_body__contains: str | None = None, + text_body__icontains: str | None = None, + text_body__startswith: str | None = None, + text_body__istartswith: str | None = None, + text_body__endswith: str | None = None, + text_body__iendswith: str | None = None, + text_body__iexact: str | None = None, + text_body__in: list[str] | None = None, + text_body__isnull: bool | None = None, + ) -> ModerationMessageQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + decided_at: datetime | None = None, + decided_at__gt: datetime | None = None, + decided_at__gte: datetime | None = None, + decided_at__lt: datetime | None = None, + decided_at__lte: datetime | None = None, + decided_at__between: tuple[datetime, datetime] | None = None, + decided_at__range: datetime | None = None, + decided_at__year: int | None = None, + decided_at__month: int | None = None, + decided_at__day: int | None = None, + decided_at__in: list[datetime] | None = None, + decided_at__isnull: bool | None = None, + html_body: str | None = None, + html_body__contains: str | None = None, + html_body__icontains: str | None = None, + html_body__startswith: str | None = None, + html_body__istartswith: str | None = None, + html_body__endswith: str | None = None, + html_body__iendswith: str | None = None, + html_body__iexact: str | None = None, + html_body__in: list[str] | None = None, + html_body__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + mailing_list: MailingList | None = None, + mailing_list__in: list[MailingList] | None = None, + mailing_list__isnull: bool | None = None, + mailing_list_id: int | None = None, + mailing_list_id__gt: int | None = None, + mailing_list_id__gte: int | None = None, + mailing_list_id__lt: int | None = None, + mailing_list_id__lte: int | None = None, + mailing_list_id__between: tuple[int, int] | None = None, + mailing_list_id__range: int | None = None, + mailing_list_id__in: list[int] | None = None, + mailing_list_id__isnull: bool | None = None, + message_id: str | None = None, + message_id__contains: str | None = None, + message_id__icontains: str | None = None, + message_id__startswith: str | None = None, + message_id__istartswith: str | None = None, + message_id__endswith: str | None = None, + message_id__iendswith: str | None = None, + message_id__iexact: str | None = None, + message_id__in: list[str] | None = None, + message_id__isnull: bool | None = None, + sender: EmailStr | None = None, + sender__in: list[EmailStr] | None = None, + sender__isnull: bool | None = None, + sent_at: datetime | None = None, + sent_at__gt: datetime | None = None, + sent_at__gte: datetime | None = None, + sent_at__lt: datetime | None = None, + sent_at__lte: datetime | None = None, + sent_at__between: tuple[datetime, datetime] | None = None, + sent_at__range: datetime | None = None, + sent_at__year: int | None = None, + sent_at__month: int | None = None, + sent_at__day: int | None = None, + sent_at__in: list[datetime] | None = None, + sent_at__isnull: bool | None = None, + status: str | None = None, + status__contains: str | None = None, + status__icontains: str | None = None, + status__startswith: str | None = None, + status__istartswith: str | None = None, + status__endswith: str | None = None, + status__iendswith: str | None = None, + status__iexact: str | None = None, + status__in: list[str] | None = None, + status__isnull: bool | None = None, + subject: str | None = None, + subject__contains: str | None = None, + subject__icontains: str | None = None, + subject__startswith: str | None = None, + subject__istartswith: str | None = None, + subject__endswith: str | None = None, + subject__iendswith: str | None = None, + subject__iexact: str | None = None, + subject__in: list[str] | None = None, + subject__isnull: bool | None = None, + text_body: str | None = None, + text_body__contains: str | None = None, + text_body__icontains: str | None = None, + text_body__startswith: str | None = None, + text_body__istartswith: str | None = None, + text_body__endswith: str | None = None, + text_body__iendswith: str | None = None, + text_body__iexact: str | None = None, + text_body__in: list[str] | None = None, + text_body__isnull: bool | None = None, + ) -> ModerationMessageQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"]) -> ModerationMessageQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "decided_at", "html_body", "id", "mailing_list", "mailing_list_id", "message_id", "sender", "sent_at", "status", "subject", "text_body"], flat: bool = False) -> ModerationMessageQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> ModerationMessageQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> ModerationMessageQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> ModerationMessageQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> ModerationMessageQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> ModerationMessageQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> ModerationMessage: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> ModerationMessage | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[ModerationMessage, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[ModerationMessage, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[ModerationMessage]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> ModerationMessage | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> ModerationMessage | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: ModerationMessage | None = None, + client: Any | None = None, + using: str | None = None, + created_at: datetime | None = None, + decided_at: datetime | None = None, + html_body: str | None = None, + id: int | None = None, + mailing_list: MailingList | None = None, + mailing_list_id: int | None = None, + message_id: str | None = None, + sender: EmailStr | None = None, + sent_at: datetime | None = None, + status: str | None = None, + subject: str | None = None, + text_body: str | None = None, + ) -> ModerationMessage: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[ModerationMessage], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[ModerationMessage]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[ModerationMessage], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + diff --git a/freenit/models/sql/project.py b/freenit/models/sql/project.py new file mode 100644 index 0000000..3ecb45e --- /dev/null +++ b/freenit/models/sql/project.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from datetime import datetime + +import oxyde +import pydantic + +from freenit.models.sql.base import OxydeBaseModel, User + +NotFoundError = oxyde.NotFoundError +IntegrityError = oxyde.IntegrityError + + +class Project(OxydeBaseModel): + id: int | None = oxyde.Field(default=None, db_pk=True) + name: str = oxyde.Field(db_unique=True) + description: str | None = oxyde.Field(default=None) + created_by: User | None = oxyde.Field( + default=None, db_fk="id", db_on_delete="SET NULL" + ) + created_at: datetime | None = oxyde.Field(default=None) + updated_at: datetime | None = oxyde.Field(default=None) + + class Meta: + is_table = True + table_name = "project" + + +class Board(OxydeBaseModel): + id: int | None = oxyde.Field(default=None, db_pk=True) + project: Project | None = oxyde.Field( + default=None, db_fk="id", db_on_delete="CASCADE" + ) + name: str = oxyde.Field() + description: str | None = oxyde.Field(default=None) + created_at: datetime | None = oxyde.Field(default=None) + updated_at: datetime | None = oxyde.Field(default=None) + + class Meta: + is_table = True + table_name = "board" + unique_together = [("project_id", "name")] + + +class Column(OxydeBaseModel): + id: int | None = oxyde.Field(default=None, db_pk=True) + board: Board | None = oxyde.Field(default=None, db_fk="id", db_on_delete="CASCADE") + name: str = oxyde.Field() + position: int = oxyde.Field(default=0) + created_at: datetime | None = oxyde.Field(default=None) + updated_at: datetime | None = oxyde.Field(default=None) + + class Meta: + is_table = True + table_name = "board_column" + unique_together = [("board_id", "name")] + + +class Task(OxydeBaseModel): + id: int | None = oxyde.Field(default=None, db_pk=True) + column: Column | None = oxyde.Field( + default=None, db_fk="id", db_on_delete="CASCADE" + ) + title: str = oxyde.Field() + description: str | None = oxyde.Field(default=None) + position: int = oxyde.Field(default=0) + assignee: User | None = oxyde.Field( + default=None, db_fk="id", db_on_delete="SET NULL" + ) + parent: Task | None = oxyde.Field( + default=None, db_fk="id", db_on_delete="SET NULL" + ) + created_at: datetime | None = oxyde.Field(default=None) + updated_at: datetime | None = oxyde.Field(default=None) + + class Meta: + is_table = True + table_name = "task" + + +class ProjectOptional(pydantic.BaseModel): + model_config = pydantic.ConfigDict(extra="forbid") + + name: str | None = None + description: str | None = None + + +class BoardOptional(pydantic.BaseModel): + model_config = pydantic.ConfigDict(extra="forbid") + + name: str | None = None + description: str | None = None + + +class ColumnOptional(pydantic.BaseModel): + model_config = pydantic.ConfigDict(extra="forbid") + + name: str | None = None + position: int | None = None + + +class TaskOptional(pydantic.BaseModel): + model_config = pydantic.ConfigDict(extra="forbid") + + title: str | None = None + description: str | None = None + position: int | None = None + column_id: int | None = None + assignee_id: int | None = None + parent_id: int | None = None + + +Project.model_rebuild() +Board.model_rebuild() +Column.model_rebuild() +Task.model_rebuild() diff --git a/freenit/models/sql/project.pyi b/freenit/models/sql/project.pyi new file mode 100644 index 0000000..cd33f84 --- /dev/null +++ b/freenit/models/sql/project.pyi @@ -0,0 +1,2830 @@ +# Auto-generated by oxyde generate-stubs +# DO NOT EDIT - This file will be overwritten + +from typing import Any, ClassVar, Literal +from datetime import datetime, date, time +from decimal import Decimal +from uuid import UUID + +from oxyde import Model +from oxyde.queries import Query, QueryManager + +from __future__ import annotations +from datetime import datetime +import oxyde +import pydantic +from freenit.models.sql.base import OxydeBaseModel, User + +class Project(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + name: str + description: str | None + created_by: User | None + created_at: datetime | None + updated_at: datetime | None + created_by_id: int | None + objects: ClassVar["ProjectManager"] + + +class ProjectQuery(Query[Project]): + """Type-safe Query for Project model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + created_by: User | None = None, + created_by__in: list[User] | None = None, + created_by__isnull: bool | None = None, + created_by_id: int | None = None, + created_by_id__gt: int | None = None, + created_by_id__gte: int | None = None, + created_by_id__lt: int | None = None, + created_by_id__lte: int | None = None, + created_by_id__between: tuple[int, int] | None = None, + created_by_id__range: int | None = None, + created_by_id__in: list[int] | None = None, + created_by_id__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "ProjectQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + created_by: User | None = None, + created_by__in: list[User] | None = None, + created_by__isnull: bool | None = None, + created_by_id: int | None = None, + created_by_id__gt: int | None = None, + created_by_id__gte: int | None = None, + created_by_id__lt: int | None = None, + created_by_id__lte: int | None = None, + created_by_id__between: tuple[int, int] | None = None, + created_by_id__range: int | None = None, + created_by_id__in: list[int] | None = None, + created_by_id__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "ProjectQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["created_at", "-created_at", "created_by", "-created_by", "created_by_id", "-created_by_id", "description", "-description", "id", "-id", "name", "-name", "updated_at", "-updated_at"]) -> "ProjectQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "ProjectQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "ProjectQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "ProjectQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"]) -> "ProjectQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "ProjectQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "ProjectQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "ProjectQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "ProjectQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "ProjectQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"]) -> "ProjectQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "ProjectQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"]) -> "ProjectQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"], flat: bool = False) -> "ProjectQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[Project]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Project | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Project | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class ProjectManager(QueryManager[Project]): + """Type-safe Manager for Project model.""" + + # Query building methods (sync, return Query) + + def query(self) -> ProjectQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + created_by: User | None = None, + created_by__in: list[User] | None = None, + created_by__isnull: bool | None = None, + created_by_id: int | None = None, + created_by_id__gt: int | None = None, + created_by_id__gte: int | None = None, + created_by_id__lt: int | None = None, + created_by_id__lte: int | None = None, + created_by_id__between: tuple[int, int] | None = None, + created_by_id__range: int | None = None, + created_by_id__in: list[int] | None = None, + created_by_id__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> ProjectQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + created_by: User | None = None, + created_by__in: list[User] | None = None, + created_by__isnull: bool | None = None, + created_by_id: int | None = None, + created_by_id__gt: int | None = None, + created_by_id__gte: int | None = None, + created_by_id__lt: int | None = None, + created_by_id__lte: int | None = None, + created_by_id__between: tuple[int, int] | None = None, + created_by_id__range: int | None = None, + created_by_id__in: list[int] | None = None, + created_by_id__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> ProjectQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"]) -> ProjectQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "created_by", "created_by_id", "description", "id", "name", "updated_at"], flat: bool = False) -> ProjectQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> ProjectQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> ProjectQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> ProjectQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> ProjectQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> ProjectQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Project: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Project | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Project, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Project, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[Project]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Project | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Project | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: Project | None = None, + client: Any | None = None, + using: str | None = None, + created_at: datetime | None = None, + created_by: User | None = None, + created_by_id: int | None = None, + description: str | None = None, + id: int | None = None, + name: str | None = None, + updated_at: datetime | None = None, + ) -> Project: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[Project], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[Project]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[Project], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + + +class Board(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + project: Project | None + name: str + description: str | None + created_at: datetime | None + updated_at: datetime | None + project_id: int | None + objects: ClassVar["BoardManager"] + + +class BoardQuery(Query[Board]): + """Type-safe Query for Board model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + project: Project | None = None, + project__in: list[Project] | None = None, + project__isnull: bool | None = None, + project_id: int | None = None, + project_id__gt: int | None = None, + project_id__gte: int | None = None, + project_id__lt: int | None = None, + project_id__lte: int | None = None, + project_id__between: tuple[int, int] | None = None, + project_id__range: int | None = None, + project_id__in: list[int] | None = None, + project_id__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "BoardQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + project: Project | None = None, + project__in: list[Project] | None = None, + project__isnull: bool | None = None, + project_id: int | None = None, + project_id__gt: int | None = None, + project_id__gte: int | None = None, + project_id__lt: int | None = None, + project_id__lte: int | None = None, + project_id__between: tuple[int, int] | None = None, + project_id__range: int | None = None, + project_id__in: list[int] | None = None, + project_id__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "BoardQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["created_at", "-created_at", "description", "-description", "id", "-id", "name", "-name", "project", "-project", "project_id", "-project_id", "updated_at", "-updated_at"]) -> "BoardQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "BoardQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "BoardQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "BoardQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"]) -> "BoardQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "BoardQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "BoardQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "BoardQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "BoardQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "BoardQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"]) -> "BoardQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "BoardQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"]) -> "BoardQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"], flat: bool = False) -> "BoardQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[Board]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Board | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Board | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class BoardManager(QueryManager[Board]): + """Type-safe Manager for Board model.""" + + # Query building methods (sync, return Query) + + def query(self) -> BoardQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + project: Project | None = None, + project__in: list[Project] | None = None, + project__isnull: bool | None = None, + project_id: int | None = None, + project_id__gt: int | None = None, + project_id__gte: int | None = None, + project_id__lt: int | None = None, + project_id__lte: int | None = None, + project_id__between: tuple[int, int] | None = None, + project_id__range: int | None = None, + project_id__in: list[int] | None = None, + project_id__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> BoardQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + project: Project | None = None, + project__in: list[Project] | None = None, + project__isnull: bool | None = None, + project_id: int | None = None, + project_id__gt: int | None = None, + project_id__gte: int | None = None, + project_id__lt: int | None = None, + project_id__lte: int | None = None, + project_id__between: tuple[int, int] | None = None, + project_id__range: int | None = None, + project_id__in: list[int] | None = None, + project_id__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> BoardQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"]) -> BoardQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["created_at", "description", "id", "name", "project", "project_id", "updated_at"], flat: bool = False) -> BoardQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> BoardQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> BoardQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> BoardQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> BoardQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> BoardQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Board: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Board | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Board, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Board, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[Board]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Board | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Board | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: Board | None = None, + client: Any | None = None, + using: str | None = None, + created_at: datetime | None = None, + description: str | None = None, + id: int | None = None, + name: str | None = None, + project: Project | None = None, + project_id: int | None = None, + updated_at: datetime | None = None, + ) -> Board: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[Board], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[Board]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[Board], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + + +class Column(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + board: Board | None + name: str + position: int + created_at: datetime | None + updated_at: datetime | None + board_id: int | None + objects: ClassVar["ColumnManager"] + + +class ColumnQuery(Query[Column]): + """Type-safe Query for Column model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + board: Board | None = None, + board__in: list[Board] | None = None, + board__isnull: bool | None = None, + board_id: int | None = None, + board_id__gt: int | None = None, + board_id__gte: int | None = None, + board_id__lt: int | None = None, + board_id__lte: int | None = None, + board_id__between: tuple[int, int] | None = None, + board_id__range: int | None = None, + board_id__in: list[int] | None = None, + board_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "ColumnQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + board: Board | None = None, + board__in: list[Board] | None = None, + board__isnull: bool | None = None, + board_id: int | None = None, + board_id__gt: int | None = None, + board_id__gte: int | None = None, + board_id__lt: int | None = None, + board_id__lte: int | None = None, + board_id__between: tuple[int, int] | None = None, + board_id__range: int | None = None, + board_id__in: list[int] | None = None, + board_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "ColumnQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["board", "-board", "board_id", "-board_id", "created_at", "-created_at", "id", "-id", "name", "-name", "position", "-position", "updated_at", "-updated_at"]) -> "ColumnQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "ColumnQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "ColumnQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "ColumnQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"]) -> "ColumnQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "ColumnQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "ColumnQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "ColumnQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "ColumnQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "ColumnQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"]) -> "ColumnQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "ColumnQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"]) -> "ColumnQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"], flat: bool = False) -> "ColumnQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[Column]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Column | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Column | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class ColumnManager(QueryManager[Column]): + """Type-safe Manager for Column model.""" + + # Query building methods (sync, return Query) + + def query(self) -> ColumnQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + board: Board | None = None, + board__in: list[Board] | None = None, + board__isnull: bool | None = None, + board_id: int | None = None, + board_id__gt: int | None = None, + board_id__gte: int | None = None, + board_id__lt: int | None = None, + board_id__lte: int | None = None, + board_id__between: tuple[int, int] | None = None, + board_id__range: int | None = None, + board_id__in: list[int] | None = None, + board_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> ColumnQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + board: Board | None = None, + board__in: list[Board] | None = None, + board__isnull: bool | None = None, + board_id: int | None = None, + board_id__gt: int | None = None, + board_id__gte: int | None = None, + board_id__lt: int | None = None, + board_id__lte: int | None = None, + board_id__between: tuple[int, int] | None = None, + board_id__range: int | None = None, + board_id__in: list[int] | None = None, + board_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + name: str | None = None, + name__contains: str | None = None, + name__icontains: str | None = None, + name__startswith: str | None = None, + name__istartswith: str | None = None, + name__endswith: str | None = None, + name__iendswith: str | None = None, + name__iexact: str | None = None, + name__in: list[str] | None = None, + name__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> ColumnQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"]) -> ColumnQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["board", "board_id", "created_at", "id", "name", "position", "updated_at"], flat: bool = False) -> ColumnQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> ColumnQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> ColumnQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> ColumnQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> ColumnQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> ColumnQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Column: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Column | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Column, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Column, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[Column]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Column | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Column | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: Column | None = None, + client: Any | None = None, + using: str | None = None, + board: Board | None = None, + board_id: int | None = None, + created_at: datetime | None = None, + id: int | None = None, + name: str | None = None, + position: int | None = None, + updated_at: datetime | None = None, + ) -> Column: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[Column], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[Column]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[Column], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + + +class Task(Model): + class Meta: + is_table: bool + table_name: str + id: int | None + column: Column | None + title: str + description: str | None + position: int + assignee: User | None + parent: Task | None + created_at: datetime | None + updated_at: datetime | None + column_id: int | None + assignee_id: int | None + parent_id: int | None + objects: ClassVar["TaskManager"] + + +class TaskQuery(Query[Task]): + """Type-safe Query for Task model.""" + + # Query building methods (sync, return Query) + + def filter( + self, + *args: Any, + assignee: User | None = None, + assignee__in: list[User] | None = None, + assignee__isnull: bool | None = None, + assignee_id: int | None = None, + assignee_id__gt: int | None = None, + assignee_id__gte: int | None = None, + assignee_id__lt: int | None = None, + assignee_id__lte: int | None = None, + assignee_id__between: tuple[int, int] | None = None, + assignee_id__range: int | None = None, + assignee_id__in: list[int] | None = None, + assignee_id__isnull: bool | None = None, + column: Column | None = None, + column__in: list[Column] | None = None, + column__isnull: bool | None = None, + column_id: int | None = None, + column_id__gt: int | None = None, + column_id__gte: int | None = None, + column_id__lt: int | None = None, + column_id__lte: int | None = None, + column_id__between: tuple[int, int] | None = None, + column_id__range: int | None = None, + column_id__in: list[int] | None = None, + column_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + parent: Task | None = None, + parent__in: list[Task] | None = None, + parent__isnull: bool | None = None, + parent_id: int | None = None, + parent_id__gt: int | None = None, + parent_id__gte: int | None = None, + parent_id__lt: int | None = None, + parent_id__lte: int | None = None, + parent_id__between: tuple[int, int] | None = None, + parent_id__range: int | None = None, + parent_id__in: list[int] | None = None, + parent_id__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + title: str | None = None, + title__contains: str | None = None, + title__icontains: str | None = None, + title__startswith: str | None = None, + title__istartswith: str | None = None, + title__endswith: str | None = None, + title__iendswith: str | None = None, + title__iexact: str | None = None, + title__in: list[str] | None = None, + title__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "TaskQuery": + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + assignee: User | None = None, + assignee__in: list[User] | None = None, + assignee__isnull: bool | None = None, + assignee_id: int | None = None, + assignee_id__gt: int | None = None, + assignee_id__gte: int | None = None, + assignee_id__lt: int | None = None, + assignee_id__lte: int | None = None, + assignee_id__between: tuple[int, int] | None = None, + assignee_id__range: int | None = None, + assignee_id__in: list[int] | None = None, + assignee_id__isnull: bool | None = None, + column: Column | None = None, + column__in: list[Column] | None = None, + column__isnull: bool | None = None, + column_id: int | None = None, + column_id__gt: int | None = None, + column_id__gte: int | None = None, + column_id__lt: int | None = None, + column_id__lte: int | None = None, + column_id__between: tuple[int, int] | None = None, + column_id__range: int | None = None, + column_id__in: list[int] | None = None, + column_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + parent: Task | None = None, + parent__in: list[Task] | None = None, + parent__isnull: bool | None = None, + parent_id: int | None = None, + parent_id__gt: int | None = None, + parent_id__gte: int | None = None, + parent_id__lt: int | None = None, + parent_id__lte: int | None = None, + parent_id__between: tuple[int, int] | None = None, + parent_id__range: int | None = None, + parent_id__in: list[int] | None = None, + parent_id__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + title: str | None = None, + title__contains: str | None = None, + title__icontains: str | None = None, + title__startswith: str | None = None, + title__istartswith: str | None = None, + title__endswith: str | None = None, + title__iendswith: str | None = None, + title__iexact: str | None = None, + title__in: list[str] | None = None, + title__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> "TaskQuery": + """Exclude objects matching field lookups.""" + ... + + def order_by(self, *fields: Literal["assignee", "-assignee", "assignee_id", "-assignee_id", "column", "-column", "column_id", "-column_id", "created_at", "-created_at", "description", "-description", "id", "-id", "parent", "-parent", "parent_id", "-parent_id", "position", "-position", "title", "-title", "updated_at", "-updated_at"]) -> "TaskQuery": # type: ignore[override] + """Order results by fields.""" + ... + + def limit(self, n: int) -> "TaskQuery": + """Limit number of results.""" + ... + + def offset(self, n: int) -> "TaskQuery": + """Skip first n results.""" + ... + + def distinct(self, value: bool = True) -> "TaskQuery": + """Return distinct results.""" + ... + + def select(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"]) -> "TaskQuery": # type: ignore[override] + """Select specific fields.""" + ... + + def join(self, *paths: str) -> "TaskQuery": + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> "TaskQuery": + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> "TaskQuery": + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> "TaskQuery": + """Add FOR SHARE lock to query.""" + ... + + def annotate(self, **annotations: Any) -> "TaskQuery": + """Add computed fields using aggregate functions.""" + ... + + def group_by(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"]) -> "TaskQuery": # type: ignore[override] + """Add GROUP BY clause.""" + ... + + def having(self, *q_exprs: Any, **kwargs: Any) -> "TaskQuery": + """Add HAVING clause for filtering grouped results.""" + ... + + def values(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"]) -> "TaskQuery": # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"], flat: bool = False) -> "TaskQuery": # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + # Terminal methods (async, execute query) + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> list[Task]: + """Execute query and return all results.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Task | None: + """Execute query and return first result.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Task | None: + """Execute query and return last result.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count matching objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def update( # type: ignore[override] + self, + *, + client: Any | None = None, + using: str | None = None, + **values: Any, + ) -> int: + """Update matching objects.""" + ... + + async def increment( + self, + field: str, + by: int | float = 1, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Atomically increment a field value.""" + ... + + async def delete( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Delete matching objects.""" + ... + +class TaskManager(QueryManager[Task]): + """Type-safe Manager for Task model.""" + + # Query building methods (sync, return Query) + + def query(self) -> TaskQuery: + """Return a Query builder for this model.""" + ... + + def filter( + self, + *args: Any, + assignee: User | None = None, + assignee__in: list[User] | None = None, + assignee__isnull: bool | None = None, + assignee_id: int | None = None, + assignee_id__gt: int | None = None, + assignee_id__gte: int | None = None, + assignee_id__lt: int | None = None, + assignee_id__lte: int | None = None, + assignee_id__between: tuple[int, int] | None = None, + assignee_id__range: int | None = None, + assignee_id__in: list[int] | None = None, + assignee_id__isnull: bool | None = None, + column: Column | None = None, + column__in: list[Column] | None = None, + column__isnull: bool | None = None, + column_id: int | None = None, + column_id__gt: int | None = None, + column_id__gte: int | None = None, + column_id__lt: int | None = None, + column_id__lte: int | None = None, + column_id__between: tuple[int, int] | None = None, + column_id__range: int | None = None, + column_id__in: list[int] | None = None, + column_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + parent: Task | None = None, + parent__in: list[Task] | None = None, + parent__isnull: bool | None = None, + parent_id: int | None = None, + parent_id__gt: int | None = None, + parent_id__gte: int | None = None, + parent_id__lt: int | None = None, + parent_id__lte: int | None = None, + parent_id__between: tuple[int, int] | None = None, + parent_id__range: int | None = None, + parent_id__in: list[int] | None = None, + parent_id__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + title: str | None = None, + title__contains: str | None = None, + title__icontains: str | None = None, + title__startswith: str | None = None, + title__istartswith: str | None = None, + title__endswith: str | None = None, + title__iendswith: str | None = None, + title__iexact: str | None = None, + title__in: list[str] | None = None, + title__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> TaskQuery: + """Filter by Q-expressions or field lookups.""" + ... + + def exclude( + self, + *args: Any, + assignee: User | None = None, + assignee__in: list[User] | None = None, + assignee__isnull: bool | None = None, + assignee_id: int | None = None, + assignee_id__gt: int | None = None, + assignee_id__gte: int | None = None, + assignee_id__lt: int | None = None, + assignee_id__lte: int | None = None, + assignee_id__between: tuple[int, int] | None = None, + assignee_id__range: int | None = None, + assignee_id__in: list[int] | None = None, + assignee_id__isnull: bool | None = None, + column: Column | None = None, + column__in: list[Column] | None = None, + column__isnull: bool | None = None, + column_id: int | None = None, + column_id__gt: int | None = None, + column_id__gte: int | None = None, + column_id__lt: int | None = None, + column_id__lte: int | None = None, + column_id__between: tuple[int, int] | None = None, + column_id__range: int | None = None, + column_id__in: list[int] | None = None, + column_id__isnull: bool | None = None, + created_at: datetime | None = None, + created_at__gt: datetime | None = None, + created_at__gte: datetime | None = None, + created_at__lt: datetime | None = None, + created_at__lte: datetime | None = None, + created_at__between: tuple[datetime, datetime] | None = None, + created_at__range: datetime | None = None, + created_at__year: int | None = None, + created_at__month: int | None = None, + created_at__day: int | None = None, + created_at__in: list[datetime] | None = None, + created_at__isnull: bool | None = None, + description: str | None = None, + description__contains: str | None = None, + description__icontains: str | None = None, + description__startswith: str | None = None, + description__istartswith: str | None = None, + description__endswith: str | None = None, + description__iendswith: str | None = None, + description__iexact: str | None = None, + description__in: list[str] | None = None, + description__isnull: bool | None = None, + id: int | None = None, + id__gt: int | None = None, + id__gte: int | None = None, + id__lt: int | None = None, + id__lte: int | None = None, + id__between: tuple[int, int] | None = None, + id__range: int | None = None, + id__in: list[int] | None = None, + id__isnull: bool | None = None, + parent: Task | None = None, + parent__in: list[Task] | None = None, + parent__isnull: bool | None = None, + parent_id: int | None = None, + parent_id__gt: int | None = None, + parent_id__gte: int | None = None, + parent_id__lt: int | None = None, + parent_id__lte: int | None = None, + parent_id__between: tuple[int, int] | None = None, + parent_id__range: int | None = None, + parent_id__in: list[int] | None = None, + parent_id__isnull: bool | None = None, + position: int | None = None, + position__gt: int | None = None, + position__gte: int | None = None, + position__lt: int | None = None, + position__lte: int | None = None, + position__between: tuple[int, int] | None = None, + position__range: int | None = None, + position__in: list[int] | None = None, + position__isnull: bool | None = None, + title: str | None = None, + title__contains: str | None = None, + title__icontains: str | None = None, + title__startswith: str | None = None, + title__istartswith: str | None = None, + title__endswith: str | None = None, + title__iendswith: str | None = None, + title__iexact: str | None = None, + title__in: list[str] | None = None, + title__isnull: bool | None = None, + updated_at: datetime | None = None, + updated_at__gt: datetime | None = None, + updated_at__gte: datetime | None = None, + updated_at__lt: datetime | None = None, + updated_at__lte: datetime | None = None, + updated_at__between: tuple[datetime, datetime] | None = None, + updated_at__range: datetime | None = None, + updated_at__year: int | None = None, + updated_at__month: int | None = None, + updated_at__day: int | None = None, + updated_at__in: list[datetime] | None = None, + updated_at__isnull: bool | None = None, + ) -> TaskQuery: + """Exclude objects matching field lookups.""" + ... + + def values(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"]) -> TaskQuery: # type: ignore[override] + """Return dicts instead of models.""" + ... + + def values_list(self, *fields: Literal["assignee", "assignee_id", "column", "column_id", "created_at", "description", "id", "parent", "parent_id", "position", "title", "updated_at"], flat: bool = False) -> TaskQuery: # type: ignore[override] + """Return tuples/values instead of models.""" + ... + + def distinct(self, distinct: bool = True) -> TaskQuery: + """Return distinct results.""" + ... + + def join(self, *paths: str) -> TaskQuery: + """Perform LEFT JOIN for relations.""" + ... + + def prefetch(self, *paths: str) -> TaskQuery: + """Prefetch related objects (separate queries).""" + ... + + def for_update(self) -> TaskQuery: + """Add FOR UPDATE lock to query.""" + ... + + def for_share(self) -> TaskQuery: + """Add FOR SHARE lock to query.""" + ... + + # Terminal methods (async, execute query) + + async def get( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Task: + """Get single object matching lookups.""" + ... + + async def get_or_none( + self, + *, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> Task | None: + """Get object or None if not found.""" + ... + + async def get_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Task, bool]: + """Get object or create if not found. Returns (object, created).""" + ... + + async def update_or_create( + self, + *, + defaults: dict[str, Any] | None = None, + client: Any | None = None, + using: str | None = None, + **filters: Any, + ) -> tuple[Task, bool]: + """Get object, create if missing, or update it when defaults are provided.""" + ... + + async def all( + self, + *, + client: Any | None = None, + using: str | None = None, + mode: str = "models", + ) -> list[Task]: + """Get all objects.""" + ... + + async def first( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Task | None: + """Get first object.""" + ... + + async def last( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> Task | None: + """Get last object.""" + ... + + async def count( + self, + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Count all objects.""" + ... + + async def sum( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate sum of field values.""" + ... + + async def avg( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Calculate average of field values.""" + ... + + async def max( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get maximum field value.""" + ... + + async def min( + self, + field: str, + *, + client: Any | None = None, + using: str | None = None, + ) -> Any: + """Get minimum field value.""" + ... + + async def create( # type: ignore[override] + self, + *, + instance: Task | None = None, + client: Any | None = None, + using: str | None = None, + assignee: User | None = None, + assignee_id: int | None = None, + column: Column | None = None, + column_id: int | None = None, + created_at: datetime | None = None, + description: str | None = None, + id: int | None = None, + parent: Task | None = None, + parent_id: int | None = None, + position: int | None = None, + title: str | None = None, + updated_at: datetime | None = None, + ) -> Task: + """Create new object.""" + ... + + async def bulk_create( # type: ignore[override] + self, + objects: list[Task], + *, + batch_size: int | None = None, + client: Any | None = None, + using: str | None = None, + ) -> list[Task]: + """Bulk create objects.""" + ... + + async def bulk_update( # type: ignore[override] + self, + objects: list[Task], + fields: list[str], + *, + client: Any | None = None, + using: str | None = None, + ) -> int: + """Bulk update objects.""" + ... + diff --git a/freenit/permissions.py b/freenit/permissions.py index 7aca7e3..5d09c0c 100644 --- a/freenit/permissions.py +++ b/freenit/permissions.py @@ -4,6 +4,7 @@ group_perms = permissions() mailinglist_perms = permissions() profile_perms = permissions() +project_perms = permissions() role_perms = permissions() theme_perms = permissions() user_perms = permissions() diff --git a/migrations/0004_add_project_kanban.py b/migrations/0004_add_project_kanban.py new file mode 100644 index 0000000..b7b85f5 --- /dev/null +++ b/migrations/0004_add_project_kanban.py @@ -0,0 +1,483 @@ +"""Auto-generated migration. + +Created: 2026-06-19 21:10:05 +""" + +depends_on = "0003_create_mailing_list_table" + + +def upgrade(ctx): + """Apply migration.""" + ctx.create_table( + "project", + fields=[ + { + 'name': 'id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': True, + 'unique': True, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'name', + 'python_type': 'str', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': True, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'description', + 'python_type': 'str', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'created_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'updated_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'created_by_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + } + ], + foreign_keys=[ + { + 'name': 'fk_project_created_by_id', + 'columns': [ + 'created_by_id' + ], + 'ref_table': 'user', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'SET NULL', + 'on_update': 'CASCADE' + } + ], + ) + ctx.create_table( + "board", + fields=[ + { + 'name': 'id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': True, + 'unique': True, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'name', + 'python_type': 'str', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'description', + 'python_type': 'str', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'created_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'updated_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'project_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + } + ], + foreign_keys=[ + { + 'name': 'fk_board_project_id', + 'columns': [ + 'project_id' + ], + 'ref_table': 'project', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'CASCADE', + 'on_update': 'CASCADE' + } + ], + indexes=[ + { + 'name': 'idx_board_project_id_name', + 'fields': ['project_id', 'name'], + 'unique': True, + } + ], + ) + ctx.create_table( + "board_column", + fields=[ + { + 'name': 'id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': True, + 'unique': True, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'name', + 'python_type': 'str', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'position', + 'python_type': 'int', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': False, + 'default': '0', + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'created_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'updated_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'board_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + } + ], + foreign_keys=[ + { + 'name': 'fk_board_column_board_id', + 'columns': [ + 'board_id' + ], + 'ref_table': 'board', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'CASCADE', + 'on_update': 'CASCADE' + } + ], + indexes=[ + { + 'name': 'idx_board_column_board_id_name', + 'fields': ['board_id', 'name'], + 'unique': True, + } + ], + ) + ctx.create_table( + "task", + fields=[ + { + 'name': 'id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': True, + 'unique': True, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'title', + 'python_type': 'str', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'description', + 'python_type': 'str', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'position', + 'python_type': 'int', + 'db_type': None, + 'nullable': False, + 'primary_key': False, + 'unique': False, + 'default': '0', + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'created_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'updated_at', + 'python_type': 'datetime', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'column_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'assignee_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + }, + { + 'name': 'parent_id', + 'python_type': 'int', + 'db_type': None, + 'nullable': True, + 'primary_key': False, + 'unique': False, + 'default': None, + 'auto_increment': False, + 'max_length': None, + 'max_digits': None, + 'decimal_places': None + } + ], + foreign_keys=[ + { + 'name': 'fk_task_column_id', + 'columns': [ + 'column_id' + ], + 'ref_table': 'board_column', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'CASCADE', + 'on_update': 'CASCADE' + }, + { + 'name': 'fk_task_assignee_id', + 'columns': [ + 'assignee_id' + ], + 'ref_table': 'user', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'SET NULL', + 'on_update': 'CASCADE' + }, + { + 'name': 'fk_task_parent_id', + 'columns': [ + 'parent_id' + ], + 'ref_table': 'task', + 'ref_columns': [ + 'id' + ], + 'on_delete': 'SET NULL', + 'on_update': 'CASCADE' + } + ], + ) + + +def downgrade(ctx): + """Revert migration.""" + ctx.drop_table("task") + ctx.drop_table("board_column") + ctx.drop_table("board") + ctx.drop_table("project") diff --git a/oxyde_config.py b/oxyde_config.py index 67972bf..7d20ecd 100644 --- a/oxyde_config.py +++ b/oxyde_config.py @@ -30,7 +30,11 @@ def database_dialect(): return detect_dialect(database_url()) -MODELS = ["freenit.models.sql.base"] +MODELS = [ + "freenit.models.sql.base", + "freenit.models.sql.mailinglist", + "freenit.models.sql.project", +] DIALECT = database_dialect() MIGRATIONS_DIR = "migrations" DATABASES = { diff --git a/tests/factories.py b/tests/factories.py index 990fdf3..cd6cb3f 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -2,6 +2,7 @@ from passlib.hash import pbkdf2_sha256 from freenit.config import getConfig +from freenit.models.project import Board, Column, Project, Task from freenit.models.role import Role as RoleModel config = getConfig() @@ -26,3 +27,41 @@ class Meta: model = RoleModel name = factory.Faker("pystr") + + +class ProjectFactory(factory.Factory): + class Meta: + model = Project + + name = factory.Faker("pystr") + description = factory.Faker("sentence") + created_by_id = None + + +class BoardFactory(factory.Factory): + class Meta: + model = Board + + name = factory.Faker("pystr") + description = factory.Faker("sentence") + project_id = None + + +class ColumnFactory(factory.Factory): + class Meta: + model = Column + + name = factory.Faker("pystr") + position = factory.Faker("random_int") + board_id = None + + +class TaskFactory(factory.Factory): + class Meta: + model = Task + + title = factory.Faker("pystr") + description = factory.Faker("sentence") + position = factory.Faker("random_int") + column_id = None + assignee_id = None diff --git a/tests/test_project.py b/tests/test_project.py new file mode 100644 index 0000000..79ddddc --- /dev/null +++ b/tests/test_project.py @@ -0,0 +1,407 @@ +import pytest + +from . import factories + + +@pytest.mark.asyncio +class TestProject: + async def test_create_project(self, client): + user = factories.User() + await user.save() + client.login(user=user) + data = {"name": "Test Project", "description": "A test project"} + response = client.post("/projects", data=data) + assert response.status_code == 200 + result = response.json() + assert result["name"] == data["name"] + assert result["description"] == data["description"] + assert result["created_by_id"] == user.id + + async def test_get_projects(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + response = client.get("/projects") + assert response.status_code == 200 + assert response.json()["total"] >= 1 + + async def test_get_project(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + response = client.get(f"/projects/{project.id}") + assert response.status_code == 200 + assert response.json()["id"] == project.id + + async def test_update_project(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + data = {"name": "Updated Project"} + response = client.patch(f"/projects/{project.id}", data=data) + assert response.status_code == 200 + assert response.json()["name"] == data["name"] + + async def test_delete_project(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + response = client.delete(f"/projects/{project.id}") + assert response.status_code == 200 + response = client.get(f"/projects/{project.id}") + assert response.status_code == 404 + + async def test_create_project_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(name="Unique Project", created_by_id=user.id) + await project.save() + response = client.post("/projects", data={"name": "Unique Project"}) + assert response.status_code == 409 + + async def test_update_project_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project1 = factories.ProjectFactory(name="Project One", created_by_id=user.id) + await project1.save() + project2 = factories.ProjectFactory(name="Project Two", created_by_id=user.id) + await project2.save() + response = client.patch(f"/projects/{project2.id}", data={"name": "Project One"}) + assert response.status_code == 409 + + +@pytest.mark.asyncio +class TestBoard: + async def test_create_board(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + data = {"name": "Test Board", "description": "A test board"} + response = client.post(f"/projects/{project.id}/boards", data=data) + assert response.status_code == 200 + result = response.json() + assert result["name"] == data["name"] + assert result["project_id"] == project.id + + async def test_get_boards(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + response = client.get(f"/projects/{project.id}/boards") + assert response.status_code == 200 + assert response.json()["total"] >= 1 + + async def test_get_board(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + response = client.get(f"/boards/{board.id}") + assert response.status_code == 200 + assert response.json()["id"] == board.id + + async def test_update_board(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + data = {"name": "Updated Board"} + response = client.patch(f"/boards/{board.id}", data=data) + assert response.status_code == 200 + assert response.json()["name"] == data["name"] + + async def test_delete_board(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + response = client.delete(f"/boards/{board.id}") + assert response.status_code == 200 + response = client.get(f"/boards/{board.id}") + assert response.status_code == 404 + + async def test_create_board_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id, name="Board X") + await board.save() + response = client.post( + f"/projects/{project.id}/boards", data={"name": "Board X"} + ) + assert response.status_code == 409 + + async def test_update_board_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board1 = factories.BoardFactory(project_id=project.id, name="Board One") + await board1.save() + board2 = factories.BoardFactory(project_id=project.id, name="Board Two") + await board2.save() + response = client.patch(f"/boards/{board2.id}", data={"name": "Board One"}) + assert response.status_code == 409 + + +@pytest.mark.asyncio +class TestColumn: + async def test_create_column(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + data = {"name": "To Do"} + response = client.post(f"/boards/{board.id}/columns", data=data) + assert response.status_code == 200 + result = response.json() + assert result["name"] == data["name"] + assert result["board_id"] == board.id + + async def test_get_columns(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + response = client.get(f"/boards/{board.id}/columns") + assert response.status_code == 200 + assert response.json()["total"] >= 1 + + async def test_update_column(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + data = {"name": "In Progress", "position": 5} + response = client.patch(f"/columns/{column.id}", data=data) + assert response.status_code == 200 + result = response.json() + assert result["name"] == data["name"] + assert result["position"] == data["position"] + + async def test_delete_column(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + response = client.delete(f"/columns/{column.id}") + assert response.status_code == 200 + response = client.get(f"/columns/{column.id}") + assert response.status_code == 404 + + async def test_create_column_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id, name="Column X") + await column.save() + response = client.post( + f"/boards/{board.id}/columns", data={"name": "Column X"} + ) + assert response.status_code == 409 + + async def test_update_column_duplicate_name(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column1 = factories.ColumnFactory(board_id=board.id, name="Column One") + await column1.save() + column2 = factories.ColumnFactory(board_id=board.id, name="Column Two") + await column2.save() + response = client.patch(f"/columns/{column2.id}", data={"name": "Column One"}) + assert response.status_code == 409 + + +@pytest.mark.asyncio +class TestTask: + async def test_create_task(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + data = {"title": "Test Task", "description": "A test task"} + response = client.post(f"/columns/{column.id}/tasks", data=data) + assert response.status_code == 200 + result = response.json() + assert result["title"] == data["title"] + assert result["column_id"] == column.id + + async def test_get_tasks(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + task = factories.TaskFactory(column_id=column.id) + await task.save() + response = client.get(f"/columns/{column.id}/tasks") + assert response.status_code == 200 + assert response.json()["total"] >= 1 + + async def test_get_task(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + task = factories.TaskFactory(column_id=column.id) + await task.save() + response = client.get(f"/tasks/{task.id}") + assert response.status_code == 200 + assert response.json()["id"] == task.id + + async def test_update_task(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + task = factories.TaskFactory(column_id=column.id) + await task.save() + data = {"title": "Updated Task"} + response = client.patch(f"/tasks/{task.id}", data=data) + assert response.status_code == 200 + assert response.json()["title"] == data["title"] + + async def test_move_task_between_columns(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column1 = factories.ColumnFactory(board_id=board.id) + await column1.save() + column2 = factories.ColumnFactory(board_id=board.id) + await column2.save() + task = factories.TaskFactory(column=column1) + await task.save() + data = {"column_id": column2.id} + response = client.patch(f"/tasks/{task.id}", data=data) + assert response.status_code == 200 + assert response.json()["column_id"] == column2.id + + async def test_delete_task(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + task = factories.TaskFactory(column_id=column.id) + await task.save() + response = client.delete(f"/tasks/{task.id}") + assert response.status_code == 200 + response = client.get(f"/tasks/{task.id}") + assert response.status_code == 404 + + async def test_create_task_with_parent(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + parent = factories.TaskFactory(column_id=column.id) + await parent.save() + response = client.post( + f"/columns/{column.id}/tasks", + data={"title": "Child Task", "parent_id": parent.id}, + ) + assert response.status_code == 200 + assert response.json()["parent_id"] == parent.id + + async def test_task_self_parent_rejected(self, client): + user = factories.User() + await user.save() + client.login(user=user) + project = factories.ProjectFactory(created_by_id=user.id) + await project.save() + board = factories.BoardFactory(project_id=project.id) + await board.save() + column = factories.ColumnFactory(board_id=board.id) + await column.save() + task = factories.TaskFactory(column_id=column.id) + await task.save() + response = client.patch( + f"/tasks/{task.id}", data={"parent_id": task.id} + ) + assert response.status_code == 400