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


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)


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

def context
  @context
end

#objectObject (readonly)


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.

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.


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

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


74
75
76
77
78
79
80
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
# File 'lib/graphql/schema/object.rb', line 74

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

.interface_type_membershipsObject


119
120
121
# File 'lib/graphql/schema/object.rb', line 119

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.


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/graphql/schema/object.rb', line 124

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


179
180
181
# File 'lib/graphql/schema/object.rb', line 179

def kind
  GraphQL::TypeKinds::OBJECT
end

.own_interface_type_membershipsObject


115
116
117
# File 'lib/graphql/schema/object.rb', line 115

def own_interface_type_memberships
  @own_interface_type_memberships ||= []
end

.to_graphqlGraphQL::ObjectType


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

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