Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/graphql/pagination/keyset/connection.rb')
-rw-r--r--lib/gitlab/graphql/pagination/keyset/connection.rb97
1 files changed, 26 insertions, 71 deletions
diff --git a/lib/gitlab/graphql/pagination/keyset/connection.rb b/lib/gitlab/graphql/pagination/keyset/connection.rb
index 3e119a39e6d..b074c273996 100644
--- a/lib/gitlab/graphql/pagination/keyset/connection.rb
+++ b/lib/gitlab/graphql/pagination/keyset/connection.rb
@@ -29,7 +29,6 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
include ::Gitlab::Graphql::ConnectionCollectionMethods
prepend ::Gitlab::Graphql::ConnectionRedaction
- prepend GenericKeysetPagination
# rubocop: disable Naming/PredicateName
# https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo.Fields
@@ -58,19 +57,13 @@ module Gitlab
def has_next_page
strong_memoize(:has_next_page) do
if before
- # If `before` is specified, that points to a specific record,
- # even if it's the last one. Since we're asking for `before`,
- # then the specific record we're pointing to is in the
- # next page
true
elsif first
case sliced_nodes
when Array
sliced_nodes.size > limit_value
else
- # If we count the number of requested items plus one (`limit_value + 1`),
- # then if we get `limit_value + 1` then we know there is a next page
- relation_count(set_limit(sliced_nodes, limit_value + 1)) == limit_value + 1
+ sliced_nodes.limit(1).offset(limit_value).exists? # rubocop: disable CodeReuse/ActiveRecord
end
else
false
@@ -80,20 +73,15 @@ module Gitlab
# rubocop: enable Naming/PredicateName
def cursor_for(node)
- encoded_json_from_ordering(node)
+ order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(items)
+ encode(order.cursor_attributes_for_node(node).to_json)
end
def sliced_nodes
- @sliced_nodes ||=
- begin
- OrderInfo.validate_ordering(ordered_items, order_list) unless loaded?(ordered_items)
-
- sliced = ordered_items
- sliced = slice_nodes(sliced, before, :before) if before.present?
- sliced = slice_nodes(sliced, after, :after) if after.present?
-
- sliced
- end
+ sliced = ordered_items
+ sliced = slice_nodes(sliced, before, :before) if before.present?
+ sliced = slice_nodes(sliced, after, :after) if after.present?
+ sliced
end
def nodes
@@ -104,6 +92,20 @@ module Gitlab
@nodes ||= limited_nodes.to_a
end
+ def items
+ original_items = super
+ return original_items if Gitlab::Pagination::Keyset::Order.keyset_aware?(original_items)
+
+ strong_memoize(:keyset_pagination_items) do
+ rebuilt_items_with_keyset_order, success =
+ Gitlab::Pagination::Keyset::SimpleOrderBuilder.build(original_items)
+
+ raise(Gitlab::Pagination::Keyset::UnsupportedScopeOrder) unless success
+
+ rebuilt_items_with_keyset_order
+ end
+ end
+
private
# Apply `first` and `last` to `sliced_nodes`
@@ -129,11 +131,11 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def slice_nodes(sliced, encoded_cursor, before_or_after)
- decoded_cursor = ordering_from_encoded_json(encoded_cursor)
- builder = QueryBuilder.new(arel_table, order_list, decoded_cursor, before_or_after)
- ordering = builder.conditions
+ order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(sliced)
+ order = order.reversed_order if before_or_after == :before
- sliced.where(*ordering).where.not(id: decoded_cursor['id'])
+ decoded_cursor = ordering_from_encoded_json(encoded_cursor)
+ order.apply_cursor_conditions(sliced, decoded_cursor)
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -157,57 +159,10 @@ module Gitlab
raise ArgumentError, 'Relation must have a primary key'
end
- list = OrderInfo.build_order_list(items)
-
- if loaded?(items) && !before.present? && !after.present?
- @order_list = list.presence || [OrderInfo.new(items.primary_key)]
-
- # already sorted, or trivially sorted
- next items if list.present? || items.size <= 1
-
- pkey = items.primary_key.to_sym
- next items.sort_by { |item| item[pkey] }.reverse
- end
-
- # ensure there is a primary key ordering
- if list&.last&.attribute_name != items.primary_key
- items.order(arel_table[items.primary_key].desc) # rubocop: disable CodeReuse/ActiveRecord
- else
- items
- end
- end
- end
-
- def order_list
- strong_memoize(:order_list) do
- OrderInfo.build_order_list(ordered_items)
+ items
end
end
- def arel_table
- items.arel_table
- end
-
- # Storing the current order values in the cursor allows us to
- # make an intelligent decision on handling NULL values.
- # Otherwise we would either need to fetch the record first,
- # or fetch it in the SQL, significantly complicating it.
- def encoded_json_from_ordering(node)
- ordering = { 'id' => node[:id].to_s }
-
- order_list.each do |field|
- field_name = field.try(:attribute_name) || field
- field_value = node[field_name]
- ordering[field_name] = if field_value.is_a?(Time)
- field_value.to_s(:inspect)
- else
- field_value.to_s
- end
- end
-
- encode(ordering.to_json)
- end
-
def ordering_from_encoded_json(cursor)
Gitlab::Json.parse(decode(cursor))
rescue JSON::ParserError