feat(api): add lite list endpoints for projects, members, cycles, and modules#9410
feat(api): add lite list endpoints for projects, members, cycles, and modules#9410akhil-vamshi-konam wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughAdded lightweight paginated API endpoints for projects, cycles, modules, workspace members, and project members. Added lite serializers, routing, archived-record filtering, contract tests, and validation rejecting unsupported issue filters. ChangesLite API surface
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant API Route
participant Lite Endpoint
participant Database
participant Lite Serializer
Client->>API Route: GET lite collection
API Route->>Lite Endpoint: Dispatch request
Lite Endpoint->>Database: Query filtered records
Database-->>Lite Endpoint: Paginated records
Lite Endpoint->>Lite Serializer: Serialize results
Lite Serializer-->>Client: Paginated lite response
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (5)
apps/api/plane/tests/contract/api/test_members_lite.py (1)
86-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding error-scenario and role-assertion tests for
TestProjectMembersLite.
TestWorkspaceMembersLiteincludestest_unknown_workspace_is_rejectedand assertsitem["role"] == 20intest_lite_member_shape.TestProjectMembersLitehas neither — no test for unknown workspace/project rejection, andtest_lite_member_shapedoesn't verify the role value. Adding these would match the workspace test coverage.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/plane/tests/contract/api/test_members_lite.py` around lines 86 - 102, Extend TestProjectMembersLite with an unknown workspace/project rejection test matching TestWorkspaceMembersLite, using the existing URL helper and expected error status. Update test_lite_member_shape to assert the returned member’s role equals 20, while preserving the existing field-presence checks.apps/api/plane/tests/contract/api/test_modules_lite.py (1)
52-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider asserting the lite field shape.
Same gap as
test_cycles_lite.py: the test verifies pagination and archived exclusion but does not assert the lite field set. Adding field-shape assertions (liketest_projects_lite.pydoes) would verify the "lite" contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/plane/tests/contract/api/test_modules_lite.py` around lines 52 - 61, Update TestModulesLite.test_paginated_and_excludes_archived to assert that each returned module contains exactly the expected lite response fields, following the field-shape assertion pattern used by the related lite contract tests. Keep the existing pagination, status, and archived-module assertions unchanged.apps/api/plane/tests/contract/api/test_cycles_lite.py (2)
63-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider asserting the lite field shape.
The test verifies pagination and archived exclusion but does not assert which fields are present or absent in the response items.
test_projects_lite.pyincludestest_returns_only_lite_fieldsthat checks the lite field set and confirms heavy fields liketotal_membersare absent. Adding a similar assertion here would verify the "lite" contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/plane/tests/contract/api/test_cycles_lite.py` around lines 63 - 72, Update TestCyclesLite.test_paginated_and_excludes_archived to assert each returned cycle item matches the lite response field set, including that heavy fields such as total_members are absent. Reuse the established field-shape assertion pattern from test_projects_lite.py while preserving the existing pagination and archived-cycle checks.
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winContract tests for cycles-lite and modules-lite don't verify the lite field shape. Both tests assert pagination and archived exclusion but omit field-shape checks — the "lite" contract (which fields are present/absent) is untested.
test_projects_lite.pyincludestest_returns_only_lite_fieldsthat checks the lite field set and confirms heavy fields are absent.
apps/api/plane/tests/contract/api/test_cycles_lite.py#L63-72: Add assertions verifying lite fields present (e.g.,id,name,start_date,end_date) and computed/heavy fields absent.apps/api/plane/tests/contract/api/test_modules_lite.py#L52-61: Add similar field-shape assertions for the modules-lite response items.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/plane/tests/contract/api/test_cycles_lite.py` at line 1, Update the cycles-lite and modules-lite contract tests, specifically their response-item assertions near the existing pagination and archived-exclusion checks, to verify the expected lite fields are present and computed/heavy fields are absent. Mirror the field-shape validation used by test_returns_only_lite_fields in test_projects_lite.py, covering representative fields such as id, name, start_date, and end_date where applicable.apps/api/plane/api/views/cycle.py (1)
360-399: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
CycleLiteSerializerusesfields = "__all__", undermining the "lite" purpose.The serializer docstring says "minimal data transfer" but
fields = "__all__"serializes every Cycle model field (includingexternal_id,external_source,deleted_at, etc.). This is inconsistent withProjectLiteSerializer, which uses an explicit field list and excludes computed fields liketotal_members. Define an explicit minimal field set (e.g.,id,name,start_date,end_date,description,project,workspace,owned_by) to match the "lite" contract and prevent accidental exposure of future model fields.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/plane/api/views/cycle.py` around lines 360 - 399, The CycleLiteSerializer currently serializes all Cycle model fields, contradicting its lightweight contract. Update CycleLiteSerializer to use an explicit minimal fields list including id, name, start_date, end_date, description, project, workspace, and owned_by, excluding computed and internal fields and preventing future fields from being exposed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/plane/api/views/cycle.py`:
- Line 392: Update the cycle query ordering to pass the requested value through
the existing sanitize_order_by() helper before calling order_by(), preserving
"-created_at" as the default. Apply the same validation to the matching raw
request.GET order_by usage in the module and project endpoints.
In `@apps/api/plane/api/views/issue.py`:
- Around line 317-318: Update the unsupported_filters check in the issue-listing
view to detect whether “pql” or “filters” exists in request.GET, regardless of
its value. Preserve the existing 400 response for any supplied unsupported
parameter, including empty values.
In `@apps/api/plane/api/views/member.py`:
- Line 254: Align the non-existent workspace and project handling with the
documented OpenAPI responses: update the error returns in
WorkspaceMemberLiteAPIEndpoint and ProjectMemberLiteAPIEndpoint from HTTP 400 to
HTTP 404, preserving their existing not-found response payloads and schema
declarations.
- Around line 304-321: Add an explicit project existence check in the `get`
method before querying `project_members`, validating the project belongs to the
workspace identified by `slug`. Return the documented 404 response when no
matching project exists, while preserving the existing member listing behavior
for valid projects.
In `@apps/api/plane/api/views/project.py`:
- Line 416: Sanitize the lite endpoint ordering before passing it to
QuerySet.order_by(): in apps/api/plane/api/views/project.py:416, use
sanitize_order_by with PROJECT_ORDER_BY_ALLOWLIST and "-created_at" as the
default; in apps/api/plane/api/views/module.py:314, apply the same pattern with
the module-specific order-by allowlist and appropriate default, preserving
graceful fallback for invalid input.
- Around line 401-405: Update the workspace existence check in the project view
to return HTTP 404 when the Workspace lookup by slug fails, matching the 404
response declared by the project_docs schema; leave the error payload unchanged.
---
Nitpick comments:
In `@apps/api/plane/api/views/cycle.py`:
- Around line 360-399: The CycleLiteSerializer currently serializes all Cycle
model fields, contradicting its lightweight contract. Update CycleLiteSerializer
to use an explicit minimal fields list including id, name, start_date, end_date,
description, project, workspace, and owned_by, excluding computed and internal
fields and preventing future fields from being exposed.
In `@apps/api/plane/tests/contract/api/test_cycles_lite.py`:
- Around line 63-72: Update TestCyclesLite.test_paginated_and_excludes_archived
to assert each returned cycle item matches the lite response field set,
including that heavy fields such as total_members are absent. Reuse the
established field-shape assertion pattern from test_projects_lite.py while
preserving the existing pagination and archived-cycle checks.
- Line 1: Update the cycles-lite and modules-lite contract tests, specifically
their response-item assertions near the existing pagination and
archived-exclusion checks, to verify the expected lite fields are present and
computed/heavy fields are absent. Mirror the field-shape validation used by
test_returns_only_lite_fields in test_projects_lite.py, covering representative
fields such as id, name, start_date, and end_date where applicable.
In `@apps/api/plane/tests/contract/api/test_members_lite.py`:
- Around line 86-102: Extend TestProjectMembersLite with an unknown
workspace/project rejection test matching TestWorkspaceMembersLite, using the
existing URL helper and expected error status. Update test_lite_member_shape to
assert the returned member’s role equals 20, while preserving the existing
field-presence checks.
In `@apps/api/plane/tests/contract/api/test_modules_lite.py`:
- Around line 52-61: Update TestModulesLite.test_paginated_and_excludes_archived
to assert that each returned module contains exactly the expected lite response
fields, following the field-shape assertion pattern used by the related lite
contract tests. Keep the existing pagination, status, and archived-module
assertions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9947e3d4-3777-4ea9-aec7-846b5b2293b1
📒 Files selected for processing (17)
apps/api/plane/api/serializers/__init__.pyapps/api/plane/api/serializers/member.pyapps/api/plane/api/serializers/project.pyapps/api/plane/api/urls/cycle.pyapps/api/plane/api/urls/member.pyapps/api/plane/api/urls/module.pyapps/api/plane/api/urls/project.pyapps/api/plane/api/views/__init__.pyapps/api/plane/api/views/cycle.pyapps/api/plane/api/views/issue.pyapps/api/plane/api/views/member.pyapps/api/plane/api/views/module.pyapps/api/plane/api/views/project.pyapps/api/plane/tests/contract/api/test_cycles_lite.pyapps/api/plane/tests/contract/api/test_members_lite.pyapps/api/plane/tests/contract/api/test_modules_lite.pyapps/api/plane/tests/contract/api/test_projects_lite.py
| Cycle.objects.filter(workspace__slug=slug, project_id=project_id) | ||
| .filter(archived_at__isnull=True) | ||
| .select_related("project", "workspace", "owned_by") | ||
| .order_by(request.GET.get("order_by", "-created_at")) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether ORDER_BY_PARAMETER has an enum constraint or any runtime validation exists.
rg -n "ORDER_BY_PARAMETER" --type=py -A5 apps/api/plane/utils/openapi.py
# Also check if FieldError is handled anywhere in the base views.
rg -n "FieldError" --type=py apps/api/plane/api/views/Repository: makeplane/plane
Length of output: 225
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate relevant files and inspect the order_by handling plus any FieldError handling.
fd -a "cycle.py|base.py|openapi.py" apps/api/plane -t f || true
echo '--- rg sanitize_order_by ---'
rg -n "sanitize_order_by|order_by\\(" apps/api/plane/api/views apps/api/plane -g '*.py' || true
echo '--- rg FieldError ---'
rg -n "FieldError" apps/api/plane -g '*.py' || trueRepository: makeplane/plane
Length of output: 39733
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the specific view file around the reported line once located.
fd -a "cycle.py" apps -t f || trueRepository: makeplane/plane
Length of output: 659
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the cycle view around the reported line and the base exception handler.
sed -n '360,420p' /home/jailuser/git/apps/api/plane/api/views/cycle.py | cat -n
echo '--- base handler ---'
sed -n '1,220p' /home/jailuser/git/apps/api/plane/api/views/base.py | cat -n
echo '--- order sanitizer ---'
sed -n '1,220p' /home/jailuser/git/apps/api/plane/utils/order_queryset.py | cat -nRepository: makeplane/plane
Length of output: 18406
Validate order_by before passing it to .order_by()
request.GET.get("order_by", "-created_at") still reaches .order_by() directly here, so an invalid field can raise FieldError and fall through the generic 500 path. Reuse sanitize_order_by() here; the same raw pattern also appears in the module and project endpoints.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/cycle.py` at line 392, Update the cycle query
ordering to pass the requested value through the existing sanitize_order_by()
helper before calling order_by(), preserving "-created_at" as the default. Apply
the same validation to the matching raw request.GET order_by usage in the module
and project endpoints.
| unsupported_filters = [param for param in ("pql", "filters") if request.GET.get(param)] | ||
| if unsupported_filters: |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Reject unsupported parameters by presence, not truthiness.
request.GET.get(param) skips empty-but-supplied values, so requests such as ?pql= or ?filters= continue into normal issue listing instead of returning the documented 400. Check membership in the query parameters instead.
Proposed fix
- unsupported_filters = [param for param in ("pql", "filters") if request.GET.get(param)]
+ unsupported_filters = [param for param in ("pql", "filters") if param in request.GET]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| unsupported_filters = [param for param in ("pql", "filters") if request.GET.get(param)] | |
| if unsupported_filters: | |
| unsupported_filters = [param for param in ("pql", "filters") if param in request.GET] | |
| if unsupported_filters: |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/issue.py` around lines 317 - 318, Update the
unsupported_filters check in the issue-listing view to detect whether “pql” or
“filters” exists in request.GET, regardless of its value. Preserve the existing
400 response for any supplied unsupported parameter, including empty values.
| ), | ||
| 401: UNAUTHORIZED_RESPONSE, | ||
| 403: FORBIDDEN_RESPONSE, | ||
| 404: WORKSPACE_NOT_FOUND_RESPONSE, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
OpenAPI schema documents 404 but code returns 400 for non-existent workspace.
Both WorkspaceMemberLiteAPIEndpoint (line 254: 404: WORKSPACE_NOT_FOUND_RESPONSE) and ProjectMemberLiteAPIEndpoint (line 301: 404: PROJECT_NOT_FOUND_RESPONSE) document 404 responses, but the actual code at lines 264-268 and 311-315 returns status.HTTP_400_BAD_REQUEST. API consumers relying on the schema would expect 404 and receive 400 instead. Either change the responses to 404 (matching REST conventions for "not found") or update the schema to document 400.
Also applies to: 301-301
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/member.py` at line 254, Align the non-existent
workspace and project handling with the documented OpenAPI responses: update the
error returns in WorkspaceMemberLiteAPIEndpoint and ProjectMemberLiteAPIEndpoint
from HTTP 400 to HTTP 404, preserving their existing not-found response payloads
and schema declarations.
| def get(self, request, slug, project_id): | ||
| """List project members (lite) | ||
|
|
||
| Retrieve a paginated, lightweight list of project members, optimized for | ||
| pickers and directories. | ||
| """ | ||
| # Check if the workspace exists | ||
| if not Workspace.objects.filter(slug=slug).exists(): | ||
| return Response( | ||
| {"error": "Provided workspace does not exist"}, | ||
| status=status.HTTP_400_BAD_REQUEST, | ||
| ) | ||
|
|
||
| project_members = ( | ||
| ProjectMember.objects.filter(project_id=project_id, workspace__slug=slug) | ||
| .select_related("member") | ||
| .order_by("-created_at") | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if ProjectMemberPermission validates project existence and what exception it raises.
rg -n "class ProjectMemberPermission" --type=py -A30 apps/api/plane/utils/permissions.pyRepository: makeplane/plane
Length of output: 229
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the permission class and the lite endpoint implementation.
git ls-files | rg 'member\.py$|permissions\.py$|project.*member|ProjectMember'
rg -n "class ProjectMemberPermission|ProjectMemberLiteAPIEndpoint|def get\(self, request, slug, project_id\)" apps/api -SRepository: makeplane/plane
Length of output: 4263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the lite endpoint and the matching permission class.
sed -n '280,340p' apps/api/plane/api/views/member.py
printf '\n---\n'
sed -n '1,180p' apps/api/plane/utils/permissions/project.py
printf '\n---\n'
sed -n '1,220p' apps/api/plane/app/permissions/project.pyRepository: makeplane/plane
Length of output: 12256
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether the lite endpoint uses ProjectMemberPermission and how exceptions are handled.
sed -n '240,320p' apps/api/plane/api/views/member.py
printf '\n---\n'
sed -n '1,220p' apps/api/plane/api/views/base.py
printf '\n---\n'
rg -n "DoesNotExist|handle_exception" apps/api/plane/api/views/base.py apps/api/plane/api/views -SRepository: makeplane/plane
Length of output: 12844
Add an explicit project existence check here. ProjectMemberPermission only enforces access; it doesn’t raise on a missing project_id, so an invalid project in an existing workspace can still return 200 with an empty list instead of the documented 404.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/member.py` around lines 304 - 321, Add an explicit
project existence check in the `get` method before querying `project_members`,
validating the project belongs to the workspace identified by `slug`. Return the
documented 404 response when no matching project exists, while preserving the
existing member listing behavior for valid projects.
| if not Workspace.objects.filter(slug=slug).exists(): | ||
| return Response( | ||
| {"error": "Provided workspace does not exist"}, | ||
| status=status.HTTP_400_BAD_REQUEST, | ||
| ) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Status code mismatch: workspace-not-found returns 400 but schema documents 404.
The @project_docs response map declares 404: WORKSPACE_NOT_FOUND_RESPONSE, but the handler returns HTTP_400_BAD_REQUEST. Clients relying on the OpenAPI contract will expect 404 and may not handle 400 correctly.
🔧 Proposed fix: return 404 to match the documented contract
if not Workspace.objects.filter(slug=slug).exists():
return Response(
{"error": "Provided workspace does not exist"},
- status=status.HTTP_400_BAD_REQUEST,
+ status=status.HTTP_404_NOT_FOUND,
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if not Workspace.objects.filter(slug=slug).exists(): | |
| return Response( | |
| {"error": "Provided workspace does not exist"}, | |
| status=status.HTTP_400_BAD_REQUEST, | |
| ) | |
| if not Workspace.objects.filter(slug=slug).exists(): | |
| return Response( | |
| {"error": "Provided workspace does not exist"}, | |
| status=status.HTTP_404_NOT_FOUND, | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/project.py` around lines 401 - 405, Update the
workspace existence check in the project view to return HTTP 404 when the
Workspace lookup by slug fails, matching the 404 response declared by the
project_docs schema; leave the error payload unchanged.
| if not include_archived: | ||
| projects = projects.filter(archived_at__isnull=True) | ||
|
|
||
| projects = projects.order_by(request.GET.get("order_by", "-created_at")) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Unsanitized order_by in lite endpoints causes 500 errors on invalid input. Both lite endpoints pass raw request.GET.get("order_by", "-created_at") directly to QuerySet.order_by(). Invalid field names raise Django FieldError, caught by BaseAPIView.handle_exception as a generic 500. The existing ProjectListCreateAPIEndpoint in the same file already uses sanitize_order_by() with an allowlist and graceful default — the lite endpoints should follow the same pattern.
apps/api/plane/api/views/project.py#L416: replace raworder_bywithsanitize_order_by(request.GET.get("order_by", "-created_at"), PROJECT_ORDER_BY_ALLOWLIST, default="-created_at").apps/api/plane/api/views/module.py#L314: apply the equivalentsanitize_order_bycall with a module-appropriate allowlist.
📍 Affects 2 files
apps/api/plane/api/views/project.py#L416-L416(this comment)apps/api/plane/api/views/module.py#L314-L314
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/plane/api/views/project.py` at line 416, Sanitize the lite endpoint
ordering before passing it to QuerySet.order_by(): in
apps/api/plane/api/views/project.py:416, use sanitize_order_by with
PROJECT_ORDER_BY_ALLOWLIST and "-created_at" as the default; in
apps/api/plane/api/views/module.py:314, apply the same pattern with the
module-specific order-by allowlist and appropriate default, preserving graceful
fallback for invalid input.
Description
Adds lightweight, cursor-paginated list endpoints for projects, workspace members, project members, cycles, and modules to support picker/reference use cases with reduced payload sizes.
Changes
Added new lite endpoints:
GET /workspaces/{slug}/projects-lite/GET /workspaces/{slug}/members-lite/GET /workspaces/{slug}/projects/{project_id}/project-members-lite/GET /workspaces/{slug}/projects/{project_id}/cycles-lite/GET /workspaces/{slug}/projects/{project_id}/modules-lite/Introduced lightweight serializers for projects and members.
Added optional
include_archivedquery parameter for the projects-lite endpoint.Added OpenAPI documentation for all new endpoints.
Added contract tests covering response shape, pagination, archived filtering, and error scenarios.
Updated issue listing to return a clear
400response when unsupportedpqlorfiltersquery parameters are provided.Summary by CodeRabbit
New Features
Bug Fixes
Tests