diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/groups.rb | 16 | ||||
-rw-r--r-- | lib/api/helpers/pagination_strategies.rb | 36 | ||||
-rw-r--r-- | lib/gitlab/database/load_balancing/sidekiq_client_middleware.rb | 6 | ||||
-rw-r--r-- | lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/database_importers/work_items/base_type_importer.rb | 15 | ||||
-rw-r--r-- | lib/gitlab/pagination/cursor_based_keyset.rb | 27 | ||||
-rw-r--r-- | lib/gitlab/pagination/keyset/cursor_based_request_context.rb | 15 |
7 files changed, 100 insertions, 17 deletions
diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 0896357cc73..a1123b6291b 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -108,6 +108,20 @@ module API present paginate(groups), options end + def present_groups_with_pagination_strategies(params, groups) + return present_groups(params, groups) if current_user.present? || Feature.disabled?(:keyset_pagination_for_groups_api) + + options = { + with: Entities::Group, + current_user: nil, + statistics: false + } + + groups, options = with_custom_attributes(groups, options) + + present paginate_with_strategies(groups), options + end + def delete_group(group) destroy_conditionally!(group) do |group| ::Groups::DestroyService.new(group, current_user).async_execute @@ -168,7 +182,7 @@ module API end get do groups = find_groups(declared_params(include_missing: false), params[:id]) - present_groups params, groups + present_groups_with_pagination_strategies params, groups end desc 'Create a group. Available only for users who can create groups.' do diff --git a/lib/api/helpers/pagination_strategies.rb b/lib/api/helpers/pagination_strategies.rb index 61cff37e4ab..8c2186768ea 100644 --- a/lib/api/helpers/pagination_strategies.rb +++ b/lib/api/helpers/pagination_strategies.rb @@ -3,10 +3,16 @@ module API module Helpers module PaginationStrategies - def paginate_with_strategies(relation, request_scope) + def paginate_with_strategies(relation, request_scope = nil) paginator = paginator(relation, request_scope) - yield(paginator.paginate(relation)).tap do |records, _| + result = if block_given? + yield(paginator.paginate(relation)) + else + paginator.paginate(relation) + end + + result.tap do |records, _| paginator.finalize(records) end end @@ -20,17 +26,31 @@ module API private def keyset_paginator(relation) - request_context = Gitlab::Pagination::Keyset::RequestContext.new(self) - unless Gitlab::Pagination::Keyset.available?(request_context, relation) + if cursor_based_keyset_pagination_supported?(relation) + request_context_class = Gitlab::Pagination::Keyset::CursorBasedRequestContext + paginator_class = Gitlab::Pagination::Keyset::CursorPager + availability_checker = Gitlab::Pagination::CursorBasedKeyset + else + request_context_class = Gitlab::Pagination::Keyset::RequestContext + paginator_class = Gitlab::Pagination::Keyset::Pager + availability_checker = Gitlab::Pagination::Keyset + end + + request_context = request_context_class.new(self) + + unless availability_checker.available?(request_context, relation) return error!('Keyset pagination is not yet available for this type of request', 405) end - Gitlab::Pagination::Keyset::Pager.new(request_context) + paginator_class.new(request_context) end def offset_paginator(relation, request_scope) offset_limit = limit_for_scope(request_scope) - if Gitlab::Pagination::Keyset.available_for_type?(relation) && offset_limit_exceeded?(offset_limit) + if (Gitlab::Pagination::Keyset.available_for_type?(relation) || + cursor_based_keyset_pagination_supported?(relation)) && + offset_limit_exceeded?(offset_limit) + return error!("Offset pagination has a maximum allowed offset of #{offset_limit} " \ "for requests that return objects of type #{relation.klass}. " \ "Remaining records can be retrieved using keyset pagination.", 405) @@ -39,6 +59,10 @@ module API Gitlab::Pagination::OffsetPagination.new(self) end + def cursor_based_keyset_pagination_supported?(relation) + Gitlab::Pagination::CursorBasedKeyset.available_for_type?(relation) + end + def keyset_pagination_enabled? params[:pagination] == 'keyset' end diff --git a/lib/gitlab/database/load_balancing/sidekiq_client_middleware.rb b/lib/gitlab/database/load_balancing/sidekiq_client_middleware.rb index acb4842db31..518a812b406 100644 --- a/lib/gitlab/database/load_balancing/sidekiq_client_middleware.rb +++ b/lib/gitlab/database/load_balancing/sidekiq_client_middleware.rb @@ -32,12 +32,10 @@ module Gitlab def set_data_consistency_locations!(job) # Once we add support for multiple databases to our load balancer, we would use something like this: # job['wal_locations'] = Gitlab::Database::DATABASES.transform_values do |connection| - # connection.load_balancer.primary_write_location. + # connection.load_balancer.primary_write_location # end # - # TODO: Replace hardcoded database config name :main when we merge unification strategy - # https://gitlab.com/gitlab-org/gitlab/-/issues/336566 - job['wal_locations'] = { main: wal_location } if wal_location + job['wal_locations'] = { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location end def wal_location diff --git a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb index 2555f693a5d..f7fda14b215 100644 --- a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb +++ b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb @@ -66,7 +66,7 @@ module Gitlab def legacy_wal_location(job) wal_location = job['database_write_location'] || job['database_replica_location'] - { main: wal_location } if wal_location + { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location end def load_balancing_available?(worker_class) diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb new file mode 100644 index 00000000000..c5acdb41de5 --- /dev/null +++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Gitlab + module DatabaseImporters + module WorkItems + module BaseTypeImporter + def self.import + WorkItem::Type::BASE_TYPES.each do |type, attributes| + WorkItem::Type.create!(base_type: type, **attributes.slice(:name, :icon_name)) + end + end + end + end + end +end diff --git a/lib/gitlab/pagination/cursor_based_keyset.rb b/lib/gitlab/pagination/cursor_based_keyset.rb new file mode 100644 index 00000000000..f19cdf06d9a --- /dev/null +++ b/lib/gitlab/pagination/cursor_based_keyset.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Gitlab + module Pagination + module CursorBasedKeyset + SUPPORTED_ORDERING = { + Group => { name: :asc } + }.freeze + + def self.available_for_type?(relation) + SUPPORTED_ORDERING.key?(relation.klass) + end + + def self.available?(cursor_based_request_context, relation) + available_for_type?(relation) && + order_satisfied?(relation, cursor_based_request_context) + end + + def self.order_satisfied?(relation, cursor_based_request_context) + order_by_from_request = cursor_based_request_context.order_by + + SUPPORTED_ORDERING[relation.klass] == order_by_from_request + end + private_class_method :order_satisfied? + end + end +end diff --git a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb index d9c118ceef5..18390f5b59d 100644 --- a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb +++ b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb @@ -4,11 +4,12 @@ module Gitlab module Pagination module Keyset class CursorBasedRequestContext - attr_reader :request - delegate :params, :header, to: :request + DEFAULT_SORT_DIRECTION = :desc + attr_reader :request_context + delegate :params, to: :request_context - def initialize(request) - @request = request + def initialize(request_context) + @request_context = request_context end def per_page @@ -21,9 +22,13 @@ module Gitlab def apply_headers(cursor_for_next_page) Gitlab::Pagination::Keyset::HeaderBuilder - .new(self) + .new(request_context) .add_next_page_header({ cursor: cursor_for_next_page }) end + + def order_by + { params[:order_by].to_sym => params[:sort]&.to_sym || DEFAULT_SORT_DIRECTION } + end end end end |