Class: GraphQL::Schema::Object

Inherits:
Member
  • Object
show all
Extended by:
Member::AcceptsDefinition, Member::HasFields
Defined in:
lib/graphql/schema/object.rb

Constant Summary

Constants included from Member::HasFields

Member::HasFields::CONFLICT_FIELD_NAMES, Member::HasFields::GRAPHQL_RUBY_KEYWORDS, Member::HasFields::RUBY_KEYWORDS

Constants included from Member::HasDirectives

Member::HasDirectives::NO_DIRECTIVES

Constants included from Member::GraphQLTypeNames

Member::GraphQLTypeNames::Boolean, Member::GraphQLTypeNames::ID, Member::GraphQLTypeNames::Int

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Member::HasFields

add_field, field, field_class, fields, get_field, global_id_field, own_fields

Methods included from Member::CachedGraphQLDefinition

#graphql_definition, #initialize_copy, #type_class

Methods included from Relay::TypeExtensions

#connection_type, #define_connection, #define_edge, #edge_type

Methods included from Member::BaseDSLMethods

#accessible?, #authorized?, #default_graphql_name, #description, #graphql_name, #introspection, #introspection?, #mutation, #name, #overridden_graphql_name, #to_graphql, #visible?

Methods included from Member::BaseDSLMethods::ConfigurationExtension

#inherited

Methods included from Member::TypeSystemHelpers

#kind, #list?, #non_null?, #to_list_type, #to_non_null_type, #to_type_signature

Methods included from Member::Scoped

#scope_items

Methods included from Member::RelayShortcuts

#connection_type, #connection_type_class, #edge_type, #edge_type_class

Methods included from Member::HasPath

#path

Methods included from Member::HasAstNode

#ast_node

Methods included from Member::HasDirectives

#directive, #directives, #remove_directive

Constructor Details

#initialize(object, context) ⇒ Object

Returns a new instance of Object.



79
80
81
82
# File 'lib/graphql/schema/object.rb', line 79

def initialize(object, context)
  @object = object
  @context = context
end

Instance Attribute Details

#contextGraphQL::Query::Context (readonly)

Returns the context instance for this query.

Returns:



15
16
17
# File 'lib/graphql/schema/object.rb', line 15

def context
  @context
end

#objectObject (readonly)

Returns the application object this type is wrapping.

Returns:

  • (Object)

    the application object this type is wrapping



12
13
14
# File 'lib/graphql/schema/object.rb', line 12

def object
  @object
end

Class Method Details

.authorized_new(object, context) ⇒ GraphQL::Schema::Object, GraphQL::Execution::Lazy

Make a new instance of this type if the auth check passes, otherwise, raise an error.

Probably only the framework should call this method.

This might return a Execution::Lazy if the user-provided .authorized? hook returns some lazy value (like a Promise).

The reason that the auth check is in this wrapper method instead of new is because of how it might return a Promise. It would be weird if .new returned a promise; It would be a headache to try to maintain Promise-y state inside a GraphQL::Schema::Object instance. So, hopefully this wrapper method will do the job.

Parameters:

Returns:

Raises:



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/graphql/schema/object.rb', line 50

def authorized_new(object, context)
  auth_val = context.query.with_error_handling do
    begin
      authorized?(object, context)
    rescue GraphQL::UnauthorizedError => err
      context.schema.unauthorized_object(err)
    end
  end

  context.schema.after_lazy(auth_val) do |is_authorized|
    if is_authorized
      self.new(object, context)
    else
      # It failed the authorization check, so go to the schema's authorized object hook
      err = GraphQL::UnauthorizedError.new(object: object, type: self, context: context)
      # If a new value was returned, wrap that instead of the original value
      begin
        new_obj = context.schema.unauthorized_object(err)
        if new_obj
          self.new(new_obj, context)
        else
          nil
        end
      end
    end
  end
end

.fieldsHash<String => GraphQL::Schema::Field>

Returns All of this object’s fields, indexed by name.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/graphql/schema/object.rb', line 163

def fields
  all_fields = super
  interfaces.each do |int|
    # Include legacy-style interfaces, too
    if int.is_a?(GraphQL::InterfaceType)
      int_f = {}
      int.fields.each do |name, legacy_field|
        int_f[name] = field_class.from_options(name, field: legacy_field)
      end
      all_fields = int_f.merge(all_fields)
    end
  end
  all_fields
end

.implements(*new_interfaces, **options) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/graphql/schema/object.rb', line 92

def implements(*new_interfaces, **options)
  new_memberships = []
  new_interfaces.each do |int|
    if int.is_a?(Module)
      unless int.include?(GraphQL::Schema::Interface)
        raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
      end

      new_memberships << int.type_membership_class.new(int, self, **options)

      # Include the methods here,
      # `.fields` will use the inheritance chain
      # to find inherited fields
      include(int)
    elsif int.is_a?(GraphQL::InterfaceType)
      new_memberships << int.type_membership_class.new(int, self, **options)
    elsif int.is_a?(String) || int.is_a?(GraphQL::Schema::LateBoundType)
      if options.any?
        raise ArgumentError, "`implements(...)` doesn't support options with late-loaded types yet. Remove #{options} and open an issue to request this feature."
      end
      new_memberships << int
    else
      raise ArgumentError, "Unexpected interface definition (expected module): #{int} (#{int.class})"
    end
  end

  # Remove any interfaces which are being replaced (late-bound types are updated in place this way)
  own_interface_type_memberships.reject! { |old_i_m|
    old_int_type = old_i_m.respond_to?(:abstract_type) ? old_i_m.abstract_type : old_i_m
    old_name = Schema::Member::BuildType.to_type_name(old_int_type)

    new_memberships.any? { |new_i_m|
      new_int_type = new_i_m.respond_to?(:abstract_type) ? new_i_m.abstract_type : new_i_m
      new_name = Schema::Member::BuildType.to_type_name(new_int_type)

      new_name == old_name
    }
  }
  own_interface_type_memberships.concat(new_memberships)
end

.inherited(child_class) ⇒ Object

Set up a type-specific invalid null error to use when this object’s non-null fields wrongly return nil. It should help with debugging and bug tracker integrations.



87
88
89
90
# File 'lib/graphql/schema/object.rb', line 87

def inherited(child_class)
  child_class.const_set(:InvalidNullError, GraphQL::InvalidNullError.subclass_for(child_class))
  super
end

.interface_type_membershipsObject



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

def interface_type_memberships
  own_interface_type_memberships + (superclass.respond_to?(:interface_type_memberships) ? superclass.interface_type_memberships : [])
end

.interfaces(context = GraphQL::Query::NullContext) ⇒ Object

param context [Query::Context] If omitted, skip filtering.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/graphql/schema/object.rb', line 142

def interfaces(context = GraphQL::Query::NullContext)
  visible_interfaces = []
  unfiltered = context == GraphQL::Query::NullContext
  own_interface_type_memberships.each do |type_membership|
    # During initialization, `type_memberships` can hold late-bound types
    case type_membership
    when String, Schema::LateBoundType
      visible_interfaces << type_membership
    when Schema::TypeMembership
      if unfiltered || type_membership.visible?(context)
        visible_interfaces << type_membership.abstract_type
      end
    else
      raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
    end
  end
  visible_interfaces + (superclass <= GraphQL::Schema::Object ? superclass.interfaces(context) : [])
end

.kindObject



197
198
199
# File 'lib/graphql/schema/object.rb', line 197

def kind
  GraphQL::TypeKinds::OBJECT
end

.own_interface_type_membershipsObject



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

def own_interface_type_memberships
  @own_interface_type_memberships ||= []
end

.to_graphqlGraphQL::ObjectType

Returns:



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/graphql/schema/object.rb', line 179

def to_graphql
  obj_type = GraphQL::ObjectType.new
  obj_type.name = graphql_name
  obj_type.description = description
  obj_type.structural_interface_type_memberships = interface_type_memberships
  obj_type.introspection = introspection
  obj_type.mutation = mutation
  obj_type.ast_node = ast_node
  fields.each do |field_name, field_inst|
    field_defn = field_inst.to_graphql
    obj_type.fields[field_defn.name] = field_defn
  end

  obj_type.[:type_class] = self

  obj_type
end

Instance Method Details

#dataloaderGraphQL::Dataloader

Returns:



18
19
20
# File 'lib/graphql/schema/object.rb', line 18

def dataloader
  context.dataloader
end

#raw_value(obj) ⇒ Object

Call this in a field method to return a value that should be returned to the client without any further handling by GraphQL.



24
25
26
# File 'lib/graphql/schema/object.rb', line 24

def raw_value(obj)
  GraphQL::Execution::Interpreter::RawValue.new(obj)
end