Add min_access_level argument to contributed projects GraphQL query
What does this MR do and why?
Needed for &13066 where we are moving Your work
-> Projects
to Vue and fetching the data with GraphQL. We need to provide a Role
filter in the UI so we are adding a min_access_level
argument to the Contributed Projects GraphQL query.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Database
Raw SQL
Click to expand
SELECT
"projects"."id",
"projects"."name",
"projects"."path",
"projects"."description",
"projects"."created_at",
"projects"."updated_at",
"projects"."creator_id",
"projects"."namespace_id",
"projects"."last_activity_at",
"projects"."import_url",
"projects"."visibility_level",
"projects"."archived",
"projects"."avatar",
"projects"."merge_requests_template",
"projects"."star_count",
"projects"."merge_requests_rebase_enabled",
"projects"."import_type",
"projects"."import_source",
"projects"."approvals_before_merge",
"projects"."reset_approvals_on_push",
"projects"."merge_requests_ff_only_enabled",
"projects"."issues_template",
"projects"."mirror",
"projects"."mirror_last_update_at",
"projects"."mirror_last_successful_update_at",
"projects"."mirror_user_id",
"projects"."shared_runners_enabled",
"projects"."runners_token",
"projects"."build_allow_git_fetch",
"projects"."build_timeout",
"projects"."mirror_trigger_builds",
"projects"."pending_delete",
"projects"."public_builds",
"projects"."last_repository_check_failed",
"projects"."last_repository_check_at",
"projects"."only_allow_merge_if_pipeline_succeeds",
"projects"."has_external_issue_tracker",
"projects"."repository_storage",
"projects"."repository_read_only",
"projects"."request_access_enabled",
"projects"."has_external_wiki",
"projects"."ci_config_path",
"projects"."lfs_enabled",
"projects"."description_html",
"projects"."only_allow_merge_if_all_discussions_are_resolved",
"projects"."repository_size_limit",
"projects"."printing_merge_request_link_enabled",
"projects"."auto_cancel_pending_pipelines",
"projects"."service_desk_enabled",
"projects"."cached_markdown_version",
"projects"."delete_error",
"projects"."last_repository_updated_at",
"projects"."disable_overriding_approvers_per_merge_request",
"projects"."storage_version",
"projects"."resolve_outdated_diff_discussions",
"projects"."remote_mirror_available_overridden",
"projects"."only_mirror_protected_branches",
"projects"."pull_mirror_available_overridden",
"projects"."jobs_cache_index",
"projects"."external_authorization_classification_label",
"projects"."mirror_overwrites_diverged_branches",
"projects"."pages_https_only",
"projects"."external_webhook_token",
"projects"."packages_enabled",
"projects"."merge_requests_author_approval",
"projects"."pool_repository_id",
"projects"."runners_token_encrypted",
"projects"."bfg_object_map",
"projects"."detected_repository_languages",
"projects"."merge_requests_disable_committers_approval",
"projects"."require_password_to_approve",
"projects"."max_pages_size",
"projects"."max_artifacts_size",
"projects"."pull_mirror_branch_prefix",
"projects"."remove_source_branch_after_merge",
"projects"."marked_for_deletion_at",
"projects"."marked_for_deletion_by_user_id",
"projects"."autoclose_referenced_issues",
"projects"."suggestion_commit_message",
"projects"."project_namespace_id",
"projects"."hidden",
"projects"."organization_id"
FROM
"projects"
WHERE
"projects"."id" IN ( SELECT DISTINCT
"events"."project_id"
FROM
"events"
WHERE (action IN (5, 6)
OR (target_type IN ('MergeRequest', 'Issue', 'WorkItem')
AND action IN (1, 3, 7, 12)))
AND "events"."author_id" = 1
AND "events"."created_at" >= '2023-09-18 14:16:16.741227')
AND "projects"."marked_for_deletion_at" IS NULL
AND "projects"."pending_delete" = FALSE
AND "projects"."id" IN (
SELECT
"projects"."id"
FROM
"projects"
INNER JOIN "project_authorizations" ON "projects"."id" = "project_authorizations"."project_id"
WHERE
"project_authorizations"."user_id" = 5413811
AND (project_authorizations.access_level >= 30))
AND "projects"."namespace_id" != 1
ORDER BY
"projects"."last_activity_at" DESC,
"projects"."id" DESC
LIMIT 101
Query plan
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31633/commands/98023
Click to expand
Limit (cost=4748.10..4748.11 rows=1 width=857) (actual time=319.385..319.394 rows=11 loops=1)
Buffers: shared hit=221 read=304 dirtied=40
I/O Timings: read=314.064 write=0.000
-> Sort (cost=4748.10..4748.11 rows=1 width=857) (actual time=319.383..319.390 rows=11 loops=1)
Sort Key: projects.last_activity_at DESC, projects.id DESC
Sort Method: quicksort Memory: 36kB
Buffers: shared hit=221 read=304 dirtied=40
I/O Timings: read=314.064 write=0.000
-> Nested Loop Semi Join (cost=2.41..4748.09 rows=1 width=857) (actual time=39.219..319.167 rows=11 loops=1)
Buffers: shared hit=215 read=304 dirtied=40
I/O Timings: read=314.064 write=0.000
-> Nested Loop (cost=1.27..3444.08 rows=899 width=861) (actual time=28.101..283.657 rows=12 loops=1)
Buffers: shared hit=117 read=275 dirtied=38
I/O Timings: read=279.388 write=0.000
-> Unique (cost=0.70..209.48 rows=901 width=4) (actual time=23.571..219.853 rows=13 loops=1)
Buffers: shared hit=86 read=237 dirtied=30
I/O Timings: read=216.615 write=0.000
-> Index Only Scan using index_events_author_id_project_id_action_target_type_created_at on public.events (cost=0.70..207.23 rows=902 width=4) (actual time=23.565..219.663 rows=203 loops=1)
Index Cond: ((events.author_id = 1) AND (events.created_at >= '2023-09-18 14:16:16.741227+00'::timestamp with time zone))
Heap Fetches: 72
Filter: ((events.action = ANY ('{5,6}'::integer[])) OR (((events.target_type)::text = ANY ('{MergeRequest,Issue,WorkItem}'::text[])) AND (events.action = ANY ('{1,3,7,12}'::integer[]))))
Rows Removed by Filter: 12
Buffers: shared hit=86 read=237 dirtied=30
I/O Timings: read=216.615 write=0.000
-> Index Scan using projects_pkey on public.projects (cost=0.56..3.58 rows=1 width=857) (actual time=4.895..4.895 rows=1 loops=13)
Index Cond: (projects.id = events.project_id)
Filter: ((projects.marked_for_deletion_at IS NULL) AND (NOT projects.pending_delete) AND (projects.namespace_id <> 1))
Rows Removed by Filter: 0
Buffers: shared hit=28 read=38 dirtied=5
I/O Timings: read=62.773 write=0.000
-> Nested Loop (cost=1.14..1.44 rows=1 width=8) (actual time=2.950..2.951 rows=1 loops=12)
Buffers: shared hit=98 read=29 dirtied=2
I/O Timings: read=34.676 write=0.000
-> Index Only Scan using projects_pkey on public.projects projects_1 (cost=0.56..0.59 rows=1 width=4) (actual time=0.391..0.392 rows=1 loops=12)
Index Cond: (projects_1.id = projects.id)
Heap Fetches: 10
Buffers: shared hit=62 read=6
I/O Timings: read=4.455 write=0.000
-> Index Only Scan using project_authorizations_pkey on public.project_authorizations (cost=0.58..0.84 rows=1 width=4) (actual time=2.546..2.546 rows=1 loops=12)
Index Cond: ((project_authorizations.user_id = 5413811) AND (project_authorizations.project_id = projects_1.id) AND (project_authorizations.access_level >= 30))
Heap Fetches: 2
Buffers: shared hit=36 read=23 dirtied=2
I/O Timings: read=30.221 write=0.000
How to set up and validate locally
- Go to http://gdk.test:3000/-/graphql-explorer
- Run the following
query getProjects {
currentUser {
contributedProjects(minAccessLevel: OWNER) {
nodes {
nameWithNamespace
maxAccessLevel {
humanAccess
}
}
}
}
}
If you don't have any contributed projects go comment on an issue in a project or push a code change to a project
Edited by Peter Hegman