Allow filtering Duo workflows by status group and goal/title
What does this MR do and why?
Allow filtering Duo workflows by their status_group or through a fuzzy search against their goal or definition (aka title).
This is needed so users are able to choose how they want to see in the sessions page.
References
Related to #571931 (closed)
GraphQL details
GraphQL Query
query getAgentFlows(
  $projectPath: ID!,
  $sort: DuoWorkflowsWorkflowSort,
  $statusGroup: DuoWorkflowStatusGroup,
  $type: String
) {
  project(fullPath: $projectPath) {
    id
    duoWorkflowWorkflows(
      projectPath: $projectPath
      sort: $sort
      statusGroup: $statusGroup
      type: $type
    ) {
      pageInfo {
        startCursor
        endCursor
        hasNextPage
        hasPreviousPage
      }
      edges {
        node {
          id
          goal
          workflowDefinition
          status
          statusName
          statusGroup
        }
      }
    }
  }
}Variables
{
  "projectPath": "gitlab-duo/test",
  "sort": "STATUS_DESC",
  "statusGroup": null,
  "type": "code_review/experimental"
}SQL query plans
When fuzzy searching by title or goal
Raw SQL
SELECT 
  "duo_workflows_workflows".*
FROM "duo_workflows_workflows" 
WHERE 
  "duo_workflows_workflows"."project_id" = 278964 
  AND "duo_workflows_workflows"."workflow_definition" != 'chat' 
  AND "duo_workflows_workflows"."environment" = 2 
  AND (
      "duo_workflows_workflows"."workflow_definition" ILIKE '%code%' 
      AND "duo_workflows_workflows"."workflow_definition" ILIKE '%review%' OR "duo_workflows_workflows"."goal" ILIKE '%code%' 
      AND "duo_workflows_workflows"."goal" ILIKE '%review%'
  )
ORDER BY 
  "duo_workflows_workflows"."created_at" DESCSQL plan without new index
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/44288/commands/135743
 Sort  (cost=9441.74..9441.76 rows=8 width=338) (actual time=2466.257..2466.261 rows=19 loops=1)
   Sort Key: duo_workflows_workflows.created_at DESC
   Sort Method: quicksort  Memory: 28kB
   Buffers: shared hit=7 read=5765 dirtied=648
   WAL: records=699 fpi=648 bytes=5146939
   I/O Timings: read=2398.086 write=0.000
   ->  Index Scan using index_duo_workflows_workflows_on_project_id on public.duo_workflows_workflows  (cost=0.29..9441.62 rows=8 width=338) (actual time=1063.636..2466.153 rows=19 loops=1)
         Index Cond: (duo_workflows_workflows.project_id = 278964)
         Filter: ((duo_workflows_workflows.workflow_definition <> 'chat'::text) AND (duo_workflows_workflows.environment = 2) AND (((duo_workflows_workflows.workflow_definition ~~* '%code%'::text) AND (duo_workflows_workflows.workflow_definition ~~* '%review%'::text)) OR ((duo_workflows_workflows.goal ~~* '%code%'::text) AND (duo_workflows_workflows.goal ~~* '%review%'::text))))
         Rows Removed by Filter: 21350
         Buffers: shared hit=4 read=5765 dirtied=648
         WAL: records=699 fpi=648 bytes=5146939
         I/O Timings: read=2398.086 write=0.000
Settings: effective_cache_size = '472585MB', jit = 'off', random_page_cost = '1.5', seq_page_cost = '4', work_mem = '100MB'SQL plan with new index
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/44420/commands/136146
Index Scan using index_duo_workflows_workflows_project_environment_created_at on public.duo_workflows_workflows  (cost=0.42..7753.65 rows=10 width=338) (actual time=0.294..20.398 rows=269 loops=1)
   Index Cond: ((duo_workflows_workflows.project_id = 278964) AND (duo_workflows_workflows.environment = 2))
   Filter: ((duo_workflows_workflows.workflow_definition <> 'chat'::text) AND (((duo_workflows_workflows.workflow_definition ~~* '%code%'::text) AND (duo_workflows_workflows.workflow_definition ~~* '%review%'::text)) OR ((duo_workflows_workflows.goal ~~* '%code%'::text) AND (duo_workflows_workflows.goal ~~* '%review%'::text))))
   Rows Removed by Filter: 8438
   Buffers: shared hit=8599 read=46 dirtied=489
   WAL: records=526 fpi=489 bytes=3877346
   I/O Timings: read=1.322 write=0.000
Settings: random_page_cost = '1.5', seq_page_cost = '4', effective_cache_size = '472585MB', jit = 'off', work_mem = '100MB'
When filtering by status_group
Raw SQL
SELECT 
  "duo_workflows_workflows".*
FROM "duo_workflows_workflows"
WHERE 
  "duo_workflows_workflows"."project_id" = 278964 
  AND "duo_workflows_workflows"."workflow_definition" != 'chat' 
  AND "duo_workflows_workflows"."environment" = 2 
  AND "duo_workflows_workflows"."status" = 5
ORDER BY 
  "duo_workflows_workflows"."created_at" DESCSQL plan
https://postgres.ai/console/gitlab/gitlab-production-main/sessions/44288/commands/135745
 Sort  (cost=1257.65..1257.74 rows=39 width=338) (actual time=21.865..21.869 rows=0 loops=1)
   Sort Key: duo_workflows_workflows.created_at DESC
   Sort Method: quicksort  Memory: 25kB
   Buffers: shared hit=470 read=29
   I/O Timings: read=17.774 write=0.000
   ->  Bitmap Heap Scan on public.duo_workflows_workflows  (cost=303.71..1256.62 rows=39 width=338) (actual time=21.847..21.851 rows=0 loops=1)
         Filter: ((duo_workflows_workflows.workflow_definition <> 'chat'::text) AND (duo_workflows_workflows.environment = 2))
         Rows Removed by Filter: 484
         Buffers: shared hit=467 read=29
         I/O Timings: read=17.774 write=0.000
         ->  BitmapAnd  (cost=303.71..303.71 rows=450 width=0) (actual time=20.151..20.154 rows=0 loops=1)
               Buffers: shared hit=34 read=29
               I/O Timings: read=17.774 write=0.000
               ->  Bitmap Index Scan using idx_workflows_status_updated_at_id  (cost=0.00..90.71 rows=3039 width=0) (actual time=18.479..18.479 rows=3045 loops=1)
                     Index Cond: (duo_workflows_workflows.status = 5)
                     Buffers: shared hit=3 read=29
                     I/O Timings: read=17.774 write=0.000
               ->  Bitmap Index Scan using index_duo_workflows_workflows_on_project_id  (cost=0.00..212.72 rows=21324 width=0) (actual time=1.498..1.498 rows=21369 loops=1)
                     Index Cond: (duo_workflows_workflows.project_id = 278964)
                     Buffers: shared hit=31
                     I/O Timings: read=0.000 write=0.000
Settings: jit = 'off', random_page_cost = '1.5', seq_page_cost = '4', work_mem = '100MB', effective_cache_size = '472585MB'SQL plan with new index
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/44420/commands/136148
 Sort  (cost=29.37..29.38 rows=1 width=338) (actual time=27.859..27.861 rows=0 loops=1)
   Sort Key: duo_workflows_workflows.created_at DESC
   Sort Method: quicksort  Memory: 25kB
   Buffers: shared hit=286 read=12 dirtied=9
   WAL: records=15 fpi=9 bytes=43767
   I/O Timings: read=26.094 write=0.000
   ->  Index Scan using idx_workflows_status_updated_at_id on public.duo_workflows_workflows  (cost=0.42..29.36 rows=1 width=338) (actual time=27.846..27.846 rows=0 loops=1)
         Index Cond: (duo_workflows_workflows.status = 1)
         Filter: ((duo_workflows_workflows.workflow_definition <> 'chat'::text) AND (duo_workflows_workflows.project_id = 278964) AND (duo_workflows_workflows.environment = 2))
         Rows Removed by Filter: 26
         Buffers: shared hit=283 read=12 dirtied=9
         WAL: records=15 fpi=9 bytes=43767
         I/O Timings: read=26.094 write=0.000
Settings: effective_cache_size = '472585MB', jit = 'off', work_mem = '100MB', random_page_cost = '1.5', seq_page_cost = '4'MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.