2018-09-11 19:08:34 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-05-23 07:55:14 +00:00
|
|
|
module Types
|
|
|
|
class BaseField < GraphQL::Schema::Field
|
|
|
|
prepend Gitlab::Graphql::Authorize
|
2019-03-27 20:02:25 +00:00
|
|
|
|
2019-06-16 10:12:56 +00:00
|
|
|
attr_reader :calls_gitaly
|
|
|
|
|
2019-03-27 20:02:25 +00:00
|
|
|
DEFAULT_COMPLEXITY = 1
|
|
|
|
|
|
|
|
def initialize(*args, **kwargs, &block)
|
2019-06-16 10:12:56 +00:00
|
|
|
@calls_gitaly = !!kwargs.delete(:calls_gitaly)
|
2019-05-06 21:24:19 +00:00
|
|
|
kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class])
|
2019-03-27 20:02:25 +00:00
|
|
|
|
|
|
|
super(*args, **kwargs, &block)
|
|
|
|
end
|
2019-05-06 21:24:19 +00:00
|
|
|
|
2019-06-16 10:12:56 +00:00
|
|
|
def base_complexity
|
|
|
|
complexity = DEFAULT_COMPLEXITY
|
|
|
|
complexity += 1 if @calls_gitaly
|
|
|
|
complexity
|
|
|
|
end
|
|
|
|
|
2019-06-21 14:20:00 +00:00
|
|
|
def calls_gitaly_check(calls)
|
|
|
|
return if @calls_gitaly
|
2019-06-26 10:42:25 +00:00
|
|
|
return if calls < 1
|
2019-06-21 14:20:00 +00:00
|
|
|
|
|
|
|
# Will inform you if :calls_gitaly should be true or false based on the number of Gitaly calls
|
|
|
|
# involved with the request.
|
2019-06-26 10:42:25 +00:00
|
|
|
raise "Gitaly is called for field '#{name}' #{"on type #{owner.name} " if owner}- please add `calls_gitaly: true` to the field declaration"
|
2019-06-21 14:20:00 +00:00
|
|
|
rescue => e
|
|
|
|
Gitlab::Sentry.track_exception(e)
|
|
|
|
end
|
|
|
|
|
2019-05-06 21:24:19 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def field_complexity(resolver_class)
|
|
|
|
if resolver_class
|
|
|
|
field_resolver_complexity
|
|
|
|
else
|
2019-06-16 10:12:56 +00:00
|
|
|
base_complexity
|
2019-05-06 21:24:19 +00:00
|
|
|
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|
|
|
|
|
# Resolvers may add extra complexity depending on used arguments
|
2019-05-31 16:46:16 +00:00
|
|
|
complexity = child_complexity + self.resolver&.try(:resolver_complexity, args, child_complexity: child_complexity).to_i
|
2019-05-06 21:24:19 +00:00
|
|
|
|
2019-06-05 15:16:50 +00:00
|
|
|
field_defn = to_graphql
|
|
|
|
|
|
|
|
if field_defn.connection?
|
2019-06-04 22:52:06 +00:00
|
|
|
# Resolvers may add extra complexity depending on number of items being loaded.
|
2019-06-05 15:16:50 +00:00
|
|
|
page_size = field_defn.connection_max_page_size || ctx.schema.default_max_page_size
|
2019-06-04 22:52:06 +00:00
|
|
|
limit_value = [args[:first], args[:last], page_size].compact.min
|
|
|
|
multiplier = self.resolver&.try(:complexity_multiplier, args).to_f
|
|
|
|
complexity += complexity * limit_value * multiplier
|
|
|
|
end
|
2019-05-06 21:24:19 +00:00
|
|
|
|
|
|
|
complexity.to_i
|
|
|
|
end
|
|
|
|
end
|
2018-05-23 07:55:14 +00:00
|
|
|
end
|
|
|
|
end
|