Support filtering by scoped label wildcards
What does this MR do and why?
Allows filtering issues, merge requests, and epics by scoped label wildcards using the <scope>::*
syntax.
This only applies to the project / group issues, merge requests, and epic lists. Dashboard pages are not included.
I excluded the dashboard pages because the query does not perform very well in some cases on the dashboard pages because that goes through a different code path that does not use the optimization we introduced in !34503 (merged). !71020 (diffs) has extra details.
Related to #12285 (closed)
Migration output
== 20210921063924 IndexLabelsUsingVarcharPatternOps: migrating ================
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, :title, {:order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_title_varchar", :algorithm=>:concurrently})
-> 0.0054s
-- add_index(:labels, :title, {:order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_title_varchar", :algorithm=>:concurrently})
-> 0.0070s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, [:project_id, :title], {:where=>"labels.group_id IS NULL", :unique=>true, :order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_project_id_and_title_varchar_unique", :algorithm=>:concurrently})
-> 0.0041s
-- add_index(:labels, [:project_id, :title], {:where=>"labels.group_id IS NULL", :unique=>true, :order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_project_id_and_title_varchar_unique", :algorithm=>:concurrently})
-> 0.0050s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, [:group_id, :title], {:where=>"labels.project_id IS NULL", :unique=>true, :order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_group_id_and_title_varchar_unique", :algorithm=>:concurrently})
-> 0.0048s
-- add_index(:labels, [:group_id, :title], {:where=>"labels.project_id IS NULL", :unique=>true, :order=>{:title=>:varchar_pattern_ops}, :name=>"index_labels_on_group_id_and_title_varchar_unique", :algorithm=>:concurrently})
-> 0.0047s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, :group_id, {:name=>"index_labels_on_group_id", :algorithm=>:concurrently})
-> 0.0044s
-- add_index(:labels, :group_id, {:name=>"index_labels_on_group_id", :algorithm=>:concurrently})
-> 0.0053s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0052s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_title"})
-> 0.0035s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0046s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_project_id_and_title_unique"})
-> 0.0029s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0042s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_group_id_and_title_unique"})
-> 0.0033s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0039s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_group_id_and_project_id_and_title"})
-> 0.0031s
== 20210921063924 IndexLabelsUsingVarcharPatternOps: migrated (0.0872s) =======
== 20210921063924 IndexLabelsUsingVarcharPatternOps: reverting ================
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, :title, {:name=>"index_labels_on_title", :algorithm=>:concurrently})
-> 0.0051s
-- add_index(:labels, :title, {:name=>"index_labels_on_title", :algorithm=>:concurrently})
-> 0.0073s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, [:project_id, :title], {:where=>"labels.group_id IS NULL", :unique=>true, :name=>"index_labels_on_project_id_and_title_unique", :algorithm=>:concurrently})
-> 0.0039s
-- add_index(:labels, [:project_id, :title], {:where=>"labels.group_id IS NULL", :unique=>true, :name=>"index_labels_on_project_id_and_title_unique", :algorithm=>:concurrently})
-> 0.0065s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, [:group_id, :title], {:where=>"labels.project_id IS NULL", :unique=>true, :name=>"index_labels_on_group_id_and_title_unique", :algorithm=>:concurrently})
-> 0.0045s
-- add_index(:labels, [:group_id, :title], {:where=>"labels.project_id IS NULL", :unique=>true, :name=>"index_labels_on_group_id_and_title_unique", :algorithm=>:concurrently})
-> 0.0049s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:labels, [:group_id, :project_id, :title], {:unique=>true, :name=>"index_labels_on_group_id_and_project_id_and_title", :algorithm=>:concurrently})
-> 0.0053s
-- add_index(:labels, [:group_id, :project_id, :title], {:unique=>true, :name=>"index_labels_on_group_id_and_project_id_and_title", :algorithm=>:concurrently})
-> 0.0051s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0051s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_title_varchar"})
-> 0.0035s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0045s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_project_id_and_title_varchar_unique"})
-> 0.0029s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0042s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_group_id_and_title_varchar_unique"})
-> 0.0033s
-- transaction_open?()
-> 0.0000s
-- indexes(:labels)
-> 0.0039s
-- remove_index(:labels, {:algorithm=>:concurrently, :name=>"index_labels_on_group_id"})
-> 0.0031s
== 20210921063924 IndexLabelsUsingVarcharPatternOps: reverted (0.0887s) =======
Sample queries
-
find_label_ids
withdevops::*
: https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/6584/commands/23240 -
find_label_ids
withdevops::*
andworkflow::*
: https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/6584/commands/23243
Screenshots or screen recordings
How to set up and validate locally
- Create multiple scoped labels with the same scope and assign them to issues
- Use the filter bar in the group / project issue list to filter by the label
<scope>::*
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.