Skip to content

Support epic board lists negated filters on GraphQL

Felipe Artur requested to merge issue_322686-negated_filters into master

What does this MR do?

Allow filtering epic on epic boards lists by negated params. Parameters are in the same format of negated issue board params: filters: { not: { authorUsername: "Joe", .....

Sample query

query epicBoardListEpics { 
  group(fullPath: "Flightjs"){
    epicBoard(id: "gid://gitlab/Boards::EpicBoard/1") {
      lists {
        nodes {
          epics(filters: { not: { authorUsername: "Joe", labelName: ["Staging", "Production"], myReactionEmoji: "thumbsup" } }) {
            nodes {
              id
            }
          }
        }
      }
    }
  }
}

Query to fetch epics without given emoji name

SELECT          "epics".* 
FROM            "epics" 
LEFT OUTER JOIN "boards_epic_board_positions" 
ON              "boards_epic_board_positions"."epic_id" = "epics"."id" 
WHERE           "epics"."group_id" IN (WITH recursive "base_and_descendants" AS ( 
                                       ( 
                                              SELECT "namespaces".* 
                                              FROM   "namespaces" 
                                              WHERE  "namespaces"."type" = 'Group' 
                                              AND    "namespaces"."id" = 9970) 
                                UNION 
                                      ( 
                                             SELECT "namespaces".* 
                                             FROM   "namespaces", 
                                                    "base_and_descendants" 
                                             WHERE  "namespaces"."type" = 'Group' 
                                             AND    "namespaces"."parent_id" = "base_and_descendants"."id"))SELECT   "namespaces"."id"
                                 FROM     "base_and_descendants" AS "namespaces") 
       AND      "epics"."state_id" = 1 
       AND      NOT ( 
                         EXISTS 
                         ( 
                                SELECT true 
                                FROM   "award_emoji" 
                                WHERE  "award_emoji"."user_id" = 426128 
                                AND    "award_emoji"."awardable_type" = 'Epic' 
                                AND    "award_emoji"."awardable_id" = "epics"."id" 
                                AND    "award_emoji"."name" = 'thumbsup')) 
       AND      ( 
                         "boards_epic_board_positions"."epic_board_id" = 4 
                OR       "boards_epic_board_positions"."epic_board_id" IS NULL) 
       ORDER BY boards_epic_board_positions.relative_position ASC nulls last, 
                epics.id DESC limit 100

Query plan(production explain analyze)

 Limit  (cost=4114.97..4115.00 rows=13 width=1204) (actual time=117.353..117.368 rows=100 loops=1)
   ->  Sort  (cost=4114.97..4115.00 rows=13 width=1204) (actual time=117.351..117.358 rows=100 loops=1)
         Sort Key: boards_epic_board_positions.relative_position, epics.id DESC
         Sort Method: top-N heapsort  Memory: 214kB
         ->  Nested Loop Anti Join  (cost=4055.77..4114.73 rows=13 width=1204) (actual time=110.626..114.
592 rows=3875 loops=1)
               Join Filter: (award_emoji.awardable_id = epics.id)
               ->  Hash Right Join  (cost=4055.21..4110.95 rows=13 width=1204) (actual time=109.199..111.
724 rows=3875 loops=1)
                     Hash Cond: (boards_epic_board_positions.epic_id = epics.id)
                     Filter: ((boards_epic_board_positions.epic_board_id = 4) OR (boards_epic_board_posit
ions.epic_board_id IS NULL))
                     ->  Seq Scan on boards_epic_board_positions  (cost=0.00..51.30 rows=1130 width=20) (
actual time=0.005..0.005 rows=0 loops=1)
                     ->  Hash  (cost=4039.40..4039.40 rows=1265 width=1200) (actual time=109.171..109.171
 rows=3875 loops=1)
                           Buckets: 4096 (originally 2048)  Batches: 1 (originally 1)  Memory Usage: 3562
kB
                           ->  Nested Loop  (cost=1435.52..4039.40 rows=1265 width=1200) (actual time=11.
171..102.632 rows=3875 loops=1)
                                 ->  HashAggregate  (cost=1435.10..1436.81 rows=171 width=4) (actual time
=10.918..11.050 rows=233 loops=1)
                                       Group Key: namespaces.id
                                       ->  CTE Scan on base_and_descendants namespaces  (cost=1429.54..14
32.96 rows=171 width=4) (actual time=0.095..10.803 rows=233 loops=1)
                                             CTE base_and_descendants
                                               ->  Recursive Union  (cost=0.43..1429.54 rows=171 width=34
4) (actual time=0.092..10.358 rows=233 loops=1)
                                                     ->  Index Scan using index_namespaces_on_type_and_id
_partial on namespaces namespaces_1  (cost=0.43..3.45 rows=1 width=344) (actual time=0.084..0.085 rows=1 
loops=1)
                                                           Index Cond: (((type)::text = 'Group'::text) AN
D (id = 9970))
                                                     ->  Nested Loop  (cost=0.56..142.27 rows=17 width=34
4) (actual time=0.085..1.586 rows=39 loops=6)
                                                           ->  WorkTable Scan on base_and_descendants  (c
ost=0.00..0.20 rows=10 width=4) (actual time=0.000..0.007 rows=39 loops=6)
                                                           ->  Index Scan using index_namespaces_on_paren
t_id_and_id on namespaces namespaces_2  (cost=0.56..14.19 rows=2 width=344) (actual time=0.025..0.040 row
s=1 loops=233)
                                                                 Index Cond: (parent_id = base_and_descen
dants.id)
                                                                 Filter: ((type)::text = 'Group'::text)
                                 ->  Index Scan using index_epics_on_group_id_and_iid on epics  (cost=0.4
2..15.15 rows=7 width=1200) (actual time=0.108..0.388 rows=17 loops=233)
                                       Index Cond: (group_id = namespaces.id)
                                       Filter: (state_id = 1)
                                       Rows Removed by Filter: 9
               ->  Materialize  (cost=0.56..3.58 rows=1 width=4) (actual time=0.000..0.000 rows=0 loops=3
875)
                     ->  Index Only Scan using idx_award_emoji_on_user_emoji_name_awardable_type_awardabl
e_id on award_emoji  (cost=0.56..3.58 rows=1 width=4) (actual time=1.421..1.421 rows=0 loops=1)
                           Index Cond: ((user_id = 426128) AND (name = 'thumbsup'::text) AND (awardable_t
ype = 'Epic'::text))
                           Heap Fetches: 0
 Planning Time: 17.626 ms
 Execution Time: 118.219 ms
(35 rows)

related to #322686 (closed)

Edited by Felipe Artur

Merge request reports