graphql-rb 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +26 -0
- data/lib/graphql/configuration/configurable.rb +46 -0
- data/lib/graphql/configuration/configuration.rb +92 -0
- data/lib/graphql/configuration/slot.rb +124 -0
- data/lib/graphql/configuration.rb +3 -0
- data/lib/graphql/errors/error.rb +3 -0
- data/lib/graphql/errors.rb +1 -0
- data/lib/graphql/executor.rb +83 -0
- data/lib/graphql/introspection/meta_fields.rb +54 -0
- data/lib/graphql/introspection/query.rb +81 -0
- data/lib/graphql/introspection/schema.rb +158 -0
- data/lib/graphql/introspection.rb +3 -0
- data/lib/graphql/language/argument.rb +11 -0
- data/lib/graphql/language/directive.rb +5 -0
- data/lib/graphql/language/document.rb +23 -0
- data/lib/graphql/language/field.rb +55 -0
- data/lib/graphql/language/fragment_definition.rb +23 -0
- data/lib/graphql/language/fragment_spread.rb +5 -0
- data/lib/graphql/language/inline_fragment.rb +23 -0
- data/lib/graphql/language/list_type.rb +15 -0
- data/lib/graphql/language/name.rb +5 -0
- data/lib/graphql/language/named_type.rb +15 -0
- data/lib/graphql/language/non_null_type.rb +15 -0
- data/lib/graphql/language/operation_definition.rb +33 -0
- data/lib/graphql/language/parser.rb +331 -0
- data/lib/graphql/language/selection_set.rb +107 -0
- data/lib/graphql/language/transform.rb +101 -0
- data/lib/graphql/language/value.rb +24 -0
- data/lib/graphql/language/variable.rb +11 -0
- data/lib/graphql/language/variable_definition.rb +34 -0
- data/lib/graphql/language.rb +40 -0
- data/lib/graphql/type/argument.rb +16 -0
- data/lib/graphql/type/directive.rb +37 -0
- data/lib/graphql/type/directives.rb +25 -0
- data/lib/graphql/type/enum_type.rb +100 -0
- data/lib/graphql/type/field.rb +50 -0
- data/lib/graphql/type/input_object_type.rb +47 -0
- data/lib/graphql/type/interface_type.rb +64 -0
- data/lib/graphql/type/list.rb +23 -0
- data/lib/graphql/type/non_null.rb +25 -0
- data/lib/graphql/type/object_type.rb +57 -0
- data/lib/graphql/type/scalar_type.rb +137 -0
- data/lib/graphql/type/schema.rb +49 -0
- data/lib/graphql/type/union_type.rb +39 -0
- data/lib/graphql/type.rb +82 -0
- data/lib/graphql/validator.rb +43 -0
- data/lib/graphql/version.rb +3 -0
- data/lib/graphql.rb +21 -0
- data/spec/configuration/configuration_spec.rb +4 -0
- data/spec/data.rb +89 -0
- data/spec/introspection/full_spec.rb +12 -0
- data/spec/introspection/simple_spec.rb +153 -0
- data/spec/language/parser_spec.rb +73 -0
- data/spec/schema.rb +145 -0
- data/spec/spec_helper.rb +99 -0
- data/spec/type/enum_spec.rb +27 -0
- data/spec/type/input_object_spec.rb +21 -0
- data/spec/type/list_spec.rb +16 -0
- data/spec/type/non_null_spec.rb +22 -0
- data/spec/type/scalar_type_spec.rb +117 -0
- data/spec/type/schema_spec.rb +13 -0
- metadata +202 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Language
|
5
|
+
|
6
|
+
class Transform < Parslet::Transform
|
7
|
+
|
8
|
+
|
9
|
+
rule(document: sequence(:a)) { Document.new(a) }
|
10
|
+
|
11
|
+
|
12
|
+
rule(operation_definition: {
|
13
|
+
type: simple(:a),
|
14
|
+
name: simple(:b),
|
15
|
+
variable_definitions: subtree(:c),
|
16
|
+
directives: subtree(:d),
|
17
|
+
selection_set: simple(:e)
|
18
|
+
}) { OperationDefinition.new(a, b, c || [], d || [], e || []) }
|
19
|
+
|
20
|
+
rule(operation_definition: {
|
21
|
+
selection_set: simple(:a)
|
22
|
+
}) { OperationDefinition.new('query', '', [], [], a) }
|
23
|
+
|
24
|
+
|
25
|
+
rule(fragment_definition: {
|
26
|
+
name: simple(:a),
|
27
|
+
type_condition: subtree(:b),
|
28
|
+
directives: subtree(:c),
|
29
|
+
selection_set: simple(:d)
|
30
|
+
}) { FragmentDefinition.new(a, b, c || [], d || []) }
|
31
|
+
|
32
|
+
|
33
|
+
rule(fragment_spread: {
|
34
|
+
name: simple(:a),
|
35
|
+
directives: subtree(:b)
|
36
|
+
}) { FragmentSpread.new(a, b || []) }
|
37
|
+
|
38
|
+
|
39
|
+
rule(inline_fragment: {
|
40
|
+
type_condition: subtree(:a),
|
41
|
+
directives: subtree(:b),
|
42
|
+
selection_set: simple(:c)
|
43
|
+
}) { InlineFragment.new(a, b || [], c || []) }
|
44
|
+
|
45
|
+
|
46
|
+
rule(field: {
|
47
|
+
alias: simple(:a),
|
48
|
+
name: simple(:b),
|
49
|
+
arguments: subtree(:c),
|
50
|
+
directives: subtree(:d),
|
51
|
+
selection_set: simple(:e)
|
52
|
+
}) { Field.new(a, b, c || [], d || [], e || []) }
|
53
|
+
|
54
|
+
|
55
|
+
rule(directive: {
|
56
|
+
name: simple(:a),
|
57
|
+
arguments: subtree(:b)
|
58
|
+
}) { Directive.new(a, b || []) }
|
59
|
+
|
60
|
+
|
61
|
+
rule(argument: {
|
62
|
+
name: simple(:a),
|
63
|
+
value: simple(:b)
|
64
|
+
}) { Argument.new(a, b) }
|
65
|
+
|
66
|
+
|
67
|
+
rule(selection_set: {
|
68
|
+
selections: subtree(:a)
|
69
|
+
}) { SelectionSet.new(a || []) }
|
70
|
+
|
71
|
+
|
72
|
+
rule(variable_definition: {
|
73
|
+
variable: simple(:a),
|
74
|
+
type: simple(:b),
|
75
|
+
default_value: simple(:c)
|
76
|
+
}) { VariableDefinition.new(a, b, c) }
|
77
|
+
|
78
|
+
|
79
|
+
rule(variable: simple(:a)) { Variable.new(a) }
|
80
|
+
|
81
|
+
rule(named_type: simple(:a)) { NamedType.new(a) }
|
82
|
+
rule(list_type: simple(:a)) { ListType.new(a) }
|
83
|
+
rule(non_null_type: simple(:a)) { NonNullType.new(a) }
|
84
|
+
|
85
|
+
rule(name: simple(:a)) { a.to_s }
|
86
|
+
|
87
|
+
rule(value: simple(:a)) { a }
|
88
|
+
rule(value: subtree(:a)) { Value.new(a[:kind], a[:value]) }
|
89
|
+
|
90
|
+
rule(string_value: simple(:a)) { { value: a.to_s, kind: :string } }
|
91
|
+
rule(int_value: simple(:a)) { { value: a.to_i, kind: :int } }
|
92
|
+
rule(float_value: simple(:a)) { { value: a.to_f, kind: :float } }
|
93
|
+
rule(boolean_value: simple(:a)) { { value: a == 'true', kind: :boolean } }
|
94
|
+
rule(enum_value: simple(:a)) { { value: a, kind: :enum } }
|
95
|
+
rule(list_value: sequence(:a)) { { value: a, kind: :list } }
|
96
|
+
rule(object_value: subtree(:a)) { { value: a, kind: :object } }
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Language
|
3
|
+
Value = Struct.new('Value', :kind, :value) do
|
4
|
+
|
5
|
+
|
6
|
+
def materialize(type, variables)
|
7
|
+
case type
|
8
|
+
when GraphQLNonNull
|
9
|
+
materialize(type.of_type, variables)
|
10
|
+
when GraphQLList
|
11
|
+
value.map { |value| value.materialize(type.of_type, variables) }
|
12
|
+
when GraphQLInputObjectType
|
13
|
+
raise "Not. Implemented. Yet."
|
14
|
+
when GraphQLScalarType, GraphQLEnumType
|
15
|
+
type.parse_literal(self)
|
16
|
+
else
|
17
|
+
raise "Must be input type"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Language
|
3
|
+
VariableDefinition = Struct.new('VariableDefinition', :variable, :type, :default_value) do
|
4
|
+
|
5
|
+
|
6
|
+
def materialize(schema, param)
|
7
|
+
schema_type = type.materialize(schema)
|
8
|
+
|
9
|
+
if schema_type.nil? || !schema_type.is_a?(GraphQLInputType)
|
10
|
+
raise GraphQLError, "Variable '#{variable.name}' expected value " +
|
11
|
+
"of type '#{schema_type}' which cannot be used as input type."
|
12
|
+
end
|
13
|
+
|
14
|
+
if Validator.valid_value?(param, schema_type)
|
15
|
+
if !param && default_value
|
16
|
+
return default_value.materialize(schema_type)
|
17
|
+
end
|
18
|
+
return Validator.coerce_value(param, schema_type)
|
19
|
+
end
|
20
|
+
|
21
|
+
if param
|
22
|
+
raise GraphQLError, "Variable '#{variable.name}' expected value " +
|
23
|
+
"of type '#{schema_type}' but got '#{param}'."
|
24
|
+
else
|
25
|
+
raise GraphQLError, "Variable '#{variable.name}' " +
|
26
|
+
"of required type '#{type}' was not provided."
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'language/document'
|
2
|
+
require_relative 'language/operation_definition'
|
3
|
+
require_relative 'language/fragment_definition'
|
4
|
+
require_relative 'language/fragment_spread'
|
5
|
+
require_relative 'language/inline_fragment'
|
6
|
+
require_relative 'language/selection_set'
|
7
|
+
require_relative 'language/variable_definition'
|
8
|
+
require_relative 'language/variable'
|
9
|
+
require_relative 'language/named_type'
|
10
|
+
require_relative 'language/list_type'
|
11
|
+
require_relative 'language/non_null_type'
|
12
|
+
require_relative 'language/name'
|
13
|
+
require_relative 'language/value'
|
14
|
+
require_relative 'language/field'
|
15
|
+
require_relative 'language/argument'
|
16
|
+
require_relative 'language/directive'
|
17
|
+
|
18
|
+
require_relative 'language/parser'
|
19
|
+
require_relative 'language/transform'
|
20
|
+
|
21
|
+
|
22
|
+
module GraphQL
|
23
|
+
module Language
|
24
|
+
|
25
|
+
def self.parse(query)
|
26
|
+
transform.apply(parser.parse(query))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.parser
|
32
|
+
@parser ||= GraphQL::Language::Parser.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.transform
|
36
|
+
@transform ||= GraphQL::Language::Transform.new
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
# GraphQLArgument
|
4
|
+
#
|
5
|
+
class GraphQLArgumentConfiguration < GraphQL::Configuration::Base
|
6
|
+
slot :name, String, coerce: -> (v) { v.to_s }
|
7
|
+
slot :type, GraphQLInputType
|
8
|
+
slot :default_value, Object, null: true
|
9
|
+
slot :description, String, null: true
|
10
|
+
end
|
11
|
+
|
12
|
+
class GraphQLArgument < GraphQL::Configuration::Configurable
|
13
|
+
configure_with GraphQLArgumentConfiguration
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
# GraphQLDirectiveConfiguration
|
4
|
+
#
|
5
|
+
class GraphQLDirectiveConfiguration < GraphQL::Configuration::Base
|
6
|
+
slot :name, String, coerce: -> (v) { v.to_s }
|
7
|
+
slot :args, [-> { GraphQLArgument }], singular: :arg
|
8
|
+
slot :description, String, null: true
|
9
|
+
slot :on_operation, Object, coerce: -> (v) { !!v }
|
10
|
+
slot :on_fragment, Object, coerce: -> (v) { !!v }
|
11
|
+
slot :on_field, Object, coerce: -> (v) { !!v }
|
12
|
+
end
|
13
|
+
|
14
|
+
class GraphQLDirective < GraphQL::Configuration::Configurable
|
15
|
+
configure_with GraphQLDirectiveConfiguration
|
16
|
+
|
17
|
+
def arg_map
|
18
|
+
@arg_map ||= @configuration.args.reduce({}) { |memo, arg| memo[arg.name.to_sym] = arg ; memo }
|
19
|
+
end
|
20
|
+
|
21
|
+
def arg_names
|
22
|
+
@arg_names ||= arg_map.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
def args
|
26
|
+
@args ||= arg_map.values
|
27
|
+
end
|
28
|
+
|
29
|
+
def arg(name)
|
30
|
+
arg_map(name.to_sym)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
require_relative 'directives'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
GraphQLIncludeDirective = GraphQLDirective.new do
|
4
|
+
name :include
|
5
|
+
description 'Directs the executor to include this field or fragment only when the `if` argument is true.'
|
6
|
+
|
7
|
+
arg :if, ! GraphQLBoolean, description: 'Included when true'
|
8
|
+
|
9
|
+
on_operation false
|
10
|
+
on_fragment true
|
11
|
+
on_field true
|
12
|
+
end
|
13
|
+
|
14
|
+
GraphQLSkipDirective = GraphQLDirective.new do
|
15
|
+
name :skip
|
16
|
+
description 'Directs the executor to skip this field or fragment only when the `if` argument is true.'
|
17
|
+
|
18
|
+
arg :if, ! GraphQLBoolean, description: 'Skipped when true'
|
19
|
+
|
20
|
+
on_operation false
|
21
|
+
on_fragment true
|
22
|
+
on_field true
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
#
|
4
|
+
# == GraphQLEnumType Definition
|
5
|
+
#
|
6
|
+
# Some leaf values of requests and input values are Enums. GraphQL serializes
|
7
|
+
# Enum values as strings, however internally Enums can be represented by any
|
8
|
+
# kind of type, often integers.
|
9
|
+
#
|
10
|
+
# Examples:
|
11
|
+
#
|
12
|
+
# RGBAType = GraphQLEnum.new do
|
13
|
+
# name 'RGBA'
|
14
|
+
#
|
15
|
+
# value :RED, 0
|
16
|
+
# value :GREEN, 1
|
17
|
+
# value :BLUE, 2
|
18
|
+
# value :ALPHA, description: 'Alpha channel'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Note: If a value is not provided in a definition, the name of the enum value
|
22
|
+
# will be used as it's internal value.
|
23
|
+
#
|
24
|
+
|
25
|
+
|
26
|
+
# GraphQLEnumValueConfiguration
|
27
|
+
#
|
28
|
+
class GraphQLEnumValue < GraphQL::Configuration::Base
|
29
|
+
slot :name, String, coerce: -> (v) { v.to_s }
|
30
|
+
slot :value, Object, null: true
|
31
|
+
slot :description, String, null: true
|
32
|
+
slot :deprecation_reason, String, null: true
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# GraphQLEnumTypeConfiguration
|
37
|
+
#
|
38
|
+
class GraphQLEnumTypeConfiguration < GraphQL::Configuration::Base
|
39
|
+
slot :name, String
|
40
|
+
slot :values, [GraphQLEnumValue], singular: :value
|
41
|
+
slot :description, String, null: true
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# GraphQLEnumType
|
46
|
+
#
|
47
|
+
class GraphQLEnumType < GraphQL::Configuration::Configurable
|
48
|
+
|
49
|
+
include GraphQLType
|
50
|
+
include GraphQLInputType
|
51
|
+
include GraphQLOutputType
|
52
|
+
include GraphQLLeafType
|
53
|
+
include GraphQLNullableType
|
54
|
+
include GraphQLNamedType
|
55
|
+
|
56
|
+
configure_with GraphQLEnumTypeConfiguration
|
57
|
+
|
58
|
+
|
59
|
+
def value_map
|
60
|
+
@value_map ||= @configuration.values.reduce({}) do |memo, value|
|
61
|
+
value.value = value.name if value.value.nil?
|
62
|
+
memo[value.name.to_sym] = value
|
63
|
+
memo
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def value_map_by_values
|
68
|
+
@value_map_by_values ||= values.reduce({}) { |memo, value| memo[value.value.to_s] = value ; memo }
|
69
|
+
end
|
70
|
+
|
71
|
+
def value_names
|
72
|
+
@value_names ||= value_map.keys
|
73
|
+
end
|
74
|
+
|
75
|
+
def values
|
76
|
+
@values ||= value_map.values
|
77
|
+
end
|
78
|
+
|
79
|
+
def value(name)
|
80
|
+
value_map[name.to_sym]
|
81
|
+
end
|
82
|
+
|
83
|
+
def serialize(v)
|
84
|
+
value_map_by_values[v.to_s].name rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_value(v)
|
88
|
+
value(v).value rescue nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse_literal(ast)
|
92
|
+
value(ast[:value]).value rescue nil if ast[:kind] == :enum
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
name
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
# GraphQLFieldConfiguration
|
4
|
+
#
|
5
|
+
class GraphQLFieldConfiguration < GraphQL::Configuration::Base
|
6
|
+
slot :name, String, coerce: -> (v) { v.to_s }
|
7
|
+
slot :type, -> { GraphQLOutputType }
|
8
|
+
slot :args, [ -> { GraphQLArgument } ], singular: :arg
|
9
|
+
slot :resolve, Proc
|
10
|
+
slot :deprecation_reason, String, null: true
|
11
|
+
slot :description, String, null: true
|
12
|
+
end
|
13
|
+
|
14
|
+
# GraphQLField
|
15
|
+
#
|
16
|
+
class GraphQLField < GraphQL::Configuration::Configurable
|
17
|
+
configure_with GraphQLFieldConfiguration
|
18
|
+
|
19
|
+
DEFAULT_RESOLVE = lambda { |name|
|
20
|
+
lambda { |object|
|
21
|
+
object.public_send(name)
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
def type
|
26
|
+
@type ||= @configuration.type.is_a?(Proc) ? @configuration.type.call : @configuration.type
|
27
|
+
end
|
28
|
+
|
29
|
+
def arg_map
|
30
|
+
@arg_map ||= @configuration.args.reduce({}) { |memo, arg| memo[arg.name.to_sym] = arg ; memo }
|
31
|
+
end
|
32
|
+
|
33
|
+
def arg_names
|
34
|
+
@arg_names ||= arg_map.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def args
|
38
|
+
@args ||= arg_map.values
|
39
|
+
end
|
40
|
+
|
41
|
+
def arg(name)
|
42
|
+
arg_map(name.to_sym)
|
43
|
+
end
|
44
|
+
|
45
|
+
def resolve
|
46
|
+
@resolve ||= @configuration.resolve || DEFAULT_RESOLVE.call(name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
class GraphQLInputObjectField < GraphQL::Configuration::Base
|
4
|
+
slot :name, String
|
5
|
+
slot :type, GraphQLInputType
|
6
|
+
slot :default_value, Object, null: true
|
7
|
+
slot :description, String, null: true
|
8
|
+
end
|
9
|
+
|
10
|
+
class GraphQLInputObjectTypeConfiguration < GraphQL::Configuration::Base
|
11
|
+
slot :name, String
|
12
|
+
slot :fields, [GraphQLInputObjectField], singular: :field
|
13
|
+
slot :description, String, null: true
|
14
|
+
end
|
15
|
+
|
16
|
+
class GraphQLInputObjectType < GraphQL::Configuration::Configurable
|
17
|
+
|
18
|
+
include GraphQLType
|
19
|
+
include GraphQLInputType
|
20
|
+
include GraphQLNullableType
|
21
|
+
include GraphQLNamedType
|
22
|
+
|
23
|
+
configure_with GraphQLInputObjectTypeConfiguration
|
24
|
+
|
25
|
+
|
26
|
+
def field_map
|
27
|
+
@field_map ||= @configuration.fields.reduce({}) { |memo, field| memo[field.name.to_sym] = field ; memo }
|
28
|
+
end
|
29
|
+
|
30
|
+
def field_names
|
31
|
+
@field_names ||= field_map.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def fields
|
35
|
+
@fields ||= field_map.values
|
36
|
+
end
|
37
|
+
|
38
|
+
def field(name)
|
39
|
+
field_map[name.to_sym]
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
class GraphQLInterfaceTypeConfiguration < GraphQL::Configuration::Base
|
4
|
+
slot :name, String
|
5
|
+
slot :fields, [-> { GraphQLField }], singular: :field
|
6
|
+
slot :resolve_type, Proc, null: true
|
7
|
+
slot :description, String, null: true
|
8
|
+
end
|
9
|
+
|
10
|
+
class GraphQLInterfaceType < GraphQL::Configuration::Configurable
|
11
|
+
|
12
|
+
include GraphQLType
|
13
|
+
include GraphQLOutputType
|
14
|
+
include GraphQLCompositeType
|
15
|
+
include GraphQLAbstractType
|
16
|
+
include GraphQLNullableType
|
17
|
+
include GraphQLNamedType
|
18
|
+
|
19
|
+
configure_with GraphQLInterfaceTypeConfiguration
|
20
|
+
|
21
|
+
def initialize(configuration)
|
22
|
+
super
|
23
|
+
@implementations = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def implement!(type)
|
27
|
+
raise RuntimeError.new("#{self} can implement instances of GraphQLType. Got #{type.class}.") unless type.is_a?(GraphQLType)
|
28
|
+
@implementations << type unless possible_type?(type)
|
29
|
+
end
|
30
|
+
|
31
|
+
def field_map
|
32
|
+
@field_map ||= @configuration.fields.reduce({}) { |memo, field| memo[field.name.to_sym] = field ; memo}
|
33
|
+
end
|
34
|
+
|
35
|
+
def field_names
|
36
|
+
@field_names ||= field_map.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
def fields
|
40
|
+
@fields ||= field_map.values
|
41
|
+
end
|
42
|
+
|
43
|
+
def field(name)
|
44
|
+
field_map(name.to_sym)
|
45
|
+
end
|
46
|
+
|
47
|
+
def possible_types
|
48
|
+
@implementations
|
49
|
+
end
|
50
|
+
|
51
|
+
def possible_type?(type)
|
52
|
+
possible_types.include?(type)
|
53
|
+
end
|
54
|
+
|
55
|
+
def resolve_type(type)
|
56
|
+
@configuration.resolve_type.nil? ? type_of(type) : @configuration.resolve_type.call(type)
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
class GraphQLList
|
4
|
+
|
5
|
+
include GraphQLType
|
6
|
+
include GraphQLInputType
|
7
|
+
include GraphQLOutputType
|
8
|
+
include GraphQLNullableType
|
9
|
+
|
10
|
+
attr_reader :of_type
|
11
|
+
|
12
|
+
def initialize(of_type)
|
13
|
+
raise "Expecting #{GraphQLType}, got #{of_type.class}." unless of_type.is_a?(GraphQLType)
|
14
|
+
@of_type = of_type
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
'[' + of_type.to_s + ']'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
class GraphQLNonNull
|
4
|
+
|
5
|
+
include GraphQLType
|
6
|
+
include GraphQLInputType
|
7
|
+
include GraphQLOutputType
|
8
|
+
|
9
|
+
NESTING_ERROR = 'Cannot nest NonNull inside NonNull'
|
10
|
+
|
11
|
+
attr_reader :of_type
|
12
|
+
|
13
|
+
def initialize(of_type)
|
14
|
+
raise "Expecting #{GraphQLType}, got #{of_type.class}." unless of_type.is_a?(GraphQLType)
|
15
|
+
raise NESTING_ERROR if of_type.is_a?(GraphQLNonNull)
|
16
|
+
@of_type = of_type
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
of_type.to_s + '!'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GraphQL
|
2
|
+
|
3
|
+
class GraphQLObjectTypeConfiguration < GraphQL::Configuration::Base
|
4
|
+
slot :name, String
|
5
|
+
slot :interfaces, [-> { GraphQLInterfaceType }], null: true, singular: :interface
|
6
|
+
slot :fields, [-> { GraphQLField }], singular: :field
|
7
|
+
slot :type_of?, Proc, null: true
|
8
|
+
slot :description, String, null: true
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
class GraphQLObjectType < GraphQL::Configuration::Configurable
|
13
|
+
|
14
|
+
include GraphQLType
|
15
|
+
include GraphQLOutputType
|
16
|
+
include GraphQLCompositeType
|
17
|
+
include GraphQLNullableType
|
18
|
+
include GraphQLNamedType
|
19
|
+
|
20
|
+
configure_with GraphQLObjectTypeConfiguration
|
21
|
+
|
22
|
+
def initialize(configuration)
|
23
|
+
super
|
24
|
+
interfaces.each { |interface| interface.implement!(self) }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def field_map
|
29
|
+
@field_map ||= @configuration.fields.reduce({}) { |memo, field| memo[field.name.to_sym] = field ; memo}
|
30
|
+
end
|
31
|
+
|
32
|
+
def field_names
|
33
|
+
@field_names ||= field_map.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def fields
|
37
|
+
@fields ||= field_map.values
|
38
|
+
end
|
39
|
+
|
40
|
+
def field(name)
|
41
|
+
field_map[name.to_sym]
|
42
|
+
end
|
43
|
+
|
44
|
+
def interfaces
|
45
|
+
@configuration.interfaces
|
46
|
+
end
|
47
|
+
|
48
|
+
def type_of?(type)
|
49
|
+
@configuration.type_of?.nil? ? false : @configuration.type_of?.call(type)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|