debian-mirror-gitlab/app/graphql/gitlab_schema.rb

187 lines
5.9 KiB
Ruby
Raw Normal View History

2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2018-11-08 19:23:39 +05:30
class GitlabSchema < GraphQL::Schema
2019-07-07 11:18:12 +05:30
# Currently an IntrospectionQuery has a complexity of 179.
# These values will evolve over time.
2021-10-27 15:23:28 +05:30
DEFAULT_MAX_COMPLEXITY = 200
AUTHENTICATED_MAX_COMPLEXITY = 250
ADMIN_MAX_COMPLEXITY = 300
2019-07-07 11:18:12 +05:30
2019-09-04 21:01:54 +05:30
DEFAULT_MAX_DEPTH = 15
AUTHENTICATED_MAX_DEPTH = 20
2021-12-11 22:18:48 +05:30
# Tracers (order is important)
use Gitlab::Graphql::Tracers::ApplicationContextTracer
use Gitlab::Graphql::Tracers::MetricsTracer
use Gitlab::Graphql::Tracers::LoggerTracer
2022-07-23 23:45:48 +05:30
# TODO: Old tracer which will be removed eventually
# See https://gitlab.com/gitlab-org/gitlab/-/issues/345396
use Gitlab::Graphql::GenericTracing
2021-12-11 22:18:48 +05:30
use Gitlab::Graphql::Tracers::TimerTracer
2023-06-20 00:43:36 +05:30
use Gitlab::Graphql::Subscriptions::ActionCableWithLoadBalancing
2018-11-08 19:23:39 +05:30
use BatchLoader::GraphQL
2020-04-22 19:07:51 +05:30
use Gitlab::Graphql::Pagination::Connections
2020-04-08 14:13:33 +05:30
use Gitlab::Graphql::Timeout, max_seconds: Gitlab.config.gitlab.graphql_timeout
2019-07-07 11:18:12 +05:30
2022-07-23 23:45:48 +05:30
query_analyzer Gitlab::Graphql::QueryAnalyzers::AST::LoggerAnalyzer
query_analyzer Gitlab::Graphql::QueryAnalyzers::AST::RecursionAnalyzer
2019-07-07 11:18:12 +05:30
2019-10-31 01:37:42 +05:30
query Types::QueryType
mutation Types::MutationType
2021-06-08 01:23:25 +05:30
subscription Types::SubscriptionType
2019-10-31 01:37:42 +05:30
default_max_page_size 100
2019-07-07 11:18:12 +05:30
2021-12-07 22:27:20 +05:30
validate_max_errors 5
validate_timeout 0.2.seconds
2021-01-29 00:20:46 +05:30
lazy_resolve ::Gitlab::Graphql::Lazy, :force
2019-09-04 21:01:54 +05:30
class << self
def multiplex(queries, **kwargs)
2021-04-29 21:17:54 +05:30
kwargs[:max_complexity] ||= max_query_complexity(kwargs[:context]) unless kwargs.key?(:max_complexity)
2019-07-07 11:18:12 +05:30
2019-09-04 21:01:54 +05:30
queries.each do |query|
2021-10-27 15:23:28 +05:30
query[:max_complexity] ||= max_query_complexity(query[:context]) unless query.key?(:max_complexity)
query[:max_depth] = max_query_depth(query[:context]) unless query.key?(:max_depth)
2019-09-04 21:01:54 +05:30
end
super(queries, **kwargs)
end
2022-07-23 23:45:48 +05:30
def get_type(type_name, context = GraphQL::Query::NullContext)
2021-09-04 01:27:46 +05:30
type_name = Gitlab::GlobalId::Deprecations.apply_to_graphql_name(type_name)
2022-08-27 11:52:29 +05:30
type_name = Gitlab::Graphql::TypeNameDeprecations.apply_to_graphql_name(type_name)
2021-09-04 01:27:46 +05:30
2022-07-23 23:45:48 +05:30
super(type_name, context)
2020-10-24 23:57:45 +05:30
end
2019-12-26 22:10:19 +05:30
def id_from_object(object, _type = nil, _ctx = nil)
2019-09-04 21:01:54 +05:30
unless object.respond_to?(:to_global_id)
# This is an error in our schema and needs to be solved. So raise a
2019-12-04 20:38:33 +05:30
# more meaningful error message
2019-09-04 21:01:54 +05:30
raise "#{object} does not implement `to_global_id`. "\
"Include `GlobalID::Identification` into `#{object.class}"
end
object.to_global_id
end
2020-03-13 15:44:24 +05:30
# Find an object by looking it up from its global ID, passed as a string.
#
# This is the composition of 'parse_gid' and 'find_by_gid', see these
# methods for further documentation.
def object_from_id(global_id, ctx = {})
gid = parse_gid(global_id, ctx)
find_by_gid(gid)
end
2019-09-04 21:01:54 +05:30
2021-01-29 00:20:46 +05:30
def resolve_type(type, object, ctx = :__undefined__)
2022-07-23 23:45:48 +05:30
return if type.respond_to?(:assignable?) && !type.assignable?(object)
2021-01-29 00:20:46 +05:30
super
end
2020-03-13 15:44:24 +05:30
# Find an object by looking it up from its 'GlobalID'.
#
# * For `ApplicationRecord`s, this is equivalent to
# `global_id.model_class.find(gid.model_id)`, but more efficient.
# * For classes that implement `.lazy_find(global_id)`, this class method
# will be called.
# * All other classes will use `GlobalID#find`
def find_by_gid(gid)
2020-10-24 23:57:45 +05:30
return unless gid
2019-09-04 21:01:54 +05:30
if gid.model_class < ApplicationRecord
Gitlab::Graphql::Loaders::BatchModelLoader.new(gid.model_class, gid.model_id).find
2019-09-30 21:07:59 +05:30
elsif gid.model_class.respond_to?(:lazy_find)
gid.model_class.lazy_find(gid.model_id)
2019-09-04 21:01:54 +05:30
else
gid.find
end
end
2020-03-13 15:44:24 +05:30
# Parse a string to a GlobalID, raising ArgumentError if there are problems
# with it.
#
# Problems that may occur:
# * it may not be syntactically valid
# * it may not match the expected type (see below)
#
# Options:
# * :expected_type [Class] - the type of object this GlobalID should refer to.
2021-04-29 21:17:54 +05:30
# * :expected_type [[Class]] - array of the types of object this GlobalID should refer to.
2020-03-13 15:44:24 +05:30
#
# e.g.
#
# ```
# gid = GitlabSchema.parse_gid(my_string, expected_type: ::Project)
# project_id = gid.model_id
# gid.model_class == ::Project
# ```
def parse_gid(global_id, ctx = {})
2021-04-29 21:17:54 +05:30
expected_types = Array(ctx[:expected_type])
2020-03-13 15:44:24 +05:30
gid = GlobalID.parse(global_id)
2020-11-24 15:15:51 +05:30
raise Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab ID." unless gid
2020-03-13 15:44:24 +05:30
2021-04-29 21:17:54 +05:30
if expected_types.any? && expected_types.none? { |type| gid.model_class.ancestors.include?(type) }
vars = { global_id: global_id, expected_types: expected_types.join(', ') }
msg = _('%{global_id} is not a valid ID for %{expected_types}.') % vars
2020-03-13 15:44:24 +05:30
raise Gitlab::Graphql::Errors::ArgumentError, msg
end
gid
end
2022-11-25 23:54:43 +05:30
# Parse an array of strings to an array of GlobalIDs, raising ArgumentError if there are problems
# with it.
# See #parse_gid
#
# ```
# gids = GitlabSchema.parse_gids(my_array_of_strings, expected_type: ::Project)
# project_ids = gids.map(&:model_id)
# gids.all? { |gid| gid.model_class == ::Project }
# ```
def parse_gids(global_ids, ctx = {})
global_ids.map { |gid| parse_gid(gid, ctx) }
end
2019-09-04 21:01:54 +05:30
private
def max_query_complexity(ctx)
current_user = ctx&.fetch(:current_user, nil)
if current_user&.admin
2021-10-27 15:23:28 +05:30
ADMIN_MAX_COMPLEXITY
2019-09-04 21:01:54 +05:30
elsif current_user
2021-10-27 15:23:28 +05:30
AUTHENTICATED_MAX_COMPLEXITY
2019-09-04 21:01:54 +05:30
else
DEFAULT_MAX_COMPLEXITY
end
end
2019-07-07 11:18:12 +05:30
2019-09-04 21:01:54 +05:30
def max_query_depth(ctx)
current_user = ctx&.fetch(:current_user, nil)
2019-07-07 11:18:12 +05:30
2019-09-04 21:01:54 +05:30
if current_user
AUTHENTICATED_MAX_DEPTH
else
DEFAULT_MAX_DEPTH
end
2019-07-07 11:18:12 +05:30
end
end
2020-10-24 23:57:45 +05:30
def get_type(type_name)
2021-09-04 01:27:46 +05:30
type_name = Gitlab::GlobalId::Deprecations.apply_to_graphql_name(type_name)
2022-08-27 11:52:29 +05:30
type_name = Gitlab::Graphql::TypeNameDeprecations.apply_to_graphql_name(type_name)
2021-09-04 01:27:46 +05:30
2020-10-24 23:57:45 +05:30
super(type_name)
end
2018-11-08 19:23:39 +05:30
end
2020-04-08 14:13:33 +05:30
2021-06-08 01:23:25 +05:30
GitlabSchema.prepend_mod_with('GitlabSchema') # rubocop: disable Cop/InjectEnterpriseEditionModule