Class: Rails::GraphQL::Request::Component::Field

Inherits:
Rails::GraphQL::Request::Component show all
Includes:
Authorizable, Directives, SelectionSet, ValueWriters
Defined in:
lib/rails/graphql/request/component/field.rb

Overview

GraphQL Request Component Field

This class holds information about a given field that should be collected from the source of where it was requested.

Constant Summary

Constants included from ValueWriters

ValueWriters::KIND_WRITERS

Instance Attribute Summary collapse

Attributes included from SelectionSet

#selection

Instance Method Summary collapse

Methods included from Directives

#directive_events, #directive_listeners

Methods included from ValueWriters

#format_array_exception, #write_array, #write_array!, #write_value

Methods included from Authorizable

#check_authorization!

Methods inherited from Rails::GraphQL::Request::Component

#hash, #invalid?, #invalidate!, kind, #skip!, #unresolvable?

Methods included from Resolvable

#resolve!

Methods included from Preparable

#prepare!, #prepared_data!, #prepared_data?

Methods included from Organizable

#organize!

Constructor Details

#initialize(parent, node) ⇒ Field

Returns a new instance of Field.



25
26
27
28
29
30
31
32
# File 'lib/rails/graphql/request/component/field.rb', line 25

def initialize(parent, node)
  @parent = parent

  @name = node[0]
  @alias_name = node[1]

  super(node)
end

Instance Attribute Details

#alias_nameObject (readonly)

Returns the value of attribute alias_name.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def alias_name
  @alias_name
end

#argumentsObject (readonly) Also known as: args

Returns the value of attribute arguments.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def arguments
  @arguments
end

#current_objectObject (readonly)

Returns the value of attribute current_object.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def current_object
  @current_object
end

#fieldObject (readonly)

Returns the value of attribute field.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def field
  @field
end

#nameObject (readonly)

Returns the value of attribute name.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



21
22
23
# File 'lib/rails/graphql/request/component/field.rb', line 21

def parent
  @parent
end

Instance Method Details

#all_argumentsObject

Get and cache all the arguments for the field



64
65
66
67
68
69
70
71
72
# File 'lib/rails/graphql/request/component/field.rb', line 64

def all_arguments
  return unless field.arguments?

  request.nested_cache(:arguments, field) do
    field.all_arguments.each_value.with_object({}) do |argument, hash|
      hash[argument.gql_name] = argument
    end
  end
end

#all_eventsObject

Override that considers the requested field directives and also the definition field events, both from itself and its directives events



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rails/graphql/request/component/field.rb', line 51

def all_events
  request.nested_cache(:events, field) do
    if !field.events?
      directive_events
    elsif !directives?
      field.all_events
    else
      Helpers.merge_hash_array(field.all_events, directive_events)
    end
  end
end

#all_listenersObject

Override that considers the requested field directives and also the definition field events, both from itself and its directives events



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rails/graphql/request/component/field.rb', line 36

def all_listeners
  request.nested_cache(:listeners, field) do
    if !field.listeners?
      directive_listeners
    elsif !directives?
      field.all_listeners
    else
      local = directive_listeners
      local.empty? ? field.all_listeners : field.all_listeners + local
    end
  end
end

#assign_to(field) ⇒ Object

Assign a given field to this class. The field must be an output field, which means that output_type? must be true. It also must be called exactly once per field.

Raises:



82
83
84
85
86
87
88
# File 'lib/rails/graphql/request/component/field.rb', line 82

def assign_to(field)
  raise ArgumentError, (+<<~MSG).squish if defined?(@assigned)
    The "#{gql_name}" field is already assigned to #{@field.inspect}.
  MSG

  @field = field
end

#assignable?Boolean

Fields are assignable because they are actually the selection, so they need to be assigned to a filed

Returns:

  • (Boolean)


109
110
111
# File 'lib/rails/graphql/request/component/field.rb', line 109

def assignable?
  true
end

#broadcastable?Boolean

Check if all the sub fields are broadcastable TODO: Maybe check for interfaces and if all types allow broadcast

Returns:

  • (Boolean)


115
116
117
118
119
# File 'lib/rails/graphql/request/component/field.rb', line 115

def broadcastable?
  value = field.broadcastable?
  value = schema.config.default_subscription_broadcastable if value.nil?
  value != false
end

#cache_dumpObject

Build the cache object TODO: Add the arguments into the GID, but the problem is variables



161
162
163
# File 'lib/rails/graphql/request/component/field.rb', line 161

def cache_dump
  super.merge(field: (field && all_to_gid(field)))
end

#cache_load(data) ⇒ Object

Organize from cache data



166
167
168
169
170
171
172
173
# File 'lib/rails/graphql/request/component/field.rb', line 166

def cache_load(data)
  @name = data[:node][0]
  @alias_name = data[:node][1]
  @field = all_from_gid(data[:field])
  super

  check_authorization! unless unresolvable?
end

#entry_point?Boolean

Check if the field is an entry point, meaning that it is attached to an owner that has Schema Fields

Returns:

  • (Boolean)


102
103
104
105
# File 'lib/rails/graphql/request/component/field.rb', line 102

def entry_point?
  return @entry_point if defined?(@entry_point)
  @entry_point = field.entry_point?
end

#gql_nameObject

Return the name of the field to be used on the response



91
92
93
# File 'lib/rails/graphql/request/component/field.rb', line 91

def gql_name
  alias_name || name
end

#of_type?(klass) ⇒ Boolean

A little extension of the is_a? method that allows checking it using the underlying field

Returns:

  • (Boolean)


129
130
131
# File 'lib/rails/graphql/request/component/field.rb', line 129

def of_type?(klass)
  super || field.of_type?(klass)
end

#resolve_invalid(error = nil) ⇒ Object

When the field is invalid, there’s no much to do TODO: Maybe add a invalid event trigger here



135
136
137
138
139
140
141
142
# File 'lib/rails/graphql/request/component/field.rb', line 135

def resolve_invalid(error = nil)
  request.exception_to_error(error, self) if error.present?

  validate_output!(nil)
  response.safe_add(gql_name, nil)
rescue InvalidValueError
  raise unless entry_point?
end

#resolve_with!(object) ⇒ Object

When the type_klass of an object is an interface or a union, the field needs to be redirected to the one from the actual resolved object type



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rails/graphql/request/component/field.rb', line 147

def resolve_with!(object)
  return if skipped?
  return resolve! if invalid?

  old_field, @field = @field, object[@field.name]
  request.nested_cache(:listeners, field) { strategy.add_listeners_from(self) }
  @current_object = object
  resolve!
ensure
  @field, @current_object = old_field, nil
end

#skipped?Boolean

Override this to also check if the key would be added to the response again

Returns:

  • (Boolean)


123
124
125
# File 'lib/rails/graphql/request/component/field.rb', line 123

def skipped?
  super || response.key?(gql_name)
end

#typenameObject

A little helper for finding the correct parent type name



96
97
98
# File 'lib/rails/graphql/request/component/field.rb', line 96

def typename
  (try(:current_object) || try(:type_klass))&.gql_name
end

#using?(item_or_symbol) ⇒ Boolean

Check if the field is using a directive

Returns:

  • (Boolean)


75
76
77
# File 'lib/rails/graphql/request/component/field.rb', line 75

def using?(item_or_symbol)
  super || field.using?(item_or_symbol)
end