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::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::HasAstNode

#ast_node

Methods included from Member::HasPath

#path

Methods included from Member::RelayShortcuts

#connection_type, #connection_type_class, #edge_type, #edge_type_class

Methods included from Member::Scoped

#scope_items

Methods included from Member::TypeSystemHelpers

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

Methods included from Member::BaseDSLMethods::ConfigurationExtension

#inherited

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 Relay::TypeExtensions

#connection_type, #define_connection, #define_edge, #edge_type

Methods included from Member::CachedGraphQLDefinition

#graphql_definition, #initialize_copy, #type_class

Constructor Details

#initialize(object, context) ⇒ Object

Returns a new instance of Object.


68
69
70
71
# File 'lib/graphql/schema/object.rb', line 68

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:


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/graphql/schema/object.rb', line 39

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.


152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/graphql/schema/object.rb', line 152

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


81
82
83
84
85
86
87
88
89
90
91
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
# File 'lib/graphql/schema/object.rb', line 81

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.


76
77
78
79
# File 'lib/graphql/schema/object.rb', line 76

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

.interface_type_membershipsObject


126
127
128
# File 'lib/graphql/schema/object.rb', line 126

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.


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/graphql/schema/object.rb', line 131

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


186
187
188
# File 'lib/graphql/schema/object.rb', line 186

def kind
  GraphQL::TypeKinds::OBJECT
end

.own_interface_type_membershipsObject


122
123
124
# File 'lib/graphql/schema/object.rb', line 122

def own_interface_type_memberships
  @own_interface_type_memberships ||= []
end

.to_graphqlGraphQL::ObjectType

Returns:


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/graphql/schema/object.rb', line 168

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