Class: Rails::GraphQL::Field

Inherits:
Object
  • Object
show all
Extended by:
ActiveSupport::Autoload
Includes:
Helpers::WithDescription, Helpers::WithDirectives
Defined in:
lib/rails/graphql/field.rb

Overview

GraphQL Field

A field has multiple purposes, which is defined by the specific subclass used. They are also, in various ways, similar to arguments, since they tend to have the same structure. array as input.

Options

  • :owner - The main object that this field belongs to.

  • :null - Marks if the overall type can be null (defaults to true).

  • :array - Marks if the type should be wrapped as an array (defaults to false).

  • :nullable - Marks if the internal values of an array can be null (defaults to true).

  • :full - Shortcut for null: false, nullable: false, array: true (defaults to false).

  • :enabled - Mark the field as enabled (defaults to true).

  • :disabled - Works as the opposite of the enabled option (defaults to false).

  • :directives - The list of directives associated with the value (defaults to nil).

  • :desc - The description of the argument (defaults to nil).

It also accepts a block for further configurations

Direct Known Subclasses

InputField, OutputField

Defined Under Namespace

Modules: AuthorizedField, ProxiedField, ResolvedField, TypedField Classes: InputField, MutationField, OutputField, ScopedConfig, SubscriptionField

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::WithDescription

#desc, #description=, #description?

Methods included from Helpers::WithDirectives

#all_directive_events, #all_directive_listeners, #directive_events?, #directive_listeners?, extended, included, #use, #using?

Constructor Details

#initialize(name, owner:, **xargs, &block) ⇒ Field

Returns a new instance of Field.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rails/graphql/field.rb', line 104

def initialize(name, owner:, **xargs, &block)
  @owner = owner
  normalize_name(name)

  # TODO: Replace by a proper method to build and set @directives
  directives = GraphQL.directives_to_set(xargs[:directives], source: self)
  @directives = directives unless directives.nil?

  @method_name = xargs[:method_name].to_s.underscore.to_sym \
    unless xargs[:method_name].nil?

  full      = xargs.fetch(:full, false)
  @null     = full ? false : xargs.fetch(:null, true)
  @array    = full ? true  : xargs.fetch(:array, false)
  @nullable = full ? false : xargs.fetch(:nullable, true)

  self.description = xargs[:desc] || xargs[:description]
  @enabled = xargs.fetch(:enabled, !xargs.fetch(:disabled, false))

  configure(&block) if block.present?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name) ⇒ Object (protected)

Allow the subclasses to define the extra inspection methods



304
305
306
# File 'lib/rails/graphql/field.rb', line 304

def method_missing(method_name, *)
  method_name.start_with?('inspect_') ? '' : super
end

Instance Attribute Details

#gql_nameObject (readonly)

Returns the value of attribute gql_name.



50
51
52
# File 'lib/rails/graphql/field.rb', line 50

def gql_name
  @gql_name
end

#nameObject (readonly) Also known as: to_sym

Returns the value of attribute name.



50
51
52
# File 'lib/rails/graphql/field.rb', line 50

def name
  @name
end

#ownerObject (readonly) Also known as: gid_base_class, proxied_owner

Returns the value of attribute owner.



50
51
52
# File 'lib/rails/graphql/field.rb', line 50

def owner
  @owner
end

Class Method Details

.input_type?Boolean

Defines if the current field is valid as an input type

Returns:

  • (Boolean)


74
75
76
# File 'lib/rails/graphql/field.rb', line 74

def input_type?
  false
end

.leaf_type?Boolean

Defines if the current field is considered a leaf output

Returns:

  • (Boolean)


84
85
86
# File 'lib/rails/graphql/field.rb', line 84

def leaf_type?
  false
end

.mutation?Boolean

Checks if the field is associated with a mutation

Returns:

  • (Boolean)


94
95
96
# File 'lib/rails/graphql/field.rb', line 94

def mutation?
  false
end

.output_type?Boolean

Defines if the current field is valid as an output type

Returns:

  • (Boolean)


79
80
81
# File 'lib/rails/graphql/field.rb', line 79

def output_type?
  false
end

.proxy?Boolean

Checks if the the field is a proxy kind of field

Returns:

  • (Boolean)


89
90
91
# File 'lib/rails/graphql/field.rb', line 89

def proxy?
  false
end

.proxyable_methods(*list, klass:, allow_nil: false) ⇒ Object

A small shared helper method that allows field information to be proxied



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

def proxyable_methods(*list, klass:, allow_nil: false)
  list = list.flatten.compact.map do |method_name|
    ivar = +'@' + method_name.delete_suffix('?')
    accessor = +'field' + (allow_nil ? '&.' : '.') + method_name
    "def #{method_name}; defined?(#{ivar}) ? #{ivar} : #{accessor}; end"
  end

  klass.class_eval(list.join("\n"), __FILE__, __LINE__ + 1)
end

.subscription?Boolean

Checks if the field is associated with a subscription

Returns:

  • (Boolean)


99
100
101
# File 'lib/rails/graphql/field.rb', line 99

def subscription?
  false
end

Instance Method Details

#=~(other) ⇒ Object

Check if the other field is equivalent



277
278
279
280
281
282
# File 'lib/rails/graphql/field.rb', line 277

def =~(other)
  other.is_a?(GraphQL::Field) &&
    other.array? == array? &&
    (other.null? == null? || other.null? && !null?) &&
    (other.nullable? == nullable? || other.nullable? && !nullable?)
end

#all_ownersObject

Return the owner as the single item of the list



151
152
153
# File 'lib/rails/graphql/field.rb', line 151

def all_owners
  [owner]
end

#apply_changes(**xargs, &block) ⇒ Object

Apply a controlled set of changes to the field



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

def apply_changes(**xargs, &block)
  required_items! unless xargs.fetch(:nullable, true)
  required! unless xargs.fetch(:null, true)
  disable! if xargs.fetch(:disabled, false)
  enable! if xargs.fetch(:enabled, false)

  self.description = xargs[:desc] if xargs.key?(:desc)
  self.description = xargs[:description] if xargs.key?(:description)
  configure(&block) if block.present?
end

#array?Boolean

Checks if the field can be an array

Returns:

  • (Boolean)


197
198
199
# File 'lib/rails/graphql/field.rb', line 197

def array?
  !!@array
end

#as_jsonObject

Turn the given value into a JSON string representation

Raises:

  • (NotImplementedError)


242
243
244
# File 'lib/rails/graphql/field.rb', line 242

def as_json(*)
  raise NotImplementedError, +"#{self.class.name} does not implement as_json"
end

#configure(&block) ⇒ Object

Allow extra configurations to be performed using a block



145
146
147
148
# File 'lib/rails/graphql/field.rb', line 145

def configure(&block)
  Field::ScopedConfig.new(self, block.binding.receiver).instance_exec(&block)
  self
end

#description(namespace = nil) ⇒ Object

Override to add the kind



217
218
219
# File 'lib/rails/graphql/field.rb', line 217

def description(namespace = nil, *)
  super(namespace, :field)
end

#deserializeObject

Turn a user input of this given type into an ruby object

Raises:

  • (NotImplementedError)


247
248
249
# File 'lib/rails/graphql/field.rb', line 247

def deserialize(*)
  raise NotImplementedError, +"#{self.class.name} does not implement deserialize"
end

#disable!Object

Mark the field as globally disabled



172
173
174
# File 'lib/rails/graphql/field.rb', line 172

def disable!
  @enabled = false
end

#disabled?Boolean

Check if tre field is disabled

Returns:

  • (Boolean)


212
213
214
# File 'lib/rails/graphql/field.rb', line 212

def disabled?
  !enabled?
end

#enable!Object

Mark the field as globally enabled



167
168
169
# File 'lib/rails/graphql/field.rb', line 167

def enable!
  @enabled = true
end

#enabled?Boolean

Check if tre field is enabled

Returns:

  • (Boolean)


207
208
209
# File 'lib/rails/graphql/field.rb', line 207

def enabled?
  !!@enabled
end

#initialize_copyObject



126
127
128
129
130
# File 'lib/rails/graphql/field.rb', line 126

def initialize_copy(*)
  super

  @owner = nil
end

#inspectObject



284
285
286
287
288
289
290
291
292
293
294
# File 'lib/rails/graphql/field.rb', line 284

def inspect
  (+"    #<GraphQL::\#{self.class.name.split('::').last}\n    \#{inspect_owner&.split(+'GraphQL::')&.last&.sub(+'::NestedTypes', '')}\n    \#{inspect_source}\n    \#{inspect_enabled}\n    \#{gql_name}\#{inspect_arguments}\#{inspect_type}\n    \#{inspect_default_value}\n    \#{inspect_directives}\n  INFO\nend\n").squish << '>'

#internal?Boolean

Check if the field is an internal one

Returns:

  • (Boolean)


222
223
224
# File 'lib/rails/graphql/field.rb', line 222

def internal?
  name.start_with?('__')
end

#method_nameObject

Returns the name of the method used to retrieve the information



156
157
158
159
160
161
162
163
164
# File 'lib/rails/graphql/field.rb', line 156

def method_name
  if defined?(@method_name)
    @method_name
  elsif from_alternative?
    :resolve
  else
    @name
  end
end

#null?Boolean

Checks if the field can be null

Returns:

  • (Boolean)


187
188
189
# File 'lib/rails/graphql/field.rb', line 187

def null?
  !!@null
end

#nullable?Boolean

Checks if the field can have null elements in the array

Returns:

  • (Boolean)


202
203
204
# File 'lib/rails/graphql/field.rb', line 202

def nullable?
  !!@nullable
end

#required!Object

Update the null value



177
178
179
# File 'lib/rails/graphql/field.rb', line 177

def required!
  @null = false
end

#required?Boolean

Checks if the field cannot br null

Returns:

  • (Boolean)


192
193
194
# File 'lib/rails/graphql/field.rb', line 192

def required?
  !null?
end

#required_items!Object

Update the nullable value



182
183
184
# File 'lib/rails/graphql/field.rb', line 182

def required_items!
  @nullable = false
end

#to_jsonObject

Transforms the given value to its representation in a JSON string

Raises:

  • (NotImplementedError)


237
238
239
# File 'lib/rails/graphql/field.rb', line 237

def to_json(*)
  raise NotImplementedError, +"#{self.class.name} does not implement to_json"
end

#to_proxy(*args, **xargs, &block) ⇒ Object

Create a proxy of the current field



268
269
270
271
272
273
274
# File 'lib/rails/graphql/field.rb', line 268

def to_proxy(*args, **xargs, &block)
  proxy = self.class.allocate
  proxy.extend Field::ProxiedField
  proxy.send(:proxied)
  proxy.send(:initialize, self, *args, **xargs, &block)
  proxy
end

#valid?(value) ⇒ Boolean

Check if the given value is valid using valid_input? or valid_output? depending of the type of the field

Returns:

  • (Boolean)


253
254
255
# File 'lib/rails/graphql/field.rb', line 253

def valid?(value)
  input_type? ? valid_input?(value) : valid_output?(value)
end

#valid_input?Boolean

This method must be overridden by children classes

Returns:

  • (Boolean)


227
228
229
# File 'lib/rails/graphql/field.rb', line 227

def valid_input?(*)
  enabled?
end

#valid_output?Boolean

This method must be overridden by children classes

Returns:

  • (Boolean)


232
233
234
# File 'lib/rails/graphql/field.rb', line 232

def valid_output?(*)
  enabled?
end

#validate!Object

Checks if the definition of the field is valid.

Raises:



258
259
260
261
262
263
264
265
# File 'lib/rails/graphql/field.rb', line 258

def validate!(*)
  super if defined? super

  raise NameError, (+"    The name \"\#{gql_name}\" is invalid. Only internal fields from the\n    spec can have a name starting with \"__\".\n  MSG\nend\n").squish if gql_name.start_with?('__') && !internal?