graphql 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql.rb +10 -0
- data/lib/graphql/base_type.rb +8 -5
- data/lib/graphql/compatibility.rb +3 -0
- data/lib/graphql/compatibility/execution_specification.rb +414 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +117 -0
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +81 -0
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +78 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +239 -0
- data/lib/graphql/define/instance_definable.rb +53 -21
- data/lib/graphql/directive.rb +1 -1
- data/lib/graphql/enum_type.rb +31 -8
- data/lib/graphql/execution/directive_checks.rb +0 -6
- data/lib/graphql/input_object_type.rb +6 -4
- data/lib/graphql/introspection/arguments_field.rb +3 -1
- data/lib/graphql/introspection/enum_values_field.rb +10 -5
- data/lib/graphql/introspection/fields_field.rb +1 -1
- data/lib/graphql/introspection/input_fields_field.rb +2 -2
- data/lib/graphql/introspection/interfaces_field.rb +7 -1
- data/lib/graphql/introspection/possible_types_field.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +1 -1
- data/lib/graphql/introspection/type_by_name_field.rb +4 -2
- data/lib/graphql/introspection/type_type.rb +7 -6
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/parser.rb +1 -1
- data/lib/graphql/language/parser.y +1 -1
- data/lib/graphql/list_type.rb +3 -4
- data/lib/graphql/non_null_type.rb +4 -8
- data/lib/graphql/object_type.rb +5 -3
- data/lib/graphql/query.rb +48 -12
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/serial_execution/execution_context.rb +8 -3
- data/lib/graphql/query/serial_execution/field_resolution.rb +8 -5
- data/lib/graphql/query/serial_execution/operation_resolution.rb +2 -2
- data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -21
- data/lib/graphql/query/serial_execution/value_resolution.rb +59 -99
- data/lib/graphql/query/variables.rb +7 -2
- data/lib/graphql/scalar_type.rb +1 -1
- data/lib/graphql/schema.rb +49 -18
- data/lib/graphql/schema/build_from_definition.rb +248 -0
- data/lib/graphql/schema/instrumented_field_map.rb +23 -0
- data/lib/graphql/schema/loader.rb +4 -11
- data/lib/graphql/schema/possible_types.rb +4 -2
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +4 -4
- data/lib/graphql/schema/type_map.rb +1 -1
- data/lib/graphql/schema/validation.rb +4 -0
- data/lib/graphql/schema/warden.rb +114 -0
- data/lib/graphql/static_validation/literal_validator.rb +10 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -3
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -14
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -4
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +2 -1
- data/lib/graphql/static_validation/validation_context.rb +7 -1
- data/lib/graphql/union_type.rb +6 -3
- data/lib/graphql/unresolved_type_error.rb +1 -2
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -5
- data/spec/graphql/compatibility/execution_specification_spec.rb +3 -0
- data/spec/graphql/compatibility/query_parser_specification_spec.rb +5 -0
- data/spec/graphql/compatibility/schema_parser_specification_spec.rb +5 -0
- data/spec/graphql/define/instance_definable_spec.rb +20 -0
- data/spec/graphql/directive_spec.rb +11 -0
- data/spec/graphql/enum_type_spec.rb +20 -1
- data/spec/graphql/input_object_type_spec.rb +9 -9
- data/spec/graphql/introspection/directive_type_spec.rb +4 -4
- data/spec/graphql/introspection/input_value_type_spec.rb +6 -6
- data/spec/graphql/introspection/type_type_spec.rb +28 -26
- data/spec/graphql/language/parser_spec.rb +27 -17
- data/spec/graphql/list_type_spec.rb +2 -2
- data/spec/graphql/query/variables_spec.rb +1 -0
- data/spec/graphql/scalar_type_spec.rb +3 -3
- data/spec/graphql/schema/build_from_definition_spec.rb +693 -0
- data/spec/graphql/schema/type_expression_spec.rb +3 -3
- data/spec/graphql/schema/validation_spec.rb +7 -3
- data/spec/graphql/schema/warden_spec.rb +510 -0
- data/spec/graphql/schema_spec.rb +129 -0
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -1
- data/spec/graphql/static_validation/type_stack_spec.rb +3 -3
- data/spec/spec_helper.rb +27 -1
- data/spec/support/dairy_app.rb +8 -5
- metadata +21 -3
- data/lib/graphql/language/parser_tests.rb +0 -809
data/lib/graphql/scalar_type.rb
CHANGED
@@ -41,7 +41,7 @@ module GraphQL
|
|
41
41
|
self.coerce_result = proc
|
42
42
|
end
|
43
43
|
|
44
|
-
def validate_non_null_input(value)
|
44
|
+
def validate_non_null_input(value, warden)
|
45
45
|
result = Query::InputValidationResult.new
|
46
46
|
if coerce_non_null_input(value).nil?
|
47
47
|
result.add_problem("Could not coerce value #{JSON.generate(value, quirks_mode: true)} to #{name}")
|
data/lib/graphql/schema.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "graphql/schema/catchall_middleware"
|
2
2
|
require "graphql/schema/invalid_type_error"
|
3
|
+
require "graphql/schema/instrumented_field_map"
|
3
4
|
require "graphql/schema/middleware_chain"
|
4
5
|
require "graphql/schema/possible_types"
|
5
6
|
require "graphql/schema/rescue_middleware"
|
@@ -9,6 +10,8 @@ require "graphql/schema/type_expression"
|
|
9
10
|
require "graphql/schema/type_map"
|
10
11
|
require "graphql/schema/unique_within_type"
|
11
12
|
require "graphql/schema/validation"
|
13
|
+
require "graphql/schema/warden"
|
14
|
+
require "graphql/schema/build_from_definition"
|
12
15
|
|
13
16
|
module GraphQL
|
14
17
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
@@ -43,6 +46,8 @@ module GraphQL
|
|
43
46
|
# end
|
44
47
|
#
|
45
48
|
class Schema
|
49
|
+
include BuildFromDefinition
|
50
|
+
|
46
51
|
include GraphQL::Define::InstanceDefinable
|
47
52
|
accepts_definitions \
|
48
53
|
:query, :mutation, :subscription,
|
@@ -50,6 +55,8 @@ module GraphQL
|
|
50
55
|
:max_depth, :max_complexity,
|
51
56
|
:orphan_types, :resolve_type,
|
52
57
|
:object_from_id, :id_from_object,
|
58
|
+
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m }},
|
59
|
+
instrument: -> (schema, type, instrumenter) { schema.instrumenters[type] << instrumenter },
|
53
60
|
query_analyzer: ->(schema, analyzer) { schema.query_analyzers << analyzer },
|
54
61
|
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
55
62
|
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block)}
|
@@ -58,13 +65,14 @@ module GraphQL
|
|
58
65
|
:query, :mutation, :subscription,
|
59
66
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
60
67
|
:max_depth, :max_complexity,
|
61
|
-
:orphan_types,
|
62
|
-
:query_analyzers, :middleware
|
68
|
+
:orphan_types, :directives,
|
69
|
+
:query_analyzers, :middleware, :instrumenters
|
63
70
|
|
71
|
+
BUILT_IN_TYPES = Hash[[INT_TYPE, STRING_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, ID_TYPE].map{ |type| [type.name, type] }]
|
64
72
|
DIRECTIVES = [GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
|
65
73
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
|
66
74
|
|
67
|
-
attr_reader :
|
75
|
+
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
68
76
|
|
69
77
|
# @!attribute [r] middleware
|
70
78
|
# @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
|
@@ -83,6 +91,7 @@ module GraphQL
|
|
83
91
|
@resolve_type_proc = nil
|
84
92
|
@object_from_id_proc = nil
|
85
93
|
@id_from_object_proc = nil
|
94
|
+
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
86
95
|
# Default to the built-in execution strategy:
|
87
96
|
@query_execution_strategy = GraphQL::Query::SerialExecution
|
88
97
|
@mutation_execution_strategy = GraphQL::Query::SerialExecution
|
@@ -101,21 +110,33 @@ module GraphQL
|
|
101
110
|
|
102
111
|
def define(**kwargs, &block)
|
103
112
|
super
|
104
|
-
|
113
|
+
all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
|
114
|
+
@types = GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
|
115
|
+
|
116
|
+
@instrumented_field_map = InstrumentedFieldMap.new(self)
|
117
|
+
field_instrumenters = @instrumenters[:field]
|
118
|
+
types.each do |type_name, type|
|
119
|
+
if type.kind.fields?
|
120
|
+
type.all_fields.each do |field_defn|
|
121
|
+
|
122
|
+
instrumented_field_defn = field_instrumenters.reduce(field_defn) do |defn, inst|
|
123
|
+
inst.instrument(type, defn)
|
124
|
+
end
|
125
|
+
|
126
|
+
@instrumented_field_map.set(type.name, field_defn.name, instrumented_field_defn)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
105
130
|
# Assert that all necessary configs are present:
|
106
131
|
validation_error = Validation.validate(self)
|
107
132
|
validation_error && raise(NotImplementedError, validation_error)
|
108
133
|
nil
|
109
134
|
end
|
110
135
|
|
136
|
+
|
137
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
111
138
|
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
|
112
|
-
|
113
|
-
@types ||= begin
|
114
|
-
ensure_defined
|
115
|
-
all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
|
116
|
-
GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
|
117
|
-
end
|
118
|
-
end
|
139
|
+
attr_reader :types
|
119
140
|
|
120
141
|
# Execute a query on itself.
|
121
142
|
# See {Query#initialize} for arguments.
|
@@ -127,9 +148,11 @@ module GraphQL
|
|
127
148
|
|
128
149
|
# Resolve field named `field_name` for type `parent_type`.
|
129
150
|
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
|
151
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
152
|
+
# @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
|
130
153
|
def get_field(parent_type, field_name)
|
131
154
|
ensure_defined
|
132
|
-
defined_field = parent_type.
|
155
|
+
defined_field = @instrumented_field_map.get(parent_type.name, field_name)
|
133
156
|
if defined_field
|
134
157
|
defined_field
|
135
158
|
elsif field_name == "__typename"
|
@@ -137,7 +160,7 @@ module GraphQL
|
|
137
160
|
elsif field_name == "__schema" && parent_type == query
|
138
161
|
GraphQL::Introspection::SchemaField.create(self)
|
139
162
|
elsif field_name == "__type" && parent_type == query
|
140
|
-
GraphQL::Introspection::TypeByNameField.create(self
|
163
|
+
GraphQL::Introspection::TypeByNameField.create(self)
|
141
164
|
else
|
142
165
|
nil
|
143
166
|
end
|
@@ -145,16 +168,16 @@ module GraphQL
|
|
145
168
|
|
146
169
|
def type_from_ast(ast_node)
|
147
170
|
ensure_defined
|
148
|
-
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
171
|
+
GraphQL::Schema::TypeExpression.build_type(self.types, ast_node)
|
149
172
|
end
|
150
173
|
|
151
|
-
#
|
174
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
152
175
|
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
153
176
|
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
154
177
|
def possible_types(type_defn)
|
155
178
|
ensure_defined
|
156
|
-
@
|
157
|
-
@
|
179
|
+
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
180
|
+
@possible_types.possible_types(type_defn)
|
158
181
|
end
|
159
182
|
|
160
183
|
def root_type_for_operation(operation)
|
@@ -184,7 +207,8 @@ module GraphQL
|
|
184
207
|
end
|
185
208
|
|
186
209
|
# Determine the GraphQL type for a given object.
|
187
|
-
# This is required for unions and interfaces (
|
210
|
+
# This is required for unions and interfaces (including Relay's `Node` interface)
|
211
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
188
212
|
# @param object [Any] An application object which GraphQL is currently resolving on
|
189
213
|
# @param ctx [GraphQL::Query::Context] The context for the current query
|
190
214
|
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
@@ -250,6 +274,13 @@ module GraphQL
|
|
250
274
|
@id_from_object_proc = new_proc
|
251
275
|
end
|
252
276
|
|
277
|
+
# Create schema with the result of an introspection query.
|
278
|
+
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
279
|
+
# @return [GraphQL::Schema] the schema described by `input`
|
280
|
+
def self.from_introspection(introspection_result)
|
281
|
+
GraphQL::Schema::Loader.load(introspection_result)
|
282
|
+
end
|
283
|
+
|
253
284
|
private
|
254
285
|
|
255
286
|
# Lazily create a middleware and add it to the schema
|
@@ -0,0 +1,248 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Schema
|
3
|
+
module BuildFromDefinition
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
class InvalidDocumentError < Error; end;
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# Create schema from an IDL schema.
|
12
|
+
# @param definition_string String A schema definition string
|
13
|
+
# @return [GraphQL::Schema] the schema described by `document`
|
14
|
+
def from_definition(definition_string)
|
15
|
+
document = GraphQL::parse(definition_string)
|
16
|
+
Builder.build(document)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Builder
|
21
|
+
extend self
|
22
|
+
|
23
|
+
def build(document)
|
24
|
+
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
25
|
+
|
26
|
+
schema_definition = nil
|
27
|
+
types = {}
|
28
|
+
types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
|
29
|
+
directives = {}
|
30
|
+
type_resolver = -> (type) { -> { resolve_type(types, type) } }
|
31
|
+
|
32
|
+
document.definitions.each do |definition|
|
33
|
+
case definition
|
34
|
+
when GraphQL::Language::Nodes::SchemaDefinition
|
35
|
+
raise InvalidDocumentError.new('Must provide only one schema definition.') if schema_definition
|
36
|
+
schema_definition = definition
|
37
|
+
when GraphQL::Language::Nodes::EnumTypeDefinition
|
38
|
+
types[definition.name] = build_enum_type(definition, type_resolver)
|
39
|
+
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
40
|
+
types[definition.name] = build_object_type(definition, type_resolver)
|
41
|
+
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
42
|
+
types[definition.name] = build_interface_type(definition, type_resolver)
|
43
|
+
when GraphQL::Language::Nodes::UnionTypeDefinition
|
44
|
+
types[definition.name] = build_union_type(definition, type_resolver)
|
45
|
+
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
46
|
+
types[definition.name] = build_scalar_type(definition, type_resolver)
|
47
|
+
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
48
|
+
types[definition.name] = build_input_object_type(definition, type_resolver)
|
49
|
+
when GraphQL::Language::Nodes::DirectiveDefinition
|
50
|
+
directives[definition.name] = build_directive(definition, type_resolver)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
GraphQL::Schema::DIRECTIVES.each do |built_in_directive|
|
55
|
+
directives[built_in_directive.name] = built_in_directive unless directives[built_in_directive.name]
|
56
|
+
end
|
57
|
+
|
58
|
+
if schema_definition
|
59
|
+
if schema_definition.query
|
60
|
+
raise InvalidDocumentError.new("Specified query type \"#{schema_definition.query}\" not found in document.") unless types[schema_definition.query]
|
61
|
+
query_root_type = types[schema_definition.query]
|
62
|
+
end
|
63
|
+
|
64
|
+
if schema_definition.mutation
|
65
|
+
raise InvalidDocumentError.new("Specified mutation type \"#{schema_definition.mutation}\" not found in document.") unless types[schema_definition.mutation]
|
66
|
+
mutation_root_type = types[schema_definition.mutation]
|
67
|
+
end
|
68
|
+
|
69
|
+
if schema_definition.subscription
|
70
|
+
raise InvalidDocumentError.new("Specified subscription type \"#{schema_definition.subscription}\" not found in document.") unless types[schema_definition.subscription]
|
71
|
+
subscription_root_type = types[schema_definition.subscription]
|
72
|
+
end
|
73
|
+
else
|
74
|
+
query_root_type = types['Query']
|
75
|
+
mutation_root_type = types['Mutation']
|
76
|
+
subscription_root_type = types['Subscription']
|
77
|
+
end
|
78
|
+
|
79
|
+
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
80
|
+
|
81
|
+
Schema.define do
|
82
|
+
query query_root_type
|
83
|
+
mutation mutation_root_type
|
84
|
+
subscription subscription_root_type
|
85
|
+
orphan_types types.values
|
86
|
+
resolve_type NullResolveType
|
87
|
+
|
88
|
+
directives directives.values
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
NullResolveType = -> (obj, ctx) {
|
93
|
+
raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution.")
|
94
|
+
}
|
95
|
+
|
96
|
+
def build_enum_type(enum_type_definition, type_resolver)
|
97
|
+
GraphQL::EnumType.define(
|
98
|
+
name: enum_type_definition.name,
|
99
|
+
description: enum_type_definition.description,
|
100
|
+
values: enum_type_definition.values.map do |enum_value_definition|
|
101
|
+
EnumType::EnumValue.define(
|
102
|
+
name: enum_value_definition.name,
|
103
|
+
value: enum_value_definition.name,
|
104
|
+
deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
|
105
|
+
description: enum_value_definition.description,
|
106
|
+
)
|
107
|
+
end
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
def build_deprecation_reason(directives)
|
112
|
+
deprecated_directive = directives.find{ |d| d.name == 'deprecated' }
|
113
|
+
return unless deprecated_directive
|
114
|
+
|
115
|
+
reason = deprecated_directive.arguments.find{ |a| a.name == 'reason' }
|
116
|
+
return GraphQL::Directive::DEFAULT_DEPRECATION_REASON unless reason
|
117
|
+
|
118
|
+
reason.value
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_scalar_type(scalar_type_definition, type_resolver)
|
122
|
+
GraphQL::ScalarType.define(
|
123
|
+
name: scalar_type_definition.name,
|
124
|
+
description: scalar_type_definition.description,
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def build_union_type(union_type_definition, type_resolver)
|
129
|
+
GraphQL::UnionType.define(
|
130
|
+
name: union_type_definition.name,
|
131
|
+
description: union_type_definition.description,
|
132
|
+
possible_types: union_type_definition.types.map{ |type_name| type_resolver.call(type_name) },
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
def build_object_type(object_type_definition, type_resolver)
|
137
|
+
GraphQL::ObjectType.define(
|
138
|
+
name: object_type_definition.name,
|
139
|
+
description: object_type_definition.description,
|
140
|
+
fields: Hash[build_fields(object_type_definition.fields, type_resolver)],
|
141
|
+
interfaces: object_type_definition.interfaces.map{ |interface_name| type_resolver.call(interface_name) },
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_input_object_type(input_object_type_definition, type_resolver)
|
146
|
+
GraphQL::InputObjectType.define(
|
147
|
+
name: input_object_type_definition.name,
|
148
|
+
description: input_object_type_definition.description,
|
149
|
+
arguments: Hash[build_input_arguments(input_object_type_definition, type_resolver)],
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def build_input_arguments(input_object_type_definition, type_resolver)
|
154
|
+
input_object_type_definition.fields.map do |input_argument|
|
155
|
+
default_value = case input_argument.default_value
|
156
|
+
when GraphQL::Language::Nodes::Enum
|
157
|
+
input_argument.default_value.name
|
158
|
+
else
|
159
|
+
input_argument.default_value
|
160
|
+
end
|
161
|
+
|
162
|
+
[
|
163
|
+
input_argument.name,
|
164
|
+
GraphQL::Argument.define(
|
165
|
+
name: input_argument.name,
|
166
|
+
type: type_resolver.call(input_argument.type),
|
167
|
+
description: input_argument.description,
|
168
|
+
default_value: default_value,
|
169
|
+
)
|
170
|
+
]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def build_directive(directive_definition, type_resolver)
|
175
|
+
GraphQL::Directive.define(
|
176
|
+
name: directive_definition.name,
|
177
|
+
description: directive_definition.description,
|
178
|
+
arguments: Hash[build_directive_arguments(directive_definition, type_resolver)],
|
179
|
+
locations: directive_definition.locations.map(&:to_sym),
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def build_directive_arguments(directive_definition, type_resolver)
|
184
|
+
directive_definition.arguments.map do |directive_argument|
|
185
|
+
[
|
186
|
+
directive_argument.name,
|
187
|
+
GraphQL::Argument.define(
|
188
|
+
name: directive_argument.name,
|
189
|
+
type: type_resolver.call(directive_argument.type),
|
190
|
+
description: directive_argument.description,
|
191
|
+
default_value: directive_argument.default_value,
|
192
|
+
)
|
193
|
+
]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def build_interface_type(interface_type_definition, type_resolver)
|
198
|
+
GraphQL::InterfaceType.define(
|
199
|
+
name: interface_type_definition.name,
|
200
|
+
description: interface_type_definition.description,
|
201
|
+
fields: Hash[build_fields(interface_type_definition.fields, type_resolver)],
|
202
|
+
)
|
203
|
+
end
|
204
|
+
|
205
|
+
def build_fields(field_definitions, type_resolver)
|
206
|
+
field_definitions.map do |field_definition|
|
207
|
+
field_arguments = Hash[field_definition.arguments.map do |argument|
|
208
|
+
default_value = case argument.default_value
|
209
|
+
when GraphQL::Language::Nodes::Enum
|
210
|
+
argument.default_value.name
|
211
|
+
else
|
212
|
+
argument.default_value
|
213
|
+
end
|
214
|
+
|
215
|
+
arg = GraphQL::Argument.define(
|
216
|
+
name: argument.name,
|
217
|
+
description: argument.description,
|
218
|
+
type: type_resolver.call(argument.type),
|
219
|
+
default_value: default_value,
|
220
|
+
)
|
221
|
+
|
222
|
+
[argument.name, arg]
|
223
|
+
end]
|
224
|
+
|
225
|
+
[
|
226
|
+
field_definition.name,
|
227
|
+
GraphQL::Field.define(
|
228
|
+
name: field_definition.name,
|
229
|
+
description: field_definition.description,
|
230
|
+
type: type_resolver.call(field_definition.type),
|
231
|
+
arguments: field_arguments,
|
232
|
+
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
233
|
+
)
|
234
|
+
]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def resolve_type(types, ast_node)
|
239
|
+
type = GraphQL::Schema::TypeExpression.build_type(types, ast_node)
|
240
|
+
raise InvalidDocumentError.new("Type \"#{ast_node.name}\" not found in document.") unless type
|
241
|
+
type
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
private_constant :Builder
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Schema
|
3
|
+
# A two-level map with fields as the last values.
|
4
|
+
# The first level is type names, which point to a second map.
|
5
|
+
# The second level is field names, which point to fields.
|
6
|
+
#
|
7
|
+
# The catch is, the fields in this map _may_ have been modified by being instrumented.
|
8
|
+
class InstrumentedFieldMap
|
9
|
+
def initialize(schema)
|
10
|
+
@storage = Hash.new { |h, k| h[k] = {} }
|
11
|
+
end
|
12
|
+
|
13
|
+
def set(type_name, field_name, field)
|
14
|
+
@storage[type_name][field_name] = field
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(type_name, field_name)
|
18
|
+
type = @storage[type_name]
|
19
|
+
type && type[field_name]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
10
10
|
# Create schema with the result of an introspection query.
|
11
11
|
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
12
12
|
# @return [GraphQL::Schema] the schema described by `input`
|
13
|
+
# @deprecated Use {GraphQL::Schema.from_introspection} instead
|
13
14
|
def load(introspection_result)
|
14
15
|
schema = introspection_result.fetch("data").fetch("__schema")
|
15
16
|
|
@@ -109,17 +110,9 @@ module GraphQL
|
|
109
110
|
default_value: type["defaultValue"] ? JSON.parse(type["defaultValue"], quirks_mode: true) : nil
|
110
111
|
)
|
111
112
|
when "SCALAR"
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
when "String"
|
116
|
-
STRING_TYPE
|
117
|
-
when "Float"
|
118
|
-
FLOAT_TYPE
|
119
|
-
when "Boolean"
|
120
|
-
BOOLEAN_TYPE
|
121
|
-
when "ID"
|
122
|
-
ID_TYPE
|
113
|
+
type_name = type.fetch("name")
|
114
|
+
if GraphQL::Schema::BUILT_IN_TYPES[type_name]
|
115
|
+
GraphQL::Schema::BUILT_IN_TYPES[type_name]
|
123
116
|
else
|
124
117
|
ScalarType.define(
|
125
118
|
name: type["name"],
|