Add fuzzySearch argument to labels GraphQL queries

What does this MR do and why?

Adds an opt-in fuzzySearch boolean argument to the labels GraphQL field on Project and Group. When set, searchTerm matches labels containing the searched characters in order, but not necessarily contiguously (for example, bugu matches bug::ux).

This mirrors the client-side fuzzaldrin-plus subsequence matching that markdown/rich text label autocomplete already uses. The label widgets on work items and MRs currently pass searchTerm to this field, where it is matched as a contiguous substring (ILIKE '%bugu%'), so fuzzy queries that work in markdown return no results in the widgets.

This is part 1 of 2, backend only — no behavior changes for existing queries (the argument defaults to false). The follow-up MR (!252373) makes the label widgets use the new argument. Split per multiversion compatibility guidelines: @gl_introduced cannot be applied to arguments, so the frontend must not send fuzzySearch until the backend is deployed.

Database

New opt-in query shape (generated via Label.search('bug u%', search_in: [:title], fuzzy_search: true) — note whitespace stripping and LIKE wildcard escaping):

SELECT "labels".* FROM "labels"
WHERE ("labels"."type" = 'GroupLabel' AND "labels"."group_id" IN (9970) OR "labels"."type" = 'ProjectLabel' AND "labels"."project_id" = 278964) 
AND "labels"."title" ILIKE '%b%u%g%u%' AND "labels"."archived" = FALSE
ORDER BY "labels"."title" ASC, "labels"."id" DESC LIMIT 101 

https://console.postgres.ai/gitlab/projects/gitlab-production-main/sessions/55871/commands/159719

The existing non-fuzzy path is unchanged:

SELECT "labels".* FROM "labels" WHERE "labels"."title" ILIKE '%bugu%' ORDER BY "labels"."title" ASC

Like the existing label search, the pattern is unanchored so it cannot use an index, but label queries are always scoped to a namespace hierarchy (see the existing min_chars_for_partial_matching override in BaseLabel for the same rationale).

References

  • Part 2 of 2 (frontend, stacked on this MR): !252373

Screenshots or screen recordings

None — backend only. UI change lands in !252373.

How to set up and validate locally

  1. Create a scoped label such as foo::baz in a project.

  2. In GraphiQL (/-/graphql-explorer), run:

    query {
      project(fullPath: "<your-project>") {
        labels(searchTerm: "faz", searchIn: TITLE, fuzzySearch: true) {
          nodes { title }
        }
      }
    }
  3. foo::baz is returned. Without fuzzySearch: true, no labels are returned.

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.

Edited by Keeyan Nejad

Merge request reports

Loading
Loading