Class: Types::BaseField

Inherits:
GraphQL::Schema::Field
  • Object
show all
Includes:
Gitlab::Graphql::Authorize::AuthorizeResource, Gitlab::Graphql::Deprecations
Defined in:
app/graphql/types/base_field.rb

Direct Known Subclasses

Ci::JobBaseField

Constant Summary collapse

DEFAULT_COMPLEXITY =
1

Constants included from Gitlab::Graphql::Authorize::AuthorizeResource

Gitlab::Graphql::Authorize::AuthorizeResource::ConfigurationError, Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Graphql::Authorize::AuthorizeResource

#authorize!, #authorized_find!, #authorized_resource?, #find_object, #raise_resource_not_available_error!

Methods included from Gitlab::Graphql::Deprecations

#visible?

Constructor Details

#initialize(**kwargs, &block) ⇒ BaseField

Returns a new instance of BaseField.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/graphql/types/base_field.rb', line 15

def initialize(**kwargs, &block)
  @requires_argument = kwargs.delete(:requires_argument)
  @calls_gitaly = kwargs.delete(:calls_gitaly)
  @doc_reference = kwargs.delete(:see)

  given_complexity = kwargs[:complexity] || kwargs[:resolver_class].try(:complexity)
  @constant_complexity = given_complexity.is_a?(Integer) && given_complexity > 0
  kwargs[:complexity] = field_complexity(kwargs[:resolver_class], given_complexity)

  @authorize = Array.wrap(kwargs.delete(:authorize))
  @skip_type_authorization = Array.wrap(kwargs.delete(:skip_type_authorization))
  @scopes = Array.wrap(kwargs.delete(:scopes) || %i[api read_api])
  after_connection_extensions = kwargs.delete(:late_extensions) || []

  super(**kwargs, &block)

  # We want to avoid the overhead of this in prod
  extension ::Gitlab::Graphql::CallsGitaly::FieldExtension if Gitlab.dev_or_test_env?
  extension ::Gitlab::Graphql::Present::FieldExtension
  extension ::Gitlab::Graphql::Authorize::FieldExtension

  after_connection_extensions.each { extension _1 } if after_connection_extensions.any?
end

Instance Attribute Details

#doc_referenceObject (readonly)

Returns the value of attribute doc_reference.



12
13
14
# File 'app/graphql/types/base_field.rb', line 12

def doc_reference
  @doc_reference
end

#skip_type_authorizationObject

Returns the value of attribute skip_type_authorization.



13
14
15
# File 'app/graphql/types/base_field.rb', line 13

def skip_type_authorization
  @skip_type_authorization
end

Instance Method Details

#authorized?(object, args, ctx) ⇒ Boolean

By default fields authorize against the current object, but that is not how our resolvers work - they use declarative permissions to authorize fields manually (so we make them opt in). TODO: gitlab.com/gitlab-org/gitlab/-/issues/300922

(separate out authorize into permissions on the object, and on the
resolved values)

We do not support argument authorization in our schema. If/when we do, we should call ‘super` here, to apply argument authorization checks. See: gitlab.com/gitlab-org/gitlab/-/issues/324647

Returns:

  • (Boolean)


57
58
59
# File 'app/graphql/types/base_field.rb', line 57

def authorized?(object, args, ctx)
  field_authorized?(object, ctx) && resolver_authorized?(object, ctx)
end

#base_complexityObject



85
86
87
88
89
# File 'app/graphql/types/base_field.rb', line 85

def base_complexity
  complexity = DEFAULT_COMPLEXITY
  complexity += 1 if calls_gitaly?
  complexity
end

#calls_gitaly?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'app/graphql/types/base_field.rb', line 91

def calls_gitaly?
  !!(@calls_gitaly.nil? ? @resolver_class.try(:calls_gitaly?) : @calls_gitaly)
end

#complexity_for(child_complexity:, query:, lookahead:) ⇒ Object

This gets called from the gem’s ‘calculate_complexity` method, allowing us to ensure our complexity calculation is used even for connections. This code is actually a copy of the default case in `calculate_complexity` in `lib/graphql/schema/field.rb` (github.com/rmosolgo/graphql-ruby/blob/master/lib/graphql/schema/field.rb)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/graphql/types/base_field.rb', line 66

def complexity_for(child_complexity:, query:, lookahead:)
  defined_complexity = complexity

  case defined_complexity
  when Proc
    arguments = query.arguments_for(lookahead.ast_nodes.first, self)

    if arguments.respond_to?(:keyword_arguments)
      defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
    else
      child_complexity
    end
  when Numeric
    defined_complexity + child_complexity
  else
    raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
  end
end

#constant_complexity?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'app/graphql/types/base_field.rb', line 95

def constant_complexity?
  @constant_complexity
end

#may_call_gitaly?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'app/graphql/types/base_field.rb', line 39

def may_call_gitaly?
  @constant_complexity || calls_gitaly?
end

#requires_argument?Boolean

Returns:

  • (Boolean)


43
44
45
46
# File 'app/graphql/types/base_field.rb', line 43

def requires_argument?
  value = @requires_argument.nil? ? @resolver_class.try(:requires_argument?) : @requires_argument
  !!value || arguments.values.any? { |argument| argument.type.non_null? }
end