summaryrefslogtreecommitdiff
path: root/lib/gitlab/graphql/pagination/active_record_array_connection.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/graphql/pagination/active_record_array_connection.rb')
-rw-r--r--lib/gitlab/graphql/pagination/active_record_array_connection.rb90
1 files changed, 90 insertions, 0 deletions
diff --git a/lib/gitlab/graphql/pagination/active_record_array_connection.rb b/lib/gitlab/graphql/pagination/active_record_array_connection.rb
new file mode 100644
index 00000000000..9e40f79b2fd
--- /dev/null
+++ b/lib/gitlab/graphql/pagination/active_record_array_connection.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+# Connection for an array of Active Record instances.
+# Resolvers needs to handle cursors (before and after).
+# This connection will handle (first and last).
+# Supports batch loaded items.
+# Expects the array to use a fixed DESC order. This is similar to
+# ExternallyPaginatedArrayConnection.
+module Gitlab
+ module Graphql
+ module Pagination
+ class ActiveRecordArrayConnection < GraphQL::Pagination::ArrayConnection
+ include ::Gitlab::Graphql::ConnectionCollectionMethods
+ prepend ::Gitlab::Graphql::ConnectionRedaction
+
+ delegate :<<, to: :items
+
+ def nodes
+ load_nodes
+
+ @nodes
+ end
+
+ def next_page?
+ load_nodes
+
+ if before
+ true
+ elsif first
+ limit_value < items.size
+ else
+ false
+ end
+ end
+
+ def previous_page?
+ load_nodes
+
+ if after
+ true
+ elsif last
+ limit_value < items.size
+ else
+ false
+ end
+ end
+
+ # see https://graphql-ruby.org/pagination/custom_connections#connection-wrapper
+ alias_method :has_next_page, :next_page?
+ alias_method :has_previous_page, :previous_page?
+
+ def cursor_for(item)
+ # item could be a batch loaded item. Sync it to have the id.
+ cursor = { 'id' => Gitlab::Graphql::Lazy.force(item).id.to_s }
+ encode(cursor.to_json)
+ end
+
+ # Part of the implied interface for default objects for BatchLoader: objects must be clonable
+ def dup
+ self.class.new(
+ items.dup,
+ first: first,
+ after: after,
+ max_page_size: max_page_size,
+ last: last,
+ before: before
+ )
+ end
+
+ private
+
+ def limit_value
+ # note: only first _or_ last can be specified, not both
+ @limit_value ||= [first, last, max_page_size].compact.min
+ end
+
+ def load_nodes
+ @nodes ||= begin
+ limited_nodes = items
+
+ limited_nodes = limited_nodes.first(first) if first
+ limited_nodes = limited_nodes.last(last) if last
+
+ limited_nodes
+ end
+ end
+ end
+ end
+ end
+end