diff options
Diffstat (limited to 'lib/gitlab/graphql')
-rw-r--r-- | lib/gitlab/graphql/errors.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/graphql/limit/field_call_count.rb | 32 | ||||
-rw-r--r-- | lib/gitlab/graphql/pagination/keyset/connection.rb | 28 | ||||
-rw-r--r-- | lib/gitlab/graphql/pagination/keyset/last_items.rb | 25 | ||||
-rw-r--r-- | lib/gitlab/graphql/type_name_deprecations.rb | 3 |
5 files changed, 55 insertions, 34 deletions
diff --git a/lib/gitlab/graphql/errors.rb b/lib/gitlab/graphql/errors.rb index 40b90310e8b..657364abfdf 100644 --- a/lib/gitlab/graphql/errors.rb +++ b/lib/gitlab/graphql/errors.rb @@ -7,6 +7,7 @@ module Gitlab ArgumentError = Class.new(BaseError) ResourceNotAvailable = Class.new(BaseError) MutationError = Class.new(BaseError) + LimitError = Class.new(BaseError) end end end diff --git a/lib/gitlab/graphql/limit/field_call_count.rb b/lib/gitlab/graphql/limit/field_call_count.rb new file mode 100644 index 00000000000..4165970a2a6 --- /dev/null +++ b/lib/gitlab/graphql/limit/field_call_count.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Gitlab + module Graphql + module Limit + class FieldCallCount < ::GraphQL::Schema::FieldExtension + def resolve(object:, arguments:, context:) + raise Gitlab::Graphql::Errors::ArgumentError, 'Limit must be specified.' unless limit + raise Gitlab::Graphql::Errors::LimitError, error_message if increment_call_count(context) > limit + + yield(object, arguments) + end + + private + + def increment_call_count(context) + context[:call_count] ||= {} + context[:call_count][field] ||= 0 + context[:call_count][field] += 1 + end + + def limit + options[:limit] + end + + def error_message + "\"#{field.graphql_name}\" field can be requested only for #{limit} #{field.owner.graphql_name}(s) at a time." + end + end + end + end +end diff --git a/lib/gitlab/graphql/pagination/keyset/connection.rb b/lib/gitlab/graphql/pagination/keyset/connection.rb index b074c273996..987a5e7b74b 100644 --- a/lib/gitlab/graphql/pagination/keyset/connection.rb +++ b/lib/gitlab/graphql/pagination/keyset/connection.rb @@ -59,11 +59,15 @@ module Gitlab if before true elsif first - case sliced_nodes - when Array - sliced_nodes.size > limit_value + if Feature.enabled?(:graphql_keyset_pagination_without_next_page_query) + limited_nodes.size > limit_value else - sliced_nodes.limit(1).offset(limit_value).exists? # rubocop: disable CodeReuse/ActiveRecord + case sliced_nodes + when Array + sliced_nodes.size > limit_value + else + sliced_nodes.limit(1).offset(limit_value).exists? # rubocop: disable CodeReuse/ActiveRecord + end end else false @@ -89,7 +93,7 @@ module Gitlab # So we're ok loading them into memory here as that's bound to happen # anyway. Having them ready means we can modify the result while # rendering the fields. - @nodes ||= limited_nodes.to_a + @nodes ||= limited_nodes.to_a.take(limit_value) # rubocop: disable CodeReuse/ActiveRecord end def items @@ -116,15 +120,21 @@ module Gitlab end if last - paginated_nodes = LastItems.take_items(sliced_nodes, limit_value + 1) + paginated_nodes = sliced_nodes.last(limit_value + 1) # there is an extra node, so there is a previous page @has_previous_page = paginated_nodes.count > limit_value @has_previous_page ? paginated_nodes.last(limit_value) : paginated_nodes elsif loaded?(sliced_nodes) - sliced_nodes.take(limit_value) # rubocop: disable CodeReuse/ActiveRecord + if Feature.enabled?(:graphql_keyset_pagination_without_next_page_query) + sliced_nodes.take(limit_value + 1) # rubocop: disable CodeReuse/ActiveRecord + else + sliced_nodes.take(limit_value) # rubocop: disable CodeReuse/ActiveRecord + end + elsif Feature.enabled?(:graphql_keyset_pagination_without_next_page_query) + sliced_nodes.limit(limit_value + 1).to_a else - sliced_nodes.limit(limit_value) # rubocop: disable CodeReuse/ActiveRecord + sliced_nodes.limit(limit_value) end end end @@ -141,7 +151,7 @@ module Gitlab def limit_value # note: only first _or_ last can be specified, not both - @limit_value ||= [first, last, max_page_size].compact.min + @limit_value ||= [first, last, max_page_size, GitlabSchema.default_max_page_size].compact.min end def loaded?(items) diff --git a/lib/gitlab/graphql/pagination/keyset/last_items.rb b/lib/gitlab/graphql/pagination/keyset/last_items.rb deleted file mode 100644 index 960567a6fbc..00000000000 --- a/lib/gitlab/graphql/pagination/keyset/last_items.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Graphql - module Pagination - module Keyset - # This class handles the last(N) ActiveRecord call even if a special ORDER BY configuration is present. - # For the last(N) call, ActiveRecord calls reverse_order, however for some cases it raises - # ActiveRecord::IrreversibleOrderError error. - class LastItems - # rubocop: disable CodeReuse/ActiveRecord - def self.take_items(scope, count) - if Gitlab::Pagination::Keyset::Order.keyset_aware?(scope) - order = Gitlab::Pagination::Keyset::Order.extract_keyset_order_object(scope) - items = scope.reorder(order.reversed_order).first(count) - items.is_a?(Array) ? items.reverse : items - else - scope.last(count) - end - end - end - end - end - end -end diff --git a/lib/gitlab/graphql/type_name_deprecations.rb b/lib/gitlab/graphql/type_name_deprecations.rb index c27ad1d54f5..1ec6fd1c09f 100644 --- a/lib/gitlab/graphql/type_name_deprecations.rb +++ b/lib/gitlab/graphql/type_name_deprecations.rb @@ -14,6 +14,9 @@ module Gitlab DEPRECATIONS = [ Gitlab::Graphql::DeprecationsBase::NameDeprecation.new( old_name: 'CiRunnerUpgradeStatusType', new_name: 'CiRunnerUpgradeStatus', milestone: '15.3' + ), + Gitlab::Graphql::DeprecationsBase::NameDeprecation.new( + old_name: 'RunnerMembershipFilter', new_name: 'CiRunnerMembershipFilter', milestone: '15.4' ) ].freeze |