diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 12:55:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 12:55:51 +0300 |
commit | e8d2c2579383897a1dd7f9debd359abe8ae8373d (patch) | |
tree | c42be41678c2586d49a75cabce89322082698334 /lib/gitlab/pagination | |
parent | fc845b37ec3a90aaa719975f607740c22ba6a113 (diff) |
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'lib/gitlab/pagination')
-rw-r--r-- | lib/gitlab/pagination/keyset/column_order_definition.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/pagination/keyset/iterator.rb | 8 | ||||
-rw-r--r-- | lib/gitlab/pagination/keyset/order.rb | 24 | ||||
-rw-r--r-- | lib/gitlab/pagination/offset_pagination.rb | 15 |
4 files changed, 43 insertions, 8 deletions
diff --git a/lib/gitlab/pagination/keyset/column_order_definition.rb b/lib/gitlab/pagination/keyset/column_order_definition.rb index 0c8ec02a56b..0755af9587b 100644 --- a/lib/gitlab/pagination/keyset/column_order_definition.rb +++ b/lib/gitlab/pagination/keyset/column_order_definition.rb @@ -120,7 +120,7 @@ module Gitlab AREL_ORDER_CLASSES = { Arel::Nodes::Ascending => :asc, Arel::Nodes::Descending => :desc }.freeze ALLOWED_NULLABLE_VALUES = [:not_nullable, :nulls_first, :nulls_last].freeze - attr_reader :attribute_name, :column_expression, :order_expression, :add_to_projections + attr_reader :attribute_name, :column_expression, :order_expression, :add_to_projections, :order_direction def initialize(attribute_name:, order_expression:, column_expression: nil, reversed_order_expression: nil, nullable: :not_nullable, distinct: true, order_direction: nil, add_to_projections: false) @attribute_name = attribute_name @@ -175,7 +175,7 @@ module Gitlab private - attr_reader :reversed_order_expression, :nullable, :distinct, :order_direction + attr_reader :reversed_order_expression, :nullable, :distinct def calculate_reversed_order(order_expression) unless AREL_ORDER_CLASSES.has_key?(order_expression.class) # Arel can reverse simple orders diff --git a/lib/gitlab/pagination/keyset/iterator.rb b/lib/gitlab/pagination/keyset/iterator.rb index 3bc8c0bf616..c6f0014a0f4 100644 --- a/lib/gitlab/pagination/keyset/iterator.rb +++ b/lib/gitlab/pagination/keyset/iterator.rb @@ -4,8 +4,12 @@ module Gitlab module Pagination module Keyset class Iterator - def initialize(scope:, use_union_optimization: false) - @scope = scope + UnsupportedScopeOrder = Class.new(StandardError) + + def initialize(scope:, use_union_optimization: true) + @scope, success = Gitlab::Pagination::Keyset::SimpleOrderBuilder.build(scope) + raise(UnsupportedScopeOrder, 'The order on the scope does not support keyset pagination') unless success + @order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(scope) @use_union_optimization = use_union_optimization end diff --git a/lib/gitlab/pagination/keyset/order.rb b/lib/gitlab/pagination/keyset/order.rb index cef3a7b291a..19d44ee69dd 100644 --- a/lib/gitlab/pagination/keyset/order.rb +++ b/lib/gitlab/pagination/keyset/order.rb @@ -139,6 +139,8 @@ module Gitlab verify_incoming_values!(values) + return use_composite_row_comparison(values) if composite_row_comparison_possible? + where_values = [] reversed_column_definitions = column_definitions.reverse @@ -187,6 +189,28 @@ module Gitlab private + def composite_row_comparison_possible? + !column_definitions.one? && + column_definitions.all?(&:not_nullable?) && + column_definitions.map(&:order_direction).uniq.one? # all columns uses the same order direction + end + + # composite row comparison works with NOT NULL columns and may use only one index scan given a proper index setup + # Example: (created_at, id) > ('2012-09-18 01:40:01+00', 15) + def use_composite_row_comparison(values) + columns = Arel::Nodes::Grouping.new(column_definitions.map(&:column_expression)) + values = Arel::Nodes::Grouping.new(column_definitions.map do |column_definition| + value = values[column_definition.attribute_name] + Arel::Nodes.build_quoted(value, column_definition.column_expression) + end) + + if column_definitions.first.ascending_order? + [columns.gt(values)] + else + [columns.lt(values)] + end + end + # Adds extra columns to the SELECT clause def apply_custom_projections(scope) additional_projections = column_definitions.select(&:add_to_projections).map do |column_definition| diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb index 2805b12d95d..4f8a6ffb2cc 100644 --- a/lib/gitlab/pagination/offset_pagination.rb +++ b/lib/gitlab/pagination/offset_pagination.rb @@ -19,11 +19,10 @@ module Gitlab private def paginate_with_limit_optimization(relation) - # do not paginate relation if it is already paginated - pagination_data = if relation.respond_to?(:current_page) && relation.current_page == params[:page] && relation.limit_value == params[:per_page] - relation - else + pagination_data = if needs_pagination?(relation) relation.page(params[:page]).per(params[:per_page]) + else + relation end return pagination_data unless pagination_data.is_a?(ActiveRecord::Relation) @@ -39,6 +38,14 @@ module Gitlab end end + def needs_pagination?(relation) + return true unless relation.respond_to?(:current_page) + return true if params[:page].present? && relation.current_page != params[:page].to_i + return true if params[:per_page].present? && relation.limit_value != params[:per_page].to_i + + false + end + def add_default_order(relation) if relation.is_a?(ActiveRecord::Relation) && relation.order_values.empty? relation = relation.order(:id) # rubocop: disable CodeReuse/ActiveRecord |