diff options
Diffstat (limited to 'app/services/packages/nuget/search_service.rb')
-rw-r--r-- | app/services/packages/nuget/search_service.rb | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/app/services/packages/nuget/search_service.rb b/app/services/packages/nuget/search_service.rb index b95aa30bec1..1eead1e62b3 100644 --- a/app/services/packages/nuget/search_service.rb +++ b/app/services/packages/nuget/search_service.rb @@ -3,6 +3,7 @@ module Packages module Nuget class SearchService < BaseService + include ::Packages::FinderHelper include Gitlab::Utils::StrongMemoize include ActiveRecord::ConnectionAdapters::Quoting @@ -16,8 +17,9 @@ module Packages padding: 0 }.freeze - def initialize(project, search_term, options = {}) - @project = project + def initialize(current_user, project_or_group, search_term, options = {}) + @current_user = current_user + @project_or_group = project_or_group @search_term = search_term @options = DEFAULT_OPTIONS.merge(options) @@ -26,8 +28,8 @@ module Packages end def execute - OpenStruct.new( - total_count: package_names.total_count, + Result.new( + total_count: non_paginated_matching_package_names.count, results: search_packages ) end @@ -39,52 +41,104 @@ module Packages # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24182#technical-notes # and https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource subquery_name = :partition_subquery - arel_table = Arel::Table.new(:partition_subquery) + arel_table = Arel::Table.new(subquery_name) column_names = Packages::Package.column_names.map do |cn| "#{subquery_name}.#{quote_column_name(cn)}" end # rubocop: disable CodeReuse/ActiveRecord - pkgs = Packages::Package.select(column_names.join(',')) - .from(package_names_partition, subquery_name) - .where(arel_table[:row_number].lteq(MAX_VERSIONS_PER_PACKAGE)) + pkgs = Packages::Package + pkgs = pkgs.with(project_ids_cte.to_arel) if use_project_ids_cte? + pkgs = pkgs.select(column_names.join(',')) + .from(package_names_partition, subquery_name) + .where(arel_table[:row_number].lteq(MAX_VERSIONS_PER_PACKAGE)) return pkgs if include_prerelease_versions? # we can't use pkgs.without_version_like since we have a custom from pkgs.where.not(arel_table[:version].matches(PRE_RELEASE_VERSION_MATCHING_TERM)) + # rubocop: enable CodeReuse/ActiveRecord end def package_names_partition + # rubocop: disable CodeReuse/ActiveRecord table_name = quote_table_name(Packages::Package.table_name) name_column = "#{table_name}.#{quote_column_name('name')}" created_at_column = "#{table_name}.#{quote_column_name('created_at')}" select_sql = "ROW_NUMBER() OVER (PARTITION BY #{name_column} ORDER BY #{created_at_column} DESC) AS row_number, #{table_name}.*" - @project.packages - .select(select_sql) - .nuget - .has_version - .without_nuget_temporary_name - .with_name(package_names) + nuget_packages.select(select_sql) + .with_name(paginated_matching_package_names) + .where(project_id: project_ids) + # rubocop: enable CodeReuse/ActiveRecord end - def package_names - strong_memoize(:package_names) do - pkgs = @project.packages - .nuget - .has_version - .without_nuget_temporary_name - .order_name - .select_distinct_name + def paginated_matching_package_names + pkgs = base_matching_package_names + pkgs.page(0) # we're using a padding + .per(per_page) + .padding(padding) + end + + def non_paginated_matching_package_names + # rubocop: disable CodeReuse/ActiveRecord + pkgs = base_matching_package_names + pkgs = pkgs.with(project_ids_cte.to_arel) if use_project_ids_cte? + pkgs + # rubocop: enable CodeReuse/ActiveRecord + end + + def base_matching_package_names + strong_memoize(:base_matching_package_names) do + # rubocop: disable CodeReuse/ActiveRecord + pkgs = nuget_packages.order_name + .select_distinct_name + .where(project_id: project_ids) pkgs = pkgs.without_version_like(PRE_RELEASE_VERSION_MATCHING_TERM) unless include_prerelease_versions? pkgs = pkgs.search_by_name(@search_term) if @search_term.present? - pkgs.page(0) # we're using a padding - .per(per_page) - .padding(padding) + pkgs + # rubocop: enable CodeReuse/ActiveRecord end end + def nuget_packages + Packages::Package.nuget + .has_version + .without_nuget_temporary_name + end + + def project_ids_cte + return unless use_project_ids_cte? + + strong_memoize(:project_ids_cte) do + query = projects_visible_to_user(@current_user, within_group: @project_or_group) + Gitlab::SQL::CTE.new(:project_ids, query.select(:id)) + end + end + + def project_ids + return @project_or_group.id if project? + + if use_project_ids_cte? + # rubocop: disable CodeReuse/ActiveRecord + Project.select(:id) + .from(project_ids_cte.table) + # rubocop: enable CodeReuse/ActiveRecord + end + end + + def use_project_ids_cte? + group? + end + + def project? + @project_or_group.is_a?(::Project) + end + + def group? + @project_or_group.is_a?(::Group) + end + def include_prerelease_versions? @options[:include_prerelease_versions] end @@ -96,6 +150,12 @@ module Packages def per_page [@options[:per_page], MAX_PER_PAGE].min end + + class Result + include ActiveModel::Model + + attr_accessor :results, :total_count + end end end end |