11
11
12
12
module GraphQL
13
13
# A GraphQL schema which may be queried with {GraphQL::Query}.
14
+ #
15
+ # The {Schema} contains:
16
+ #
17
+ # - types for exposing your application
18
+ # - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
19
+ # - execution strategies for running incoming queries
20
+ # - middleware for interacting with execution
21
+ #
22
+ # Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
23
+ # The schema will traverse the tree of fields & types, using those as starting points.
24
+ # Any undiscoverable types may be provided with the `types` configuration.
25
+ #
26
+ # Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
27
+ # (These configurations can be overridden by specific calls to {Schema#execute})
28
+ #
29
+ # Schemas can specify how queries should be executed against them.
30
+ # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
31
+ # each apply to corresponding root types.
32
+ #
33
+ # A schema accepts a `Relay::GlobalNodeIdentification` instance for use with Relay IDs.
34
+ #
35
+ # @example defining a schema
36
+ # MySchema = GraphQL::Schema.define do
37
+ # query QueryType
38
+ # middleware PermissionMiddleware
39
+ # rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
40
+ # # If types are only connected by way of interfaces, they must be added here
41
+ # orphan_types ImageType, AudioType
42
+ # end
43
+ #
14
44
class Schema
15
- extend Forwardable
45
+ include GraphQL ::Define ::InstanceDefinable
46
+ accepts_definitions \
47
+ :query , :mutation , :subscription ,
48
+ :query_execution_strategy , :mutation_execution_strategy , :subscription_execution_strategy ,
49
+ :max_depth , :max_complexity ,
50
+ :node_identification ,
51
+ :orphan_types ,
52
+ query_analyzer : -> ( schema , analyzer ) { schema . query_analyzers << analyzer } ,
53
+ middleware : -> ( schema , middleware ) { schema . middleware << middleware } ,
54
+ rescue_from : -> ( schema , err_class , &block ) { schema . rescue_from ( err_class , &block ) }
55
+
56
+ lazy_defined_attr_accessor \
57
+ :query , :mutation , :subscription ,
58
+ :query_execution_strategy , :mutation_execution_strategy , :subscription_execution_strategy ,
59
+ :max_depth , :max_complexity ,
60
+ :node_identification ,
61
+ :orphan_types ,
62
+ :query_analyzers , :middleware
63
+
16
64
17
65
DIRECTIVES = [ GraphQL ::Directive ::SkipDirective , GraphQL ::Directive ::IncludeDirective ]
18
66
DYNAMIC_FIELDS = [ "__type" , "__typename" , "__schema" ]
19
67
20
- attr_reader :query , :mutation , :subscription , :directives , :static_validator , :query_analyzers
21
- attr_accessor :max_depth
22
- attr_accessor :max_complexity
23
-
24
- # Override these if you don't want the default executor:
25
- attr_accessor :query_execution_strategy ,
26
- :mutation_execution_strategy ,
27
- :subscription_execution_strategy
68
+ attr_reader :directives , :static_validator
28
69
29
70
# @return [GraphQL::Relay::GlobalNodeIdentification] the node identification instance for this schema, when using Relay
30
- attr_accessor :node_identification
71
+ def node_identification
72
+ ensure_defined
73
+ @node_identification
74
+ end
31
75
32
76
# @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
33
- attr_reader :middleware
77
+ def middleware
78
+ ensure_defined
79
+ @middleware
80
+ end
34
81
35
82
# @param query [GraphQL::ObjectType] the query root for the schema
36
83
# @param mutation [GraphQL::ObjectType] the mutation root for the schema
37
84
# @param subscription [GraphQL::ObjectType] the subscription root for the schema
38
85
# @param max_depth [Integer] maximum query nesting (if it's greater, raise an error)
39
86
# @param types [Array<GraphQL::BaseType>] additional types to include in this schema
40
- def initialize ( query :, mutation : nil , subscription : nil , max_depth : nil , max_complexity : nil , types : [ ] )
87
+ def initialize ( query : nil , mutation : nil , subscription : nil , max_depth : nil , max_complexity : nil , types : [ ] )
88
+ if query
89
+ warn ( "Schema.new is deprecated, use Schema.define instead" )
90
+ end
41
91
@query = query
42
92
@mutation = mutation
43
93
@subscription = subscription
@@ -50,17 +100,26 @@ def initialize(query:, mutation: nil, subscription: nil, max_depth: nil, max_com
50
100
@middleware = [ @rescue_middleware ]
51
101
@query_analyzers = [ ]
52
102
# Default to the built-in execution strategy:
53
- self . query_execution_strategy = GraphQL ::Query ::SerialExecution
54
- self . mutation_execution_strategy = GraphQL ::Query ::SerialExecution
55
- self . subscription_execution_strategy = GraphQL ::Query ::SerialExecution
103
+ @query_execution_strategy = GraphQL ::Query ::SerialExecution
104
+ @mutation_execution_strategy = GraphQL ::Query ::SerialExecution
105
+ @subscription_execution_strategy = GraphQL ::Query ::SerialExecution
106
+ end
107
+
108
+ def rescue_from ( *args , &block )
109
+ ensure_defined
110
+ @rescue_middleware . rescue_from ( *args , &block )
56
111
end
57
112
58
- def_delegators :@rescue_middleware , :rescue_from , :remove_handler
113
+ def remove_handler ( *args , &block )
114
+ ensure_defined
115
+ @rescue_middleware . remove_handler ( *args , &block )
116
+ end
59
117
60
118
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
61
119
def types
62
120
@types ||= begin
63
- all_types = @orphan_types + [ query , mutation , subscription , GraphQL ::Introspection ::SchemaType ]
121
+ ensure_defined
122
+ all_types = orphan_types + [ query , mutation , subscription , GraphQL ::Introspection ::SchemaType ]
64
123
GraphQL ::Schema ::ReduceTypes . reduce ( all_types . compact )
65
124
end
66
125
end
@@ -69,13 +128,14 @@ def types
69
128
# See {Query#initialize} for arguments.
70
129
# @return [Hash] query result, ready to be serialized as JSON
71
130
def execute ( *args )
72
- query = GraphQL ::Query . new ( self , *args )
73
- query . result
131
+ query_obj = GraphQL ::Query . new ( self , *args )
132
+ query_obj . result
74
133
end
75
134
76
135
# Resolve field named `field_name` for type `parent_type`.
77
136
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
78
137
def get_field ( parent_type , field_name )
138
+ ensure_defined
79
139
defined_field = parent_type . get_field ( field_name )
80
140
if defined_field
81
141
defined_field
@@ -91,12 +151,14 @@ def get_field(parent_type, field_name)
91
151
end
92
152
93
153
def type_from_ast ( ast_node )
154
+ ensure_defined
94
155
GraphQL ::Schema ::TypeExpression . build_type ( self , ast_node )
95
156
end
96
157
97
158
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
98
159
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
99
160
def possible_types ( type_defn )
161
+ ensure_defined
100
162
@interface_possible_types ||= GraphQL ::Schema ::PossibleTypes . new ( self )
101
163
@interface_possible_types . possible_types ( type_defn )
102
164
end
0 commit comments