diff options
Diffstat (limited to 'app/graphql')
-rw-r--r-- | app/graphql/resolvers/base_resolver.rb | 19 | ||||
-rw-r--r-- | app/graphql/resolvers/concerns/resolves_pipelines.rb | 10 | ||||
-rw-r--r-- | app/graphql/resolvers/issues_resolver.rb | 7 | ||||
-rw-r--r-- | app/graphql/resolvers/project_resolver.rb | 4 | ||||
-rw-r--r-- | app/graphql/types/base_field.rb | 34 | ||||
-rw-r--r-- | app/graphql/types/issue_type.rb | 6 |
6 files changed, 76 insertions, 4 deletions
diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb index 063def75d38..31850c2cadb 100644 --- a/app/graphql/resolvers/base_resolver.rb +++ b/app/graphql/resolvers/base_resolver.rb @@ -9,5 +9,24 @@ module Resolvers end end end + + def self.resolver_complexity(args) + complexity = 1 + complexity += 1 if args[:sort] + complexity += 5 if args[:search] + + complexity + end + + def self.complexity_multiplier(args) + # When fetching many items, additional complexity is added to the field + # depending on how many items is fetched. For each item we add 1% of the + # original complexity - this means that loading 100 items (our default + # maxp_age_size limit) doubles the original complexity. + # + # Complexity is not increased when searching by specific ID(s), because + # complexity difference is minimal in this case. + [args[:iid], args[:iids]].any? ? 0 : 0.01 + end end end diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb index 8fd26d85994..a166211fc18 100644 --- a/app/graphql/resolvers/concerns/resolves_pipelines.rb +++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb @@ -19,6 +19,16 @@ module ResolvesPipelines description: "Filter pipelines by the sha of the commit they are run for" end + class_methods do + def resolver_complexity(args) + complexity = super + complexity += 2 if args[:sha] + complexity += 2 if args[:ref] + + complexity + end + end + def resolve_pipelines(project, params = {}) PipelinesFinder.new(project, context[:current_user], params).execute end diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb index 54d32a688bf..1c3c24ad6dc 100644 --- a/app/graphql/resolvers/issues_resolver.rb +++ b/app/graphql/resolvers/issues_resolver.rb @@ -57,5 +57,12 @@ module Resolvers IssuesFinder.new(context[:current_user], args).execute end + + def self.resolver_complexity(args) + complexity = super + complexity += 2 if args[:labelName] + + complexity + end end end diff --git a/app/graphql/resolvers/project_resolver.rb b/app/graphql/resolvers/project_resolver.rb index ac7c9b0ce2e..2132447da5e 100644 --- a/app/graphql/resolvers/project_resolver.rb +++ b/app/graphql/resolvers/project_resolver.rb @@ -9,5 +9,9 @@ module Resolvers def resolve(full_path:) model_by_full_path(Project, full_path) end + + def self.complexity_multiplier(args) + 0 + end end end diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index 8c8b8a82d3e..15331129134 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -7,10 +7,40 @@ module Types DEFAULT_COMPLEXITY = 1 def initialize(*args, **kwargs, &block) - # complexity is already defaulted to 1, but let's make it explicit - kwargs[:complexity] ||= DEFAULT_COMPLEXITY + kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class]) super(*args, **kwargs, &block) end + + private + + def field_complexity(resolver_class) + if resolver_class + field_resolver_complexity + else + DEFAULT_COMPLEXITY + end + end + + def field_resolver_complexity + # Complexity can be either integer or proc. If proc is used then it's + # called when computing a query complexity and context and query + # arguments are available for computing complexity. For resolvers we use + # proc because we set complexity depending on arguments and number of + # items which can be loaded. + proc do |ctx, args, child_complexity| + page_size = @max_page_size || ctx.schema.default_max_page_size + limit_value = [args[:first], args[:last], page_size].compact.min + + # Resolvers may add extra complexity depending on used arguments + complexity = child_complexity + self.resolver&.try(:resolver_complexity, args).to_i + + # Resolvers may add extra complexity depending on number of items being loaded. + multiplier = self.resolver&.try(:complexity_multiplier, args).to_f + complexity += complexity * limit_value * multiplier + + complexity.to_i + end + end end end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index adb137dfee3..b21a226d07f 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -19,9 +19,11 @@ module Types null: false, resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find } - field :assignees, Types::UserType.connection_type, null: true + # Remove complexity when BatchLoader is used + field :assignees, Types::UserType.connection_type, null: true, complexity: 5 - field :labels, Types::LabelType.connection_type, null: true + # Remove complexity when BatchLoader is used + field :labels, Types::LabelType.connection_type, null: true, complexity: 5 field :milestone, Types::MilestoneType, null: true, resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } |