blob: b95aa30bec195974f590c872fa9bcc0955b41706 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# frozen_string_literal: true
module Packages
module Nuget
class SearchService < BaseService
include Gitlab::Utils::StrongMemoize
include ActiveRecord::ConnectionAdapters::Quoting
MAX_PER_PAGE = 30
MAX_VERSIONS_PER_PACKAGE = 10
PRE_RELEASE_VERSION_MATCHING_TERM = '%-%'
DEFAULT_OPTIONS = {
include_prerelease_versions: true,
per_page: Kaminari.config.default_per_page,
padding: 0
}.freeze
def initialize(project, search_term, options = {})
@project = project
@search_term = search_term
@options = DEFAULT_OPTIONS.merge(options)
raise ArgumentError, 'negative per_page' if per_page < 0
raise ArgumentError, 'negative padding' if padding < 0
end
def execute
OpenStruct.new(
total_count: package_names.total_count,
results: search_packages
)
end
private
def search_packages
# custom query to get package names and versions as expected from the nuget search api
# 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)
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))
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))
end
def package_names_partition
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)
end
def package_names
strong_memoize(:package_names) do
pkgs = @project.packages
.nuget
.has_version
.without_nuget_temporary_name
.order_name
.select_distinct_name
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)
end
end
def include_prerelease_versions?
@options[:include_prerelease_versions]
end
def padding
@options[:padding]
end
def per_page
[@options[:per_page], MAX_PER_PAGE].min
end
end
end
end
|