From a1536d0db90ed6d8757c99e5cb80e129ab783af1 Mon Sep 17 00:00:00 2001
From: Ravi Kumar <rkumar@gitlab.com>
Date: Tue, 23 Jul 2024 11:53:24 +0000
Subject: [PATCH] Add regex argument

If regex is send as true, the search mode will be regex.
If regex is send as false, the search mode will be exact.
Default value is false

Changelog: other
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159623
EE: true
---
 doc/api/graphql/reference/index.md            |  1 +
 .../search/blob/blob_search_resolver.rb       |  4 +++-
 ee/lib/search/found_multi_line_blob.rb        | 22 +++++++++++++++++--
 ee/lib/search/zoekt/multi_match.rb            |  3 ++-
 .../search/found_multi_line_blob_spec.rb      | 12 ++++++++--
 5 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 36300dbe099e7..7a7c2e0419377 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -178,6 +178,7 @@ Returns [`BlobSearch`](#blobsearch).
 | <a id="queryblobsearchpage"></a>`page` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Page number to fetch the results. |
 | <a id="queryblobsearchperpage"></a>`perPage` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Number of results per page. |
 | <a id="queryblobsearchprojectid"></a>`projectId` **{warning-solid}** | [`ProjectID`](#projectid) | **Introduced** in GitLab 17.2. **Status**: Experiment. Project to search in. |
+| <a id="queryblobsearchregex"></a>`regex` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in GitLab 17.3. **Status**: Experiment. Uses the regular expression search mode. Default is false. |
 | <a id="queryblobsearchrepositoryref"></a>`repositoryRef` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Repository reference to search in. |
 | <a id="queryblobsearchsearch"></a>`search` | [`String!`](#string) | Searched term. |
 
diff --git a/ee/app/graphql/resolvers/search/blob/blob_search_resolver.rb b/ee/app/graphql/resolvers/search/blob/blob_search_resolver.rb
index 593a4fc1c312a..f99aa301ca6b7 100644
--- a/ee/app/graphql/resolvers/search/blob/blob_search_resolver.rb
+++ b/ee/app/graphql/resolvers/search/blob/blob_search_resolver.rb
@@ -19,6 +19,8 @@ class BlobSearchResolver < BaseResolver
           default_value: ::Search::Zoekt::SearchResults::DEFAULT_PER_PAGE, description: 'Number of results per page.'
         argument :project_id, ::Types::GlobalIDType[::Project], required: false, alpha: { milestone: '17.2' },
           description: 'Project to search in.'
+        argument :regex, GraphQL::Types::Boolean, required: false, default_value: false, alpha: { milestone: '17.3' },
+          description: 'Uses the regular expression search mode. Default is false.'
         argument :repository_ref, type: GraphQL::Types::String, required: false, alpha: { milestone: '17.2' },
           description: 'Repository reference to search in.'
         argument :search, GraphQL::Types::String, required: true, description: 'Searched term.'
@@ -29,7 +31,7 @@ def ready?(**args)
           @search_service = SearchService.new(current_user, {
             group_id: args[:group_id]&.model_id, project_id: args[:project_id]&.model_id, search: args[:search],
             page: args[:page], per_page: args[:per_page], multi_match_enabled: true, chunk_count: args[:chunk_count],
-            scope: 'blobs'
+            scope: 'blobs', regex: args[:regex]
           })
           @search_level = @search_service.level
           verify_global_search_is_allowed!
diff --git a/ee/lib/search/found_multi_line_blob.rb b/ee/lib/search/found_multi_line_blob.rb
index e82a5554fc3d9..5de70411abb29 100644
--- a/ee/lib/search/found_multi_line_blob.rb
+++ b/ee/lib/search/found_multi_line_blob.rb
@@ -1,6 +1,24 @@
 # frozen_string_literal: true
 
 module Search
-  FoundMultiLineBlob = Struct.new(:path, :chunks, :file_url, :blame_url, :match_count_total, :match_count,
-    :project_path, keyword_init: true)
+  class FoundMultiLineBlob
+    include BlobActiveModel
+
+    attr_reader :path, :chunks, :file_url, :blame_url, :match_count_total, :match_count, :project_path, :project
+
+    def initialize(opts = {})
+      @path = opts[:path]
+      @chunks = opts[:chunks]
+      @file_url = opts[:file_url]
+      @blame_url = opts[:blame_url]
+      @match_count_total = opts[:match_count_total]
+      @match_count = opts[:match_count]
+      @project_path = opts[:project_path]
+      @project = opts[:project]
+    end
+
+    def id
+      nil
+    end
+  end
 end
diff --git a/ee/lib/search/zoekt/multi_match.rb b/ee/lib/search/zoekt/multi_match.rb
index 18055e6364a1a..d25b85a6ee8e8 100644
--- a/ee/lib/search/zoekt/multi_match.rb
+++ b/ee/lib/search/zoekt/multi_match.rb
@@ -22,7 +22,8 @@ def blobs_for_project(result, project, ref)
           file_url: Gitlab::Routing.url_helpers.project_blob_url(project, File.join(ref, result[:path])),
           blame_url: Gitlab::Routing.url_helpers.project_blame_url(project, File.join(ref, result[:path])),
           match_count_total: result[:match_count_total],
-          match_count: result[:match_count]
+          match_count: result[:match_count],
+          project: project
         )
       end
 
diff --git a/ee/spec/lib/gitlab/search/found_multi_line_blob_spec.rb b/ee/spec/lib/gitlab/search/found_multi_line_blob_spec.rb
index 4ba1401ac1f00..805869db66e79 100644
--- a/ee/spec/lib/gitlab/search/found_multi_line_blob_spec.rb
+++ b/ee/spec/lib/gitlab/search/found_multi_line_blob_spec.rb
@@ -4,13 +4,21 @@
 
 RSpec.describe Search::FoundMultiLineBlob, feature_category: :global_search do
   describe '#initialize and read the attributes' do
+    let(:project) { instance_double(Project) }
+
     it 'can initialize an instance and read the attributes' do
       instance = described_class.new(
-        path: 'p', chunks: [], file_url: 'f', blame_url: 'b', match_count_total: 5, match_count: 3, project_path: 'path'
+        path: 'p', chunks: [], file_url: 'f', blame_url: 'b', match_count_total: 5, match_count: 3,
+        project_path: 'path', project: project
       )
       expect(instance).to have_attributes(
-        path: 'p', chunks: [], file_url: 'f', blame_url: 'b', match_count_total: 5, match_count: 3, project_path: 'path'
+        path: 'p', chunks: [], file_url: 'f', blame_url: 'b', match_count_total: 5, match_count: 3,
+        project_path: 'path', project: project
       )
     end
   end
+
+  describe '#id' do
+    it { expect(described_class.new.id).to be_nil }
+  end
 end
-- 
GitLab