Class: Rails::GraphQL::Schema

Inherits:
Object
  • Object
show all
Extended by:
Helpers::Registerable, Helpers::WithDirectives, Helpers::WithGlobalID, Helpers::WithSchemaFields, Introspection
Includes:
ActiveSupport::Configurable, ActiveSupport::Rescuable, Helpers::Instantiable
Defined in:
lib/rails/graphql/schema.rb

Overview

GraphQL Schema

This is a pure representation of a GraphQL schema. See: spec.graphql.org/June2018/#SchemaDefinition

In addition to the spec implementation, this also allows separation by namespaces, where each schema is associated with one and only one namespace, guiding requests and types searching.

This class works similarly to the TypeMap class, where its purpose is to know which QueryFields, Mutations, and Subscriptions are available. The main difference is that it doesn’t hold namespace-based objects, since each schema is associated to a single namespace.

Constant Summary

Constants included from Helpers::WithSchemaFields

Helpers::WithSchemaFields::TYPE_FIELD_CLASS

Class Attribute Summary collapse

Attributes included from Helpers::Instantiable

#event

Class Method Summary collapse

Methods included from Helpers::WithSchemaFields

[], add_field, add_proxy_field, change_field, configure_field, configure_fields, disable_fields, enable_fields, enabled_fields_from, extended, field_names_for, fields_for, fields_for?, find_by_gid, find_field, find_field!, has_field?, import_all, import_all_into, import_into, safe_add_field, type_name_for, validate!

Methods included from Helpers::WithDirectives

all_directive_events, all_directive_listeners, directive_events?, directive_listeners?, extended, included, initialize_copy, use, using?, validate!

Methods included from Helpers::WithGlobalID

to_gid_param, to_global_id

Methods included from Helpers::Registerable

aliases, extended, inherited, register!, registered?

Methods included from Introspection

introspection?, register!

Class Attribute Details

.subscription_providerObject

Return the subscription provider for the current schema



224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/rails/graphql/schema.rb', line 224

def subscription_provider
  if !defined?(@subscription_provider)
    @subscription_provider = config.subscription_provider || config.default_subscription_provider
    subscription_provider
  elsif @subscription_provider.is_a?(String)
    provider = (name = @subscription_provider).safe_constantize
    return @subscription_provider = provider.new(logger: logger) unless provider.nil?

    raise ::NameError, +"uninitialized constant #{name}"
  else
    @subscription_provider
  end
end

Class Method Details

.accepts_subscription?(operation) ⇒ Boolean

Checks if the given operation can be subscribed to

Returns:

  • (Boolean)


257
258
259
# File 'lib/rails/graphql/schema.rb', line 257

def accepts_subscription?(operation)
  subscription_provider.accepts?(operation)
end

.add_subscriptions(*subscriptions) ⇒ Object

Add a new subscription using all the provided request subscription objects



245
246
247
# File 'lib/rails/graphql/schema.rb', line 245

def add_subscriptions(*subscriptions)
  subscription_provider.add(*subscriptions)
end

.cached?(name, options = nil) ⇒ Boolean

Simple delegator to the cache store set on the schema config, mapped to exist?

Returns:

  • (Boolean)


269
270
271
# File 'lib/rails/graphql/schema.rb', line 269

def cached?(name, options = nil)
  config.cache.exist?(expand_cache_key(name), options)
end

.delete_from_cache(name, options = nil) ⇒ Object

Simple delegator to the cache store set on the schema config, mapped to delete



275
276
277
# File 'lib/rails/graphql/schema.rb', line 275

def delete_from_cache(name, options = nil)
  config.cache.delete(expand_cache_key(name), options)
end

.execute(*args, **xargs) ⇒ Object Also known as: perform

See Request



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

def execute(*args, **xargs)
  return if self == ::Rails::GraphQL::Schema
  Rails::GraphQL::Request.execute(*args, **xargs, schema: self)
end

.fetch_from_cache(name, options = nil) ⇒ Object

Simple delegator to the cache store set on the schema config, mapped to fetch



293
294
295
# File 'lib/rails/graphql/schema.rb', line 293

def fetch_from_cache(name, options = nil)
  config.cache.fetch(expand_cache_key(name), options)
end

.find(namespace) ⇒ Object

:singleton-method: Use a soft mode to find a schema associated with a namespace



76
77
78
79
80
81
82
# File 'lib/rails/graphql/schema.rb', line 76

def find(namespace)
  type_map.fetch(:schema,
    namespaces: namespace,
    base_class: :Schema,
    exclusive: true,
  )
end

.find!(namespace) ⇒ Object

:singleton-method: Find the schema associated to the given namespace



86
87
88
89
90
91
92
# File 'lib/rails/graphql/schema.rb', line 86

def find!(namespace)
  type_map.fetch!(:schema,
    namespaces: namespace,
    base_class: :Schema,
    exclusive: true,
  )
end

.find_by_gid(gid) ⇒ Object

:singleton-method: Return the schema



102
103
104
105
106
107
# File 'lib/rails/graphql/schema.rb', line 102

def find_by_gid(gid)
  result = find!(gid.namespace.to_sym)
  return result if gid.name.nil?

  result.find_field!(gid.scope, gid.name)
end

.find_directive!(directive, **xargs) ⇒ Object

Find a given directive associated with the schema. It will raise an exception if the directive can not be found



203
204
205
206
207
# File 'lib/rails/graphql/schema.rb', line 203

def find_directive!(directive, **xargs)
  xargs[:base_class] = :Directive
  xargs[:namespaces] = namespaces
  type_map.fetch!(directive, **xargs)
end

.find_type(type, **xargs) ⇒ Object

Find a given type associated with the schema



187
188
189
190
191
# File 'lib/rails/graphql/schema.rb', line 187

def find_type(type, **xargs)
  xargs[:base_class] = :Type
  xargs[:namespaces] = namespaces
  type_map.fetch(type, **xargs)
end

.find_type!(type, **xargs) ⇒ Object

Find a given type associated with the schema. It will raise an exception if the type can not be found



195
196
197
198
199
# File 'lib/rails/graphql/schema.rb', line 195

def find_type!(type, **xargs)
  xargs[:base_class] = :Type
  xargs[:namespaces] = namespaces
  type_map.fetch!(type, **xargs)
end

.gid_base_classObject

:singleton-method: The base class of all schemas is always Schema



96
97
98
# File 'lib/rails/graphql/schema.rb', line 96

def gid_base_class
  Schema
end

.gql_nameObject Also known as: graphql_name

:singleton-method: Since there are only one schema per namespace, the name is constant



59
60
61
# File 'lib/rails/graphql/schema.rb', line 59

def gql_name
  '__Schema'
end

.kindObject Also known as: to_sym

:singleton-method: Since there is only one schema per namespace, then both kind and to_sym, which is used to register, are the same



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

def kind
  :schema
end

.namespace(*args) ⇒ Object

Schemas are assigned to a single namespace and not inherited



124
125
126
127
128
129
130
131
132
# File 'lib/rails/graphql/schema.rb', line 124

def namespace(*args)
  if args.present?
    set_namespace(*args)
  elsif defined?(@namespace) && !@namespace.nil?
    @namespace
  else
    :base
  end
end

.namespacesObject

Add compatibility to the list of namespaces



135
136
137
# File 'lib/rails/graphql/schema.rb', line 135

def namespaces
  namespace
end

.read_from_cache(name, options = nil) ⇒ Object

Simple delegator to the cache store set on the schema config, mapped to read



281
282
283
# File 'lib/rails/graphql/schema.rb', line 281

def read_from_cache(name, options = nil)
  config.cache.read(expand_cache_key(name), options)
end

.register!Object

The process to register a class and it’s name on the index

Raises:



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

def register!
  return if self == GraphQL::Schema
  return super unless registered?

  current = type_map.fetch(:schema,
    namespaces: namespace,
    base_class: :Schema,
    exclusive: true,
  )

  raise ArgumentError, (+"    The \#{namespace.inspect} namespace is already assigned to \"\#{current.name}\".\n    Please change the namespace for \"\#{klass.name}\" class.\n  MSG\nend\n").squish

.registered?Boolean

Check if the class is already registered in the type map

Returns:

  • (Boolean)


159
160
161
# File 'lib/rails/graphql/schema.rb', line 159

def registered?
  type_map.object_exist?(self, exclusive: true)
end

.remove_subscriptions(*sids) ⇒ Object

Remove subscriptions by their provided sids



239
240
241
# File 'lib/rails/graphql/schema.rb', line 239

def remove_subscriptions(*sids)
  subscription_provider&.remove(*sids)
end

.requestObject

See Request



210
211
212
213
# File 'lib/rails/graphql/schema.rb', line 210

def request
  return if self == ::Rails::GraphQL::Schema
  Rails::GraphQL::Request.new(self)
end

.restart_subscriptionsObject

The the schema is unloaded, we need to make sure that the provider can smoothly shutdown itself



251
252
253
254
# File 'lib/rails/graphql/schema.rb', line 251

def restart_subscriptions
  return unless defined?(@subscription_provider) && !@subscription_provider.nil?
  subscription_provider.shutdown
end

.set_namespace(ns, mod = nil) ⇒ Object Also known as: set_namespaces

Schemas are assigned to a single namespace. You can provide a module as the second argument to associate that module to the same namespace



116
117
118
119
# File 'lib/rails/graphql/schema.rb', line 116

def set_namespace(ns, mod = nil)
  @namespace = normalize_namespaces([ns]).first
  type_map.associate(@namespace, mod) if mod.is_a?(Module)
end

.subscription_id_forObject

This receives a request subscription object and return an id for that. By default, it just produces a random uuid



263
264
265
# File 'lib/rails/graphql/schema.rb', line 263

def subscription_id_for(*)
  SecureRandom.uuid
end

.to_gql(**xargs) ⇒ Object

Describe a schema as a GraphQL string



298
299
300
# File 'lib/rails/graphql/schema.rb', line 298

def to_gql(**xargs)
  ToGQL.describe(self, **xargs)
end

.types(base_class: :Type, &block) ⇒ Object

Find all types that are available for the current schema



110
111
112
# File 'lib/rails/graphql/schema.rb', line 110

def types(base_class: :Type, &block)
  type_map.each_from(namespace, base_class: base_class, &block)
end

.unregister!Object

Hook into the unregister process to reset the subscription provider



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

def unregister!
  restart_subscriptions
  super
end

.valid?Boolean

Check if the schema is valid

Returns:

  • (Boolean)


140
141
142
# File 'lib/rails/graphql/schema.rb', line 140

def valid?
  defined?(@validated) && @validated
end

.validateObject

Only run the validated process if it has not yet been validated



145
146
147
148
149
150
# File 'lib/rails/graphql/schema.rb', line 145

def validate
  validate! unless valid?
rescue StandardError
  GraphQL.logger.warn(+"\e[1m\e[31mSchema #{name} is invalid!\e[0m")
  raise
end

.validate!Object

Run validations and then mark itself as validated



153
154
155
156
# File 'lib/rails/graphql/schema.rb', line 153

def validate!(*)
  super if defined? super
  @validated = true
end

.write_on_cache(name, value, options = nil) ⇒ Object

Simple delegator to the cache store set on the schema config, mapped to write



287
288
289
# File 'lib/rails/graphql/schema.rb', line 287

def write_on_cache(name, value, options = nil)
  config.cache.write(expand_cache_key(name), value, options)
end