graphql 0.12.1 → 0.13.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 +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
|