Skip to content

Comments

refactor: structured query params (conditions + sorting) for tasks API#186

Open
LeeJMorel wants to merge 5 commits intodevfrom
refactor/structured-query-params
Open

refactor: structured query params (conditions + sorting) for tasks API#186
LeeJMorel wants to merge 5 commits intodevfrom
refactor/structured-query-params

Conversation

@LeeJMorel
Copy link
Member

@LeeJMorel LeeJMorel commented Feb 23, 2026

Summary

  • Replace ad-hoc filter query params (project_id, assignee_ids, tag_ids, etc.) with a structured JSON conditions parameter using FilterCondition[]
  • Replace simple sort_by/sort_dir string params with a structured JSON sorting parameter using SortField[] — enables multi-column sorting (e.g. date_group then due_date)
  • Add query parsing utilities (parse_conditions, parse_sort_fields) with security hardening (size limits, field count limits, JSON validation)
  • Both conditions and sorting follow the same pattern: JSON-encoded arrays of objects, auto-serialized by the Axios paramsSerializer

Notable changes

Backend:

  • New app/db/query.py — centralized query utilities for filtering, sorting, and pagination
  • New app/schemas/query.pyFilterCondition, SortField, FilterOp, SortDir schemas
  • tasks.py endpoint uses parse_sort_fields() to parse the sorting JSON param
  • TaskListResponse schema: sort_by/sort_dirsorting
  • OpenAPI schema injection for both conditions (FilterCondition[]) and sorting (SortField[]) so Orval auto-generates correct TypeScript types

Frontend:

  • useGlobalTasksTableSortField[] state replaces sortBy/sortDir strings; handleSortingChange maps SortingStateSortField[] with auto secondary sort for date_group
  • TagTasksTable — same pattern with SortField[]
  • GuildDashboardPage — dashboard task params use sorting: [{ field: "due_date", dir: "asc" }]
  • Route loaders (index.tsx, created-tasks.tsx) — use sorting: JSON.stringify(defaultSorting)
  • Generated types: ListTasksApiV1TasksGetParams.sorting is SortField[]

Test plan

  • ruff check — lint clean
  • pytest app/db/query_test.py — 96 tests pass (includes TestParseSortFields and TestParseConditions)
  • OpenAPI export + Orval regen — ListTasksApiV1TasksGetParams has sorting?: SortField[]
  • npx tsc --noEmit — frontend compiles with no errors

…ks API

Replace ad-hoc filter query params (project_id, assignee_ids, tag_ids,
etc.) with a structured JSON `conditions` parameter using FilterCondition[].
Replace JSON-encoded `sorting` parameter with simple `sort_by`/`sort_dir`
string params since the UI only sorts by one column at a time.

Backend: add query parsing utilities (parse_conditions, parse_sort_fields),
OpenAPI schema injection for FilterCondition/SortField types, and
automatic date_group→due_date secondary sort expansion.

Frontend: update all task list consumers (global tasks, created tasks,
tag tasks, dashboard, project tasks) to use structured conditions and
simple sort params. Update paramsSerializer to JSON-encode object arrays.
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 23, 2026

Greptile Summary

Replaces ad-hoc task filtering query parameters with a structured JSON conditions parameter using FilterCondition[], and simplifies sorting from JSON-encoded arrays to simple sort_by/sort_dir strings.

Key improvements:

  • New centralized app/db/query.py module provides composable utilities for filtering, sorting, and pagination with security hardening (10KB payload limit, 50 condition max, JSON validation)
  • Backend auto-expands sort_by=date_group to include due_date as secondary sort
  • OpenAPI schema injection ensures Orval auto-generates TypeScript types for filter/sort models
  • Comprehensive test coverage with 96 tests in query_test.py
  • Frontend updated across all task list consumers (global tasks, created tasks, tag tasks, dashboard, project tasks)

Confidence Score: 5/5

  • This PR is safe to merge with no critical issues
  • The refactoring is well-architected with strong security hardening, comprehensive test coverage (96 tests), proper error handling, and consistent patterns. All frontend consumers updated, types properly generated, and backward compatibility maintained through careful migration.
  • No files require special attention

Important Files Changed

Filename Overview
backend/app/db/query.py New centralized query utilities with security hardening (size limits, field validation) for filtering, sorting, and pagination
backend/app/db/query_test.py Comprehensive test suite with 96 tests covering filtering, sorting, pagination, and edge cases
backend/app/schemas/query.py Shared query schemas for FilterCondition, FilterGroup, SortField with proper typing and documentation
backend/app/api/v1/endpoints/tasks.py Refactored to use structured conditions with proper validation and simplified sort parameters
backend/app/main.py Added OpenAPI schema injection for query types to enable TypeScript auto-generation
frontend/src/api/client.ts Updated paramsSerializer to JSON-encode arrays of objects for structured filter conditions
frontend/src/hooks/useGlobalTasksTable.ts Refactored to use FilterCondition array and simplified single-column sort
frontend/src/components/tasks/TagTasksTable.tsx Updated to use structured conditions array instead of individual query params

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Frontend: Task List Component] -->|FilterCondition array| B[API Client paramsSerializer]
    B -->|JSON.stringify for object arrays| C[HTTP Request with conditions param]
    C --> D[Backend: list_tasks endpoint]
    D -->|parse_conditions| E[query.py: Security validation]
    E -->|Size limits, field count limits| F[FilterCondition objects]
    F -->|_build_task_filter_fields| G[Allowed fields dict with callables]
    G -->|apply_filters| H[SQLAlchemy WHERE clauses]
    
    D -->|sort_by/sort_dir strings| I[query.py: apply_sorting]
    I -->|date_group auto-expands| J[SortField list]
    J -->|TASK_SORT_FIELDS mapping| K[SQLAlchemy ORDER BY clauses]
    
    H --> L[Base query with filters]
    K --> L
    L -->|paginated_query| M[Count + Data queries]
    M -->|_clamp_page| N[TaskListResponse]
    N -->|build_paginated_response| O[JSON response]
    O --> P[Frontend: Typed FilterCondition/SortField]
    
    Q[OpenAPI Schema Injection] -->|_inject_query_schemas| R[Orval TypeScript generation]
    R --> P
Loading

Last reviewed commit: 52df4bf

…g param

Swap simple sort_by/sort_dir string params for a JSON-encoded sorting
param using SortField[] — the same pattern as conditions/FilterCondition[].
Enables multi-column sorting (e.g. date_group then due_date).
@LeeJMorel LeeJMorel changed the title refactor: structured filter conditions and simple sort params refactor: structured query params (conditions + sorting) for tasks API Feb 23, 2026
Copy link
Member

@jordandrako jordandrako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something about the current implementation is causing a regression with the default My Tasks sort.

Image

Should be:

  1. Overdue
  2. Today
  3. This week
  4. This month
  5. Later

Comment on lines +183 to +184
"QUERY_INVALID_CONDITIONS": "Invalid filter conditions",
"QUERY_INVALID_SORT_FIELDS": "Invalid sort fields",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure we also update locales/es translations

LeeJMorel and others added 3 commits February 22, 2026 20:17
…parse

- Update task.factory.ts: replace sort_by/sort_dir with sorting, add has_prev
- Add QUERY_INVALID_CONDITIONS and QUERY_INVALID_SORT_FIELDS to es/errors.json
- Add defensive `or None` to parse_sort_fields in case of empty list
Tests were still using old-style query params (assignee_ids, priorities,
guild_ids, project_id, task_status_ids) which the endpoint no longer
accepts. Migrate to the structured conditions JSON format.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants