diff --git a/apps/api/plane/app/views/issue/sub_issue.py b/apps/api/plane/app/views/issue/sub_issue.py index b52e07564f6..5194148dd7b 100644 --- a/apps/api/plane/app/views/issue/sub_issue.py +++ b/apps/api/plane/app/views/issue/sub_issue.py @@ -7,7 +7,7 @@ # Django imports from django.utils import timezone -from django.db.models import OuterRef, Func, F, Q, Value, UUIDField, Subquery +from django.db.models import OuterRef, Func, F, Q, Value, UUIDField, Subquery, Count, IntegerField from django.utils.decorators import method_decorator from django.views.decorators.gzip import gzip_page from django.contrib.postgres.aggregates import ArrayAgg @@ -22,7 +22,7 @@ from .. import BaseAPIView from plane.app.serializers import IssueSerializer from plane.app.permissions import ProjectEntityPermission -from plane.db.models import Issue, IssueLink, FileAsset, CycleIssue +from plane.db.models import Issue, IssueLink, FileAsset, CycleIssue, IssueLabel, IssueAssignee, ModuleIssue from plane.bgtasks.issue_activities_task import issue_activity from plane.utils.timezone_converter import user_timezone_converter from collections import defaultdict @@ -37,70 +37,97 @@ class SubIssuesEndpoint(BaseAPIView): def get(self, request, slug, project_id, issue_id): sub_issues = ( Issue.issue_objects.filter(parent_id=issue_id, workspace__slug=slug) - .select_related("workspace", "project", "state", "parent") - .prefetch_related("assignees", "labels", "issue_module__module") .annotate( cycle_id=Subquery( CycleIssue.objects.filter(issue=OuterRef("id"), deleted_at__isnull=True).values("cycle_id")[:1] ) ) .annotate( - link_count=IssueLink.objects.filter(issue=OuterRef("id")) - .order_by() - .annotate(count=Func(F("id"), function="Count")) - .values("count") + link_count=Coalesce( + Subquery( + IssueLink.objects.filter(issue=OuterRef("id")) + .order_by() + .values("issue") + .annotate(count=Count("id")) + .values("count"), + output_field=IntegerField(), + ), + 0, + ) ) .annotate( - attachment_count=FileAsset.objects.filter( - issue_id=OuterRef("id"), - entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT, + attachment_count=Coalesce( + Subquery( + FileAsset.objects.filter( + issue_id=OuterRef("id"), + entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT, + ) + .order_by() + .values("issue_id") + .annotate(count=Count("id")) + .values("count"), + output_field=IntegerField(), + ), + 0, ) - .order_by() - .annotate(count=Func(F("id"), function="Count")) - .values("count") ) .annotate( - sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id")) - .order_by() - .annotate(count=Func(F("id"), function="Count")) - .values("count") + sub_issues_count=Coalesce( + Subquery( + Issue.issue_objects.filter(parent=OuterRef("id")) + .order_by() + .values("parent") + .annotate(count=Count("id")) + .values("count"), + output_field=IntegerField(), + ), + 0, + ) ) .annotate( label_ids=Coalesce( - ArrayAgg( - "labels__id", - distinct=True, - filter=Q(~Q(labels__id__isnull=True) & Q(label_issue__deleted_at__isnull=True)), + Subquery( + IssueLabel.objects.filter(issue_id=OuterRef("id"), deleted_at__isnull=True) + .order_by() + .values("issue_id") + .annotate(arr=ArrayAgg("label_id", distinct=True)) + .values("arr"), + output_field=ArrayField(UUIDField()), ), Value([], output_field=ArrayField(UUIDField())), ), assignee_ids=Coalesce( - ArrayAgg( - "assignees__id", - distinct=True, - filter=Q( - ~Q(assignees__id__isnull=True) - & Q(assignees__member_project__is_active=True) - & Q(issue_assignee__deleted_at__isnull=True) - ), + Subquery( + IssueAssignee.objects.filter( + issue_id=OuterRef("id"), + assignee__member_project__is_active=True, + deleted_at__isnull=True, + ) + .order_by() + .values("issue_id") + .annotate(arr=ArrayAgg("assignee_id", distinct=True)) + .values("arr"), + output_field=ArrayField(UUIDField()), ), Value([], output_field=ArrayField(UUIDField())), ), module_ids=Coalesce( - ArrayAgg( - "issue_module__module_id", - distinct=True, - filter=Q( - ~Q(issue_module__module_id__isnull=True) - & Q(issue_module__module__archived_at__isnull=True) - & Q(issue_module__deleted_at__isnull=True) - ), + Subquery( + ModuleIssue.objects.filter( + issue_id=OuterRef("id"), + module__archived_at__isnull=True, + deleted_at__isnull=True, + ) + .order_by() + .values("issue_id") + .annotate(arr=ArrayAgg("module_id", distinct=True)) + .values("arr"), + output_field=ArrayField(UUIDField()), ), Value([], output_field=ArrayField(UUIDField())), ), ) .annotate(state_group=F("state__group")) - .order_by("-created_at") ) # Ordering @@ -110,38 +137,42 @@ def get(self, request, slug, project_id, issue_id): if order_by_param: sub_issues, order_by_param = order_issue_queryset(sub_issues, order_by_param) + sub_issues = list( + sub_issues.values( + "id", + "name", + "state_id", + "sort_order", + "completed_at", + "estimate_point", + "priority", + "start_date", + "target_date", + "sequence_id", + "project_id", + "parent_id", + "cycle_id", + "module_ids", + "label_ids", + "assignee_ids", + "sub_issues_count", + "created_at", + "updated_at", + "created_by", + "updated_by", + "attachment_count", + "link_count", + "is_draft", + "archived_at", + "state_group", + ) + ) + # create's a dict with state group name with their respective issue id's result = defaultdict(list) for sub_issue in sub_issues: - result[sub_issue.state_group].append(str(sub_issue.id)) + result[sub_issue["state_group"]].append(str(sub_issue["id"])) - sub_issues = sub_issues.values( - "id", - "name", - "state_id", - "sort_order", - "completed_at", - "estimate_point", - "priority", - "start_date", - "target_date", - "sequence_id", - "project_id", - "parent_id", - "cycle_id", - "module_ids", - "label_ids", - "assignee_ids", - "sub_issues_count", - "created_at", - "updated_at", - "created_by", - "updated_by", - "attachment_count", - "link_count", - "is_draft", - "archived_at", - ) datetime_fields = ["created_at", "updated_at"] sub_issues = user_timezone_converter(sub_issues, datetime_fields, request.user.user_timezone) # Grouping