graphql-rb 0.0.2
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 +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
|