Class: GraphQL::Field

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/field.rb

Overview

Fields are used to safely lookup values on Nodes. When you define a custom field, you can access it from Node.field

‘graphql` has built-in fields for some Ruby data types:

You can define custom fields that allow you to control how values are exposed.

  • Field.type defines how it can be used inside Node.field calls.

  • Field.call defines calls that can mutate the value before it is added to the response.

Examples:

# For example, an `AddressField` which wraps a string but exposes address-specific information
class AddressField < GraphQL::Field
  type :address
  # ^^ now you can use it with `field.address` in node definitions

  # calls can modify the value:
  # eg, get the numbers at the beginning:
  call :house_number, -> (prev_value) { prev_value[/^\d*/]}
  # get everything after a space:
  call :street_name,  -> (prev_value) { prev_value[/\s.*$/].strip }
end

# Then, use it in a node definition:
class HouseNode < GraphQL::Node
  exposes("House")
  # create an `AddressField` for this node called `street_address`:
  field.address(:street_address)
end

# Then, use the field in queries:
<<QUERY
find_house(1) {
  street_address,
  street_address.house_number() as number,
  street_address.street_name() as street,
}
QUERY

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(query: nil, owner: nil, calls: [], fields: []) ⇒ Field

Returns a new instance of Field.



42
43
44
45
46
47
# File 'lib/graphql/field.rb', line 42

def initialize(query: nil, owner: nil, calls: [], fields: [])
  @query = query
  @owner = owner
  @calls = calls
  @fields = fields
end

Instance Attribute Details

#callsObject (readonly)

Returns the value of attribute calls.



41
42
43
# File 'lib/graphql/field.rb', line 41

def calls
  @calls
end

#fieldsObject (readonly)

Returns the value of attribute fields.



41
42
43
# File 'lib/graphql/field.rb', line 41

def fields
  @fields
end

#ownerObject (readonly)

Returns the value of attribute owner.



41
42
43
# File 'lib/graphql/field.rb', line 41

def owner
  @owner
end

#queryObject (readonly)

Returns the value of attribute query.



41
42
43
# File 'lib/graphql/field.rb', line 41

def query
  @query
end

Class Method Details

.call(name, lambda) ⇒ Object

Define a call that can be made on this field. The ‘lambda` receives arguments:

  • 1: ‘previous_value` – the value of this field

  • *: arguments passed in the query (as strings)

Examples:

# upcase a string field:
call :upcase, -> (prev_value) { prev_value.upcase }
# tests a number field:
call :greater_than, -> (prev_value, test_value) { prev_value > test_value.to_f }
# (`test_value` is passed in as a string)

Parameters:

  • name (String)

    the identifier for this call

  • operation (lambda)

    the transformation this call makes



169
170
171
# File 'lib/graphql/field.rb', line 169

def call(name, lambda)
  _calls[name.to_s] = GraphQL::Call.new(name: name.to_s, lambda: lambda)
end

.callsObject



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

def calls
  superclass.calls.merge(_calls)
rescue NoMethodError
  {}
end

.create_class(name:, owner_class:, type:, description: nil, connection_class_name: nil, node_class_name: nil) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/graphql/field.rb', line 90

def create_class(name:, owner_class:, type:, description: nil, connection_class_name: nil, node_class_name: nil)
  if type.is_a?(Symbol)
    type = GraphQL::SCHEMA.get_field(type)
  end

  field_superclass = type || self
  new_class = Class.new(field_superclass)
  new_class.const_set :NAME, name
  new_class.const_set :OWNER_CLASS, owner_class
  new_class.const_set :DESCRIPTION , description
  new_class.const_set :CONNECTION_CLASS_NAME, connection_class_name
  new_class.const_set :NODE_CLASS_NAME, node_class_name
  new_class
end

.default_schema_nameObject



137
138
139
# File 'lib/graphql/field.rb', line 137

def default_schema_name
  name.split("::").last.sub(/Field$/, '').underscore
end

.descriptionObject



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

def description
  const_get(:DESCRIPTION)
end

.field_nameObject



141
142
143
# File 'lib/graphql/field.rb', line 141

def field_name
  const_get(:NAME)
end

.inherited(child_class) ⇒ Object



86
87
88
# File 'lib/graphql/field.rb', line 86

def inherited(child_class)
  GraphQL::SCHEMA.add_field(child_class)
end

.schema_nameObject



133
134
135
# File 'lib/graphql/field.rb', line 133

def schema_name
  @value_type || (name.present? ? default_schema_name : nil)
end

.to_sObject



105
106
107
108
109
110
111
# File 'lib/graphql/field.rb', line 105

def to_s
  if const_defined?(:NAME)
    "<FieldClass: #{const_get(:OWNER_CLASS).name}::#{const_get(:NAME)}>"
  else
    super
  end
end

.type(value_type_name) ⇒ Object

Defines the name used for getting fields of this type from the schema.

Examples:

# define the field with its type:
class IPAddressField < GraphQL::Field
  type :ip_address
end

# then, attach fields of this type to your nodes:
class ServerNode < GraphQL::Field
  field.ip_address(:static_ip_address)
end

Parameters:

  • type_name (Symbol)

    the name used for getting this field from the SCHEMA.



124
125
126
127
# File 'lib/graphql/field.rb', line 124

def type(value_type_name)
  @value_type = value_type_name.to_s
  GraphQL::SCHEMA.add_field(self)
end

.value_typeObject



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

def value_type
  @value_type || superclass.value_type
end

Instance Method Details

#as_resultObject



53
54
55
# File 'lib/graphql/field.rb', line 53

def as_result
  finished_value
end

#const_get(const_name) ⇒ Object

instance ‘const_get` reaches up to class namespace



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

def const_get(const_name)
  self.class.const_get(const_name)
rescue
  nil
end

#finished_valueObject



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/graphql/field.rb', line 57

def finished_value
  @finished_value ||= begin
    val = raw_value
    calls.each do |call|
      registered_call = self.class.calls[call.identifier]
      if registered_call.nil?
        raise "Call not found: #{self.class.name}##{call.identifier}"
      end
      val = registered_call.lambda.call(val, *call.arguments)
    end
    val
  end
end

#raw_valueObject



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

def raw_value
  owner.send(name)
end