graphql 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +31 -41
- data/lib/graphql/argument.rb +23 -21
- data/lib/graphql/base_type.rb +5 -8
- data/lib/graphql/define/assign_argument.rb +5 -2
- data/lib/graphql/define/type_definer.rb +2 -1
- data/lib/graphql/directive.rb +34 -36
- data/lib/graphql/directive/include_directive.rb +3 -7
- data/lib/graphql/directive/skip_directive.rb +3 -7
- data/lib/graphql/enum_type.rb +78 -76
- data/lib/graphql/execution_error.rb +1 -3
- data/lib/graphql/field.rb +99 -95
- data/lib/graphql/input_object_type.rb +49 -47
- data/lib/graphql/interface_type.rb +31 -34
- data/lib/graphql/introspection.rb +19 -18
- data/lib/graphql/introspection/directive_location_enum.rb +8 -0
- data/lib/graphql/introspection/directive_type.rb +1 -3
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/fields_field.rb +1 -1
- data/lib/graphql/introspection/introspection_query.rb +1 -3
- data/lib/graphql/introspection/possible_types_field.rb +7 -1
- data/lib/graphql/introspection/schema_field.rb +13 -9
- data/lib/graphql/introspection/type_by_name_field.rb +13 -17
- data/lib/graphql/introspection/typename_field.rb +12 -8
- data/lib/graphql/language.rb +5 -9
- data/lib/graphql/language/lexer.rb +668 -0
- data/lib/graphql/language/lexer.rl +149 -0
- data/lib/graphql/language/parser.rb +842 -116
- data/lib/graphql/language/parser.y +264 -0
- data/lib/graphql/language/token.rb +21 -0
- data/lib/graphql/list_type.rb +33 -31
- data/lib/graphql/non_null_type.rb +33 -31
- data/lib/graphql/object_type.rb +52 -55
- data/lib/graphql/query.rb +83 -80
- data/lib/graphql/query/context.rb +5 -1
- data/lib/graphql/query/directive_resolution.rb +16 -0
- data/lib/graphql/query/executor.rb +3 -3
- data/lib/graphql/query/input_validation_result.rb +17 -15
- data/lib/graphql/query/serial_execution.rb +5 -5
- data/lib/graphql/query/serial_execution/execution_context.rb +4 -3
- data/lib/graphql/query/serial_execution/selection_resolution.rb +19 -21
- data/lib/graphql/query/serial_execution/value_resolution.rb +1 -1
- data/lib/graphql/query/type_resolver.rb +22 -18
- data/lib/graphql/query/variable_validation_error.rb +14 -12
- data/lib/graphql/schema.rb +87 -77
- data/lib/graphql/schema/each_item_validator.rb +16 -12
- data/lib/graphql/schema/field_validator.rb +14 -10
- data/lib/graphql/schema/implementation_validator.rb +26 -22
- data/lib/graphql/schema/middleware_chain.rb +2 -1
- data/lib/graphql/schema/possible_types.rb +34 -0
- data/lib/graphql/schema/printer.rb +122 -120
- data/lib/graphql/schema/type_expression.rb +1 -0
- data/lib/graphql/schema/type_map.rb +3 -10
- data/lib/graphql/schema/type_reducer.rb +65 -81
- data/lib/graphql/schema/type_validator.rb +45 -41
- data/lib/graphql/static_validation.rb +7 -9
- data/lib/graphql/static_validation/all_rules.rb +29 -24
- data/lib/graphql/static_validation/arguments_validator.rb +39 -35
- data/lib/graphql/static_validation/literal_validator.rb +44 -40
- data/lib/graphql/static_validation/message.rb +30 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +15 -11
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +14 -10
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +16 -12
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +59 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +25 -21
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +28 -24
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +84 -80
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +49 -43
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +22 -17
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +19 -15
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +36 -23
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +29 -25
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +21 -17
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +79 -70
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +24 -20
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +122 -119
- data/lib/graphql/static_validation/type_stack.rb +138 -129
- data/lib/graphql/static_validation/validator.rb +29 -25
- data/lib/graphql/type_kinds.rb +42 -40
- data/lib/graphql/union_type.rb +22 -16
- data/lib/graphql/version.rb +1 -1
- data/readme.md +12 -27
- data/spec/graphql/base_type_spec.rb +3 -3
- data/spec/graphql/directive_spec.rb +10 -18
- data/spec/graphql/enum_type_spec.rb +7 -7
- data/spec/graphql/execution_error_spec.rb +1 -1
- data/spec/graphql/field_spec.rb +14 -13
- data/spec/graphql/id_type_spec.rb +6 -6
- data/spec/graphql/input_object_type_spec.rb +39 -39
- data/spec/graphql/interface_type_spec.rb +16 -32
- data/spec/graphql/introspection/directive_type_spec.rb +5 -9
- data/spec/graphql/introspection/input_value_type_spec.rb +10 -4
- data/spec/graphql/introspection/introspection_query_spec.rb +2 -2
- data/spec/graphql/introspection/schema_type_spec.rb +2 -2
- data/spec/graphql/introspection/type_type_spec.rb +34 -6
- data/spec/graphql/language/parser_spec.rb +299 -105
- data/spec/graphql/language/visitor_spec.rb +4 -4
- data/spec/graphql/list_type_spec.rb +11 -11
- data/spec/graphql/object_type_spec.rb +10 -10
- data/spec/graphql/query/arguments_spec.rb +7 -7
- data/spec/graphql/query/context_spec.rb +11 -3
- data/spec/graphql/query/executor_spec.rb +26 -19
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +6 -6
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
- data/spec/graphql/query/type_resolver_spec.rb +3 -3
- data/spec/graphql/query_spec.rb +6 -38
- data/spec/graphql/scalar_type_spec.rb +28 -19
- data/spec/graphql/schema/field_validator_spec.rb +1 -1
- data/spec/graphql/schema/middleware_chain_spec.rb +12 -1
- data/spec/graphql/schema/printer_spec.rb +12 -4
- data/spec/graphql/schema/rescue_middleware_spec.rb +1 -1
- data/spec/graphql/schema/type_expression_spec.rb +2 -2
- data/spec/graphql/schema/type_reducer_spec.rb +21 -36
- data/spec/graphql/schema/type_validator_spec.rb +9 -9
- data/spec/graphql/schema_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +39 -0
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +3 -1
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
- data/spec/graphql/static_validation/type_stack_spec.rb +3 -2
- data/spec/graphql/static_validation/validator_spec.rb +26 -6
- data/spec/graphql/union_type_spec.rb +5 -4
- data/spec/spec_helper.rb +2 -5
- data/spec/support/dairy_app.rb +30 -9
- data/spec/support/dairy_data.rb +1 -1
- data/spec/support/star_wars_data.rb +26 -26
- data/spec/support/star_wars_schema.rb +1 -1
- metadata +40 -21
- data/lib/graphql/language/transform.rb +0 -113
- data/lib/graphql/query/directive_chain.rb +0 -44
- data/lib/graphql/repl.rb +0 -27
- data/spec/graphql/language/transform_spec.rb +0 -156
@@ -0,0 +1,264 @@
|
|
1
|
+
class GraphQL::Language::Parser
|
2
|
+
rule
|
3
|
+
target: document
|
4
|
+
|
5
|
+
document: definitions_list { return make_node(:Document, definitions: val[0])}
|
6
|
+
|
7
|
+
definitions_list:
|
8
|
+
definition { return [val[0]]}
|
9
|
+
| definitions_list definition { val[0] << val[1] }
|
10
|
+
|
11
|
+
definition:
|
12
|
+
operation_definition
|
13
|
+
| fragment_definition
|
14
|
+
|
15
|
+
operation_definition:
|
16
|
+
name operation_name_opt variable_definitions_opt directives_list_opt selection_set {
|
17
|
+
return make_node(
|
18
|
+
:OperationDefinition, {
|
19
|
+
operation_type: val[0],
|
20
|
+
name: val[1],
|
21
|
+
variables: val[2],
|
22
|
+
directives: val[3],
|
23
|
+
selections: val[4],
|
24
|
+
position_source: val[0],
|
25
|
+
}
|
26
|
+
)
|
27
|
+
}
|
28
|
+
| selection_set {
|
29
|
+
return make_node(
|
30
|
+
:OperationDefinition, {
|
31
|
+
operation_type: "query",
|
32
|
+
selections: val[0],
|
33
|
+
}
|
34
|
+
)
|
35
|
+
}
|
36
|
+
|
37
|
+
operation_name_opt:
|
38
|
+
/* none */ { return nil }
|
39
|
+
| name
|
40
|
+
|
41
|
+
variable_definitions_opt:
|
42
|
+
/* none */ { return [] }
|
43
|
+
| RPAREN variable_definitions_list LPAREN { return val[1] }
|
44
|
+
|
45
|
+
variable_definitions_list:
|
46
|
+
variable_definition { return [val[0]] }
|
47
|
+
| variable_definitions_list variable_definition { val[0] << val[1] }
|
48
|
+
|
49
|
+
variable_definition:
|
50
|
+
VAR_SIGN name COLON variable_definition_type_name variable_definition_default_value_opt {
|
51
|
+
return make_node(:VariableDefinition, {
|
52
|
+
name: val[1],
|
53
|
+
type: val[3],
|
54
|
+
default_value: val[4],
|
55
|
+
position_source: val[0],
|
56
|
+
})
|
57
|
+
}
|
58
|
+
|
59
|
+
variable_definition_type_name:
|
60
|
+
name { return make_node(:TypeName, name: val[0])}
|
61
|
+
| variable_definition_type_name BANG { return make_node(:NonNullType, of_type: val[0]) }
|
62
|
+
| RBRACKET variable_definition_type_name LBRACKET { return make_node(:ListType, of_type: val[1]) }
|
63
|
+
|
64
|
+
variable_definition_default_value_opt:
|
65
|
+
/* none */ { return nil }
|
66
|
+
| EQUALS input_value { return val[1] }
|
67
|
+
|
68
|
+
selection_set:
|
69
|
+
RCURLY LCURLY { return [] }
|
70
|
+
| RCURLY selection_list LCURLY { return val[1] }
|
71
|
+
|
72
|
+
selection_set_opt:
|
73
|
+
/* none */ { return [] }
|
74
|
+
| selection_set { return val[0] }
|
75
|
+
|
76
|
+
selection_list:
|
77
|
+
selection { return [result] }
|
78
|
+
| selection_list selection { val[0] << val[1] }
|
79
|
+
|
80
|
+
selection:
|
81
|
+
field
|
82
|
+
| fragment_spread
|
83
|
+
| inline_fragment
|
84
|
+
|
85
|
+
field:
|
86
|
+
name arguments_opt directives_list_opt selection_set_opt {
|
87
|
+
return make_node(
|
88
|
+
:Field, {
|
89
|
+
name: val[0],
|
90
|
+
arguments: val[1],
|
91
|
+
directives: val[2],
|
92
|
+
selections: val[3],
|
93
|
+
position_source: val[0],
|
94
|
+
}
|
95
|
+
)
|
96
|
+
}
|
97
|
+
| name COLON name arguments_opt directives_list_opt selection_set_opt {
|
98
|
+
return make_node(
|
99
|
+
:Field, {
|
100
|
+
alias: val[0],
|
101
|
+
name: val[2],
|
102
|
+
arguments: val[3],
|
103
|
+
directives: val[4],
|
104
|
+
selections: val[5],
|
105
|
+
position_source: val[0],
|
106
|
+
}
|
107
|
+
)
|
108
|
+
}
|
109
|
+
|
110
|
+
name:
|
111
|
+
IDENTIFIER
|
112
|
+
| FRAGMENT
|
113
|
+
| TRUE
|
114
|
+
| FALSE
|
115
|
+
| ON
|
116
|
+
|
117
|
+
arguments_opt:
|
118
|
+
/* none */ { return [] }
|
119
|
+
| RPAREN LPAREN { return [] }
|
120
|
+
| RPAREN arguments_list LPAREN { return val[1] }
|
121
|
+
|
122
|
+
arguments_list:
|
123
|
+
argument { return [val[0]] }
|
124
|
+
| arguments_list argument { val[0] << val[1] }
|
125
|
+
|
126
|
+
argument:
|
127
|
+
name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
|
128
|
+
|
129
|
+
input_value:
|
130
|
+
FLOAT { return val[0].to_f }
|
131
|
+
| INT { return val[0].to_i }
|
132
|
+
| STRING { return val[0].to_s }
|
133
|
+
| TRUE { return true }
|
134
|
+
| FALSE { return false }
|
135
|
+
| variable
|
136
|
+
| list_value
|
137
|
+
| object_value
|
138
|
+
| enum_value
|
139
|
+
|
140
|
+
variable: VAR_SIGN name { return make_node(:VariableIdentifier, name: val[1], position_source: val[0]) }
|
141
|
+
|
142
|
+
list_value:
|
143
|
+
RBRACKET LBRACKET { return [] }
|
144
|
+
| RBRACKET list_value_list LBRACKET { return val[1] }
|
145
|
+
|
146
|
+
list_value_list:
|
147
|
+
input_value { return [val[0]] }
|
148
|
+
| list_value_list input_value { val[0] << val[1] }
|
149
|
+
|
150
|
+
object_value:
|
151
|
+
RCURLY LCURLY { return make_node(:InputObject, arguments: [], position_source: val[0])}
|
152
|
+
| RCURLY object_value_list LCURLY { return make_node(:InputObject, arguments: val[1], position_source: val[0])}
|
153
|
+
|
154
|
+
object_value_list:
|
155
|
+
object_value_field { return [val[0]] }
|
156
|
+
| object_value_list object_value_field { val[0] << val[1] }
|
157
|
+
|
158
|
+
object_value_field:
|
159
|
+
name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
|
160
|
+
|
161
|
+
enum_value: IDENTIFIER { return make_node(:Enum, name: val[0], position_source: val[0])}
|
162
|
+
|
163
|
+
directives_list_opt:
|
164
|
+
/* none */ { return [] }
|
165
|
+
| directives_list
|
166
|
+
|
167
|
+
directives_list:
|
168
|
+
directive { return [val[0]] }
|
169
|
+
| directives_list directive { val[0] << val[1] }
|
170
|
+
|
171
|
+
directive: DIR_SIGN name arguments_opt { return make_node(:Directive, name: val[1], arguments: val[2], position_source: val[0]) }
|
172
|
+
|
173
|
+
fragment_spread:
|
174
|
+
ELLIPSIS name directives_list_opt { return make_node(:FragmentSpread, name: val[1], directives: val[2], position_source: val[0]) }
|
175
|
+
|
176
|
+
inline_fragment:
|
177
|
+
ELLIPSIS ON name directives_list_opt selection_set {
|
178
|
+
return make_node(:InlineFragment, {
|
179
|
+
type: val[2],
|
180
|
+
directives: val[3],
|
181
|
+
selections: val[4],
|
182
|
+
position_source: val[0]
|
183
|
+
})
|
184
|
+
}
|
185
|
+
| ELLIPSIS directives_list_opt selection_set {
|
186
|
+
return make_node(:InlineFragment, {
|
187
|
+
type: nil,
|
188
|
+
directives: val[1],
|
189
|
+
selections: val[2],
|
190
|
+
position_source: val[0]
|
191
|
+
})
|
192
|
+
}
|
193
|
+
|
194
|
+
fragment_definition:
|
195
|
+
FRAGMENT name ON name directives_list_opt selection_set {
|
196
|
+
return make_node(:FragmentDefinition, {
|
197
|
+
name: val[1],
|
198
|
+
type: val[3],
|
199
|
+
directives: val[4],
|
200
|
+
selections: val[5],
|
201
|
+
position_source: val[0],
|
202
|
+
}
|
203
|
+
)
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
---- header ----
|
208
|
+
|
209
|
+
|
210
|
+
---- inner ----
|
211
|
+
|
212
|
+
def initialize(query_string)
|
213
|
+
@query_string = query_string
|
214
|
+
end
|
215
|
+
|
216
|
+
def parse_document
|
217
|
+
@document ||= begin
|
218
|
+
@tokens ||= GraphQL::Language::Lexer.tokenize(@query_string)
|
219
|
+
if @tokens.none?
|
220
|
+
make_node(:Document, definitions: [])
|
221
|
+
else
|
222
|
+
do_parse
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.parse(query_string)
|
228
|
+
self.new(query_string).parse_document
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
def next_token
|
234
|
+
lexer_token = @tokens.shift
|
235
|
+
if lexer_token.nil?
|
236
|
+
nil
|
237
|
+
else
|
238
|
+
[lexer_token.name, lexer_token]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def on_error(parser_token_id, lexer_token, vstack)
|
243
|
+
if lexer_token == "$"
|
244
|
+
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string)
|
245
|
+
else
|
246
|
+
parser_token_name = token_to_str(parser_token_id)
|
247
|
+
if parser_token_name.nil?
|
248
|
+
raise GraphQL::ParseError.new("Parse Error on unknown token: {token_id: #{parser_token_id}, lexer_token: #{lexer_token}} from #{@query_string}", nil, nil, @query_string)
|
249
|
+
else
|
250
|
+
line, col = lexer_token.line_and_column
|
251
|
+
raise GraphQL::ParseError.new("Parse error on #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def make_node(node_name, assigns)
|
257
|
+
assigns.each do |key, value|
|
258
|
+
if key != :position_source && value.is_a?(GraphQL::Language::Token)
|
259
|
+
assigns[key] = value.to_s
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
GraphQL::Language::Nodes.const_get(node_name).new(assigns)
|
264
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Language
|
3
|
+
class Token
|
4
|
+
attr_reader :name
|
5
|
+
def initialize(value:, name:, line:, col:)
|
6
|
+
@name = name
|
7
|
+
@value = value
|
8
|
+
@line = line
|
9
|
+
@col = col
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s; @value; end
|
13
|
+
def to_i; @value.to_i; end
|
14
|
+
def to_f; @value.to_f; end
|
15
|
+
|
16
|
+
def line_and_column
|
17
|
+
[@line, @col]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/graphql/list_type.rb
CHANGED
@@ -1,44 +1,46 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
module GraphQL
|
2
|
+
# A list type wraps another type.
|
3
|
+
#
|
4
|
+
# Get the underlying type with {#unwrap}
|
5
|
+
class ListType < GraphQL::BaseType
|
6
|
+
include GraphQL::BaseType::ModifiesAnotherType
|
7
|
+
attr_reader :of_type, :name
|
8
|
+
def initialize(of_type:)
|
9
|
+
@name = "List"
|
10
|
+
@of_type = of_type
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def kind
|
14
|
+
GraphQL::TypeKinds::LIST
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
def to_s
|
18
|
+
"[#{of_type.to_s}]"
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
def validate_non_null_input(value)
|
22
|
+
result = GraphQL::Query::InputValidationResult.new
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
ensure_array(value).each_with_index do |item, index|
|
25
|
+
item_result = of_type.validate_input(item)
|
26
|
+
if !item_result.valid?
|
27
|
+
result.merge_result!(index, item_result)
|
28
|
+
end
|
27
29
|
end
|
28
|
-
end
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
result
|
32
|
+
end
|
32
33
|
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def coerce_non_null_input(value)
|
36
|
+
ensure_array(value).map{ |item| of_type.coerce_input(item) }
|
37
|
+
end
|
37
38
|
|
38
39
|
|
39
|
-
|
40
|
+
private
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
def ensure_array(value)
|
43
|
+
value.is_a?(Array) ? value : [value]
|
44
|
+
end
|
43
45
|
end
|
44
46
|
end
|
@@ -1,41 +1,43 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
|
5
|
-
|
1
|
+
module GraphQL
|
2
|
+
# A non-null type wraps another type.
|
3
|
+
#
|
4
|
+
# Get the underlying type with {#unwrap}
|
5
|
+
class NonNullType < GraphQL::BaseType
|
6
|
+
include GraphQL::BaseType::ModifiesAnotherType
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
attr_reader :of_type
|
9
|
+
def initialize(of_type:)
|
10
|
+
@of_type = of_type
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def name
|
14
|
+
"Non-Null"
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
def valid_input?(value)
|
18
|
+
validate_input(value).valid?
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def validate_input(value)
|
22
|
+
if value.nil?
|
23
|
+
result = GraphQL::Query::InputValidationResult.new
|
24
|
+
result.add_problem("Expected value to not be null")
|
25
|
+
result
|
26
|
+
else
|
27
|
+
of_type.validate_input(value)
|
28
|
+
end
|
27
29
|
end
|
28
|
-
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def coerce_input(value)
|
32
|
+
of_type.coerce_input(value)
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def kind
|
36
|
+
GraphQL::TypeKinds::NON_NULL
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
def to_s
|
40
|
+
"#{of_type.to_s}!"
|
41
|
+
end
|
40
42
|
end
|
41
43
|
end
|
data/lib/graphql/object_type.rb
CHANGED
@@ -1,66 +1,63 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# field :
|
11
|
-
# field :
|
12
|
-
# field :
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# stars
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
module GraphQL
|
2
|
+
# This type exposes fields on an object.
|
3
|
+
#
|
4
|
+
# @example defining a type for your IMDB clone
|
5
|
+
# MovieType = GraphQL::ObjectType.define do
|
6
|
+
# name "Movie"
|
7
|
+
# description "A full-length film or a short film"
|
8
|
+
# interfaces [ProductionInterface, DurationInterface]
|
9
|
+
#
|
10
|
+
# field :runtimeMinutes, !types.Int, property: :runtime_minutes
|
11
|
+
# field :director, PersonType
|
12
|
+
# field :cast, CastType
|
13
|
+
# field :starring, types[PersonType] do
|
14
|
+
# arguments :limit, types.Int
|
15
|
+
# resolve -> (object, args, ctx) {
|
16
|
+
# stars = object.cast.stars
|
17
|
+
# args[:limit] && stars = stars.limit(args[:limit])
|
18
|
+
# stars
|
19
|
+
# }
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class ObjectType < GraphQL::BaseType
|
24
|
+
accepts_definitions :interfaces, field: GraphQL::Define::AssignObjectField
|
25
|
+
attr_accessor :name, :description, :interfaces
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
# @return [Hash<String, GraphQL::Field>] Map String fieldnames to their {GraphQL::Field} implementations
|
28
|
+
attr_accessor :fields
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
def initialize
|
31
|
+
@fields = {}
|
32
|
+
@interfaces = []
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@interfaces ||= []
|
39
|
-
(@interfaces - new_interfaces).each { |i| i.possible_types.delete(self) }
|
40
|
-
(new_interfaces - @interfaces).each { |i| i.possible_types << self }
|
41
|
-
@interfaces = new_interfaces
|
42
|
-
end
|
35
|
+
# @param new_interfaces [Array<GraphQL::Interface>] interfaces that this type implements
|
36
|
+
def interfaces=(new_interfaces)
|
37
|
+
@interfaces = new_interfaces
|
38
|
+
end
|
43
39
|
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
def kind
|
41
|
+
GraphQL::TypeKinds::OBJECT
|
42
|
+
end
|
47
43
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
# @return [GraphQL::Field] The field definition for `field_name` (may be inherited from interfaces)
|
45
|
+
def get_field(field_name)
|
46
|
+
fields[field_name] || interface_fields[field_name]
|
47
|
+
end
|
52
48
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
# @return [Array<GraphQL::Field>] All fields, including ones inherited from interfaces
|
50
|
+
def all_fields
|
51
|
+
interface_fields.merge(self.fields).values
|
52
|
+
end
|
57
53
|
|
58
|
-
|
54
|
+
private
|
59
55
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
# Create a {name => defn} hash for fields inherited from interfaces
|
57
|
+
def interface_fields
|
58
|
+
interfaces.reduce({}) do |memo, iface|
|
59
|
+
memo.merge!(iface.fields)
|
60
|
+
end
|
64
61
|
end
|
65
62
|
end
|
66
63
|
end
|