graphql 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graph_ql/directive.rb +36 -0
- data/lib/graph_ql/directives/directive_chain.rb +33 -0
- data/lib/graph_ql/directives/include_directive.rb +15 -0
- data/lib/graph_ql/directives/skip_directive.rb +15 -0
- data/lib/graph_ql/enum.rb +34 -0
- data/lib/graph_ql/fields/abstract_field.rb +37 -0
- data/lib/graph_ql/fields/access_field.rb +24 -0
- data/lib/graph_ql/fields/field.rb +34 -0
- data/lib/graph_ql/interface.rb +14 -0
- data/lib/graph_ql/introspection/arguments_field.rb +5 -0
- data/lib/graph_ql/introspection/directive_type.rb +12 -0
- data/lib/graph_ql/introspection/enum_value_type.rb +10 -0
- data/lib/graph_ql/introspection/enum_values_field.rb +15 -0
- data/lib/graph_ql/introspection/field_type.rb +11 -0
- data/lib/graph_ql/introspection/fields_field.rb +14 -0
- data/lib/graph_ql/introspection/input_fields_field.rb +12 -0
- data/lib/graph_ql/introspection/input_value_type.rb +10 -0
- data/lib/graph_ql/introspection/of_type_field.rb +12 -0
- data/lib/graph_ql/introspection/possible_types_field.rb +12 -0
- data/lib/graph_ql/introspection/schema_type.rb +32 -0
- data/lib/graph_ql/introspection/type_kind_enum.rb +7 -0
- data/lib/graph_ql/introspection/type_type.rb +22 -0
- data/lib/graph_ql/parser/nodes.rb +72 -0
- data/lib/graph_ql/parser/parser.rb +108 -0
- data/lib/graph_ql/parser/transform.rb +86 -0
- data/lib/graph_ql/parser/visitor.rb +47 -0
- data/lib/graph_ql/query.rb +50 -0
- data/lib/graph_ql/query/arguments.rb +25 -0
- data/lib/graph_ql/query/field_resolution_strategy.rb +83 -0
- data/lib/graph_ql/query/fragment_spread_resolution_strategy.rb +16 -0
- data/lib/graph_ql/query/inline_fragment_resolution_strategy.rb +14 -0
- data/lib/graph_ql/query/operation_resolver.rb +28 -0
- data/lib/graph_ql/query/selection_resolver.rb +20 -0
- data/lib/graph_ql/query/type_resolver.rb +19 -0
- data/lib/graph_ql/repl.rb +27 -0
- data/lib/graph_ql/schema.rb +30 -0
- data/lib/graph_ql/schema/type_reducer.rb +44 -0
- data/lib/graph_ql/type_kinds.rb +15 -0
- data/lib/graph_ql/types/abstract_type.rb +14 -0
- data/lib/graph_ql/types/boolean_type.rb +6 -0
- data/lib/graph_ql/types/float_type.rb +6 -0
- data/lib/graph_ql/types/input_object_type.rb +17 -0
- data/lib/graph_ql/types/input_value.rb +10 -0
- data/lib/graph_ql/types/int_type.rb +6 -0
- data/lib/graph_ql/types/list_type.rb +10 -0
- data/lib/graph_ql/types/non_null_type.rb +18 -0
- data/lib/graph_ql/types/non_null_with_bang.rb +5 -0
- data/lib/graph_ql/types/object_type.rb +62 -0
- data/lib/graph_ql/types/scalar_type.rb +5 -0
- data/lib/graph_ql/types/string_type.rb +6 -0
- data/lib/graph_ql/types/type_definer.rb +16 -0
- data/lib/graph_ql/union.rb +35 -0
- data/lib/graph_ql/validations/fields_are_defined_on_type.rb +44 -0
- data/lib/graph_ql/validations/fields_will_merge.rb +80 -0
- data/lib/graph_ql/validations/fragments_are_used.rb +24 -0
- data/lib/graph_ql/validator.rb +29 -0
- data/lib/graph_ql/version.rb +3 -0
- data/lib/graphql.rb +92 -99
- data/readme.md +17 -177
- data/spec/graph_ql/directive_spec.rb +81 -0
- data/spec/graph_ql/enum_spec.rb +5 -0
- data/spec/graph_ql/fields/field_spec.rb +10 -0
- data/spec/graph_ql/interface_spec.rb +13 -0
- data/spec/graph_ql/introspection/directive_type_spec.rb +40 -0
- data/spec/graph_ql/introspection/schema_type_spec.rb +39 -0
- data/spec/graph_ql/introspection/type_type_spec.rb +104 -0
- data/spec/graph_ql/parser/parser_spec.rb +120 -0
- data/spec/graph_ql/parser/transform_spec.rb +109 -0
- data/spec/graph_ql/parser/visitor_spec.rb +31 -0
- data/spec/graph_ql/query/operation_resolver_spec.rb +14 -0
- data/spec/graph_ql/query_spec.rb +82 -0
- data/spec/graph_ql/schema/type_reducer_spec.rb +24 -0
- data/spec/graph_ql/types/input_object_type_spec.rb +12 -0
- data/spec/graph_ql/types/object_type_spec.rb +35 -0
- data/spec/graph_ql/union_spec.rb +27 -0
- data/spec/graph_ql/validations/fields_are_defined_on_type_spec.rb +28 -0
- data/spec/graph_ql/validations/fields_will_merge_spec.rb +40 -0
- data/spec/graph_ql/validations/fragments_are_used_spec.rb +28 -0
- data/spec/graph_ql/validator_spec.rb +24 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/support/dummy_app.rb +123 -63
- data/spec/support/dummy_data.rb +11 -0
- metadata +107 -59
- data/lib/graphql/call.rb +0 -8
- data/lib/graphql/connection.rb +0 -65
- data/lib/graphql/field.rb +0 -12
- data/lib/graphql/field_definer.rb +0 -25
- data/lib/graphql/introspection/call_type.rb +0 -13
- data/lib/graphql/introspection/connection.rb +0 -9
- data/lib/graphql/introspection/field_type.rb +0 -10
- data/lib/graphql/introspection/root_call_argument_node.rb +0 -5
- data/lib/graphql/introspection/root_call_type.rb +0 -20
- data/lib/graphql/introspection/schema_call.rb +0 -8
- data/lib/graphql/introspection/schema_type.rb +0 -17
- data/lib/graphql/introspection/type_call.rb +0 -8
- data/lib/graphql/introspection/type_type.rb +0 -18
- data/lib/graphql/node.rb +0 -244
- data/lib/graphql/parser/parser.rb +0 -39
- data/lib/graphql/parser/transform.rb +0 -22
- data/lib/graphql/query.rb +0 -109
- data/lib/graphql/root_call.rb +0 -202
- data/lib/graphql/root_call_argument.rb +0 -11
- data/lib/graphql/root_call_argument_definer.rb +0 -17
- data/lib/graphql/schema/all.rb +0 -46
- data/lib/graphql/schema/schema.rb +0 -87
- data/lib/graphql/schema/schema_validation.rb +0 -32
- data/lib/graphql/syntax/call.rb +0 -8
- data/lib/graphql/syntax/field.rb +0 -9
- data/lib/graphql/syntax/fragment.rb +0 -7
- data/lib/graphql/syntax/node.rb +0 -8
- data/lib/graphql/syntax/query.rb +0 -8
- data/lib/graphql/syntax/variable.rb +0 -7
- data/lib/graphql/types/boolean_type.rb +0 -3
- data/lib/graphql/types/number_type.rb +0 -3
- data/lib/graphql/types/object_type.rb +0 -6
- data/lib/graphql/types/string_type.rb +0 -3
- data/lib/graphql/version.rb +0 -3
- data/spec/graphql/node_spec.rb +0 -69
- data/spec/graphql/parser/parser_spec.rb +0 -168
- data/spec/graphql/parser/transform_spec.rb +0 -157
- data/spec/graphql/query_spec.rb +0 -274
- data/spec/graphql/root_call_spec.rb +0 -69
- data/spec/graphql/schema/schema_spec.rb +0 -93
- data/spec/graphql/schema/schema_validation_spec.rb +0 -48
- data/spec/support/nodes.rb +0 -175
@@ -0,0 +1,16 @@
|
|
1
|
+
class GraphQL::Query::FragmentSpreadResolutionStrategy
|
2
|
+
attr_reader :result
|
3
|
+
def initialize(ast_fragment_spread, type, target, operation_resolver)
|
4
|
+
fragments = operation_resolver.query.fragments
|
5
|
+
fragment_def = fragments[ast_fragment_spread.name]
|
6
|
+
child_type = operation_resolver.query.schema.types[fragment_def.type]
|
7
|
+
resolved_type = GraphQL::Query::TypeResolver.new(target, child_type, type).type
|
8
|
+
if resolved_type.nil?
|
9
|
+
@result = {}
|
10
|
+
else
|
11
|
+
selections = fragment_def.selections
|
12
|
+
resolver = GraphQL::Query::SelectionResolver.new(target, resolved_type, selections, operation_resolver)
|
13
|
+
@result = resolver.result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class GraphQL::Query::InlineFragmentResolutionStrategy
|
2
|
+
attr_reader :result
|
3
|
+
def initialize(ast_inline_fragment, type, target, operation_resolver)
|
4
|
+
child_type = operation_resolver.query.schema.types[ast_inline_fragment.type]
|
5
|
+
resolved_type = GraphQL::Query::TypeResolver.new(target, child_type, type).type
|
6
|
+
if resolved_type.nil?
|
7
|
+
@result = {}
|
8
|
+
else
|
9
|
+
selections = ast_inline_fragment.selections
|
10
|
+
resolver = GraphQL::Query::SelectionResolver.new(target, resolved_type, selections, operation_resolver)
|
11
|
+
@result = resolver.result
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class GraphQL::Query::OperationResolver
|
2
|
+
extend GraphQL::Forwardable
|
3
|
+
attr_reader :variables, :query
|
4
|
+
|
5
|
+
def initialize(operation_definition, query)
|
6
|
+
@operation_definition = operation_definition
|
7
|
+
@variables = query.params
|
8
|
+
@query = query
|
9
|
+
end
|
10
|
+
|
11
|
+
delegate :context, to: :query
|
12
|
+
|
13
|
+
def result
|
14
|
+
@result ||= execute(@operation_definition, query)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def execute(op_def, query)
|
20
|
+
root = if op_def.operation_type == "query"
|
21
|
+
query.schema.query
|
22
|
+
elsif op_def.operation_type == "mutation"
|
23
|
+
query.schema.mutation
|
24
|
+
end
|
25
|
+
resolver = GraphQL::Query::SelectionResolver.new(nil, root, op_def.selections, self)
|
26
|
+
resolver.result
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class GraphQL::Query::SelectionResolver
|
2
|
+
attr_reader :result
|
3
|
+
|
4
|
+
RESOLUTION_STRATEGIES = {
|
5
|
+
GraphQL::Nodes::Field => GraphQL::Query::FieldResolutionStrategy,
|
6
|
+
GraphQL::Nodes::FragmentSpread => GraphQL::Query::FragmentSpreadResolutionStrategy,
|
7
|
+
GraphQL::Nodes::InlineFragment => GraphQL::Query::InlineFragmentResolutionStrategy,
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(target, type, selections, operation_resolver)
|
11
|
+
@result = selections.reduce({}) do |memo, ast_field|
|
12
|
+
chain = GraphQL::DirectiveChain.new(ast_field, operation_resolver) {
|
13
|
+
strategy_class = RESOLUTION_STRATEGIES[ast_field.class]
|
14
|
+
strategy = strategy_class.new(ast_field, type, target, operation_resolver)
|
15
|
+
strategy.result
|
16
|
+
}
|
17
|
+
memo.merge(chain.result)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Given an object, a type name (from the query) and a type object,
|
2
|
+
# Return the type that should be used for `object`
|
3
|
+
# or Return `nil` if it's a mismatch
|
4
|
+
class GraphQL::Query::TypeResolver
|
5
|
+
attr_reader :type
|
6
|
+
def initialize(target, child_type, parent_type)
|
7
|
+
@type = if child_type.nil?
|
8
|
+
nil
|
9
|
+
elsif GraphQL::TypeKinds::UNION == parent_type.kind
|
10
|
+
parent_type.resolve_type(target)
|
11
|
+
elsif GraphQL::TypeKinds::INTERFACE == child_type.kind
|
12
|
+
child_type.resolve_type(target)
|
13
|
+
elsif child_type == parent_type
|
14
|
+
parent_type
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'pp'
|
2
|
+
class GraphQL::Repl
|
3
|
+
def initialize(schema)
|
4
|
+
@schema = schema
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
puts "Starting a repl for schema (type 'quit' to exit)"
|
9
|
+
while line = gets do
|
10
|
+
if line == "quit\n"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
execute_query(line)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def execute_query(query_string)
|
20
|
+
begin
|
21
|
+
query = GraphQL::Query.new(@schema, query_string)
|
22
|
+
puts JSON.pretty_generate(query.execute)
|
23
|
+
rescue StandardError => err
|
24
|
+
puts "Couldn't parse: #{err}\n\n" # #{err.backtrace.join("\n")}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class GraphQL::Schema
|
2
|
+
extend ActiveSupport::Autoload
|
3
|
+
autoload(:TypeReducer)
|
4
|
+
DIRECTIVES = [GraphQL::SkipDirective, GraphQL::IncludeDirective]
|
5
|
+
|
6
|
+
attr_reader :query, :mutation, :directives
|
7
|
+
def initialize(query:, mutation:)
|
8
|
+
# Add fields to this query root for introspection:
|
9
|
+
query.fields = query.fields.merge({
|
10
|
+
"__type" => GraphQL::Field.new do |f|
|
11
|
+
f.description("A type in the GraphQL system")
|
12
|
+
f.type(!GraphQL::TypeType)
|
13
|
+
f.resolve -> (o, a, c) { self.types[a["name"]] || raise("No type found in schema for '#{a["name"]}'") }
|
14
|
+
end,
|
15
|
+
"__schema" => GraphQL::Field.new do |f|
|
16
|
+
f.description("This GraphQL schema")
|
17
|
+
f.type(!GraphQL::SchemaType)
|
18
|
+
f.resolve -> (o, a, c) { self }
|
19
|
+
end
|
20
|
+
})
|
21
|
+
|
22
|
+
@query = query
|
23
|
+
@mutation = mutation
|
24
|
+
@directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
|
25
|
+
end
|
26
|
+
|
27
|
+
def types
|
28
|
+
@types ||= TypeReducer.new(query, {}).result
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class GraphQL::Schema::TypeReducer
|
2
|
+
FIELDS_TYPE_KINDS = [GraphQL::TypeKinds::OBJECT, GraphQL::TypeKinds::INTERFACE]
|
3
|
+
POSSIBLE_TYPES_TYPE_KINDS = [GraphQL::TypeKinds::INTERFACE, GraphQL::TypeKinds::UNION]
|
4
|
+
attr_reader :type, :result
|
5
|
+
def initialize(type, existing_type_hash)
|
6
|
+
if [GraphQL::TypeKinds::NON_NULL, GraphQL::TypeKinds::LIST].include?(type.kind)
|
7
|
+
@result = reduce_type(type.of_type, existing_type_hash)
|
8
|
+
elsif existing_type_hash.has_key?(type.name)
|
9
|
+
# been here, done that
|
10
|
+
@result = existing_type_hash
|
11
|
+
else
|
12
|
+
@result = find_types(type, existing_type_hash.dup)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def find_types(type, type_hash)
|
19
|
+
type_hash[type.name] = type
|
20
|
+
if FIELDS_TYPE_KINDS.include?(type.kind)
|
21
|
+
type.fields.each do |name, field|
|
22
|
+
type_hash.merge!(reduce_type(field.type, type_hash))
|
23
|
+
field.arguments.each do |name, argument|
|
24
|
+
type_hash.merge!(reduce_type(argument[:type], type_hash))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
if type.kind == GraphQL::TypeKinds::OBJECT
|
29
|
+
type.interfaces.each do |interface|
|
30
|
+
type_hash.merge!(reduce_type(interface, type_hash))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
if POSSIBLE_TYPES_TYPE_KINDS.include?(type.kind)
|
34
|
+
type.possible_types.each do |possible_type|
|
35
|
+
type_hash.merge!(reduce_type(possible_type, type_hash))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
type_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def reduce_type(type, type_hash)
|
42
|
+
self.class.new(type, type_hash).result
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Any object can be a type as long as it implements:
|
2
|
+
# - #fields: Hash of { String => Field } pairs
|
3
|
+
# - #kind: one of GraphQL::TypeKinds
|
4
|
+
# - #interfaces: Array of Interfaces
|
5
|
+
# - #name: String
|
6
|
+
# - #description: String
|
7
|
+
#
|
8
|
+
class GraphQL::AbstractType
|
9
|
+
def fields; raise NotImplementedError; end
|
10
|
+
def kind; raise NotImplementedError; end
|
11
|
+
def interfaces; raise NotImplementedError; end
|
12
|
+
def name; raise NotImplementedError; end
|
13
|
+
def description; raise NotImplementedError; end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class GraphQL::InputObjectType < GraphQL::ObjectType
|
2
|
+
attr_definable :input_fields
|
3
|
+
|
4
|
+
def input_fields(new_fields=nil)
|
5
|
+
if new_fields.nil?
|
6
|
+
@new_fields
|
7
|
+
else
|
8
|
+
@new_fields = new_fields
|
9
|
+
.reduce({}) {|memo, (k, v)| memo[k.to_s] = v; memo}
|
10
|
+
.each { |k, v| v.respond_to?("name=") && v.name = k}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def kind
|
15
|
+
GraphQL::TypeKinds::INPUT_OBJECT
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class GraphQL::InputValue
|
2
|
+
attr_reader :type, :description, :default_value
|
3
|
+
attr_accessor :name
|
4
|
+
def initialize(type:, description:, default_value:, name: nil)
|
5
|
+
@type = type
|
6
|
+
@description = description,
|
7
|
+
@default_value = default_value
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class GraphQL::NonNullType < GraphQL::ObjectType
|
2
|
+
attr_reader :of_type
|
3
|
+
def initialize(of_type:)
|
4
|
+
@of_type = of_type
|
5
|
+
end
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Non-Null"
|
9
|
+
end
|
10
|
+
|
11
|
+
def coerce(value)
|
12
|
+
of_type.coerce(value)
|
13
|
+
end
|
14
|
+
|
15
|
+
def kind
|
16
|
+
GraphQL::TypeKinds::NON_NULL
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class GraphQL::ObjectType
|
2
|
+
extend GraphQL::Definable
|
3
|
+
attr_definable :name, :description, :interfaces, :fields
|
4
|
+
include GraphQL::NonNullWithBang
|
5
|
+
|
6
|
+
def initialize(&block)
|
7
|
+
self.fields = []
|
8
|
+
self.interfaces = []
|
9
|
+
instance_eval(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fields(new_fields=nil)
|
13
|
+
if new_fields
|
14
|
+
self.fields = new_fields
|
15
|
+
else
|
16
|
+
@fields
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def fields=(new_fields)
|
21
|
+
stringified_fields = new_fields
|
22
|
+
.reduce({}) { |memo, (key, value)| memo[key.to_s] = value; memo }
|
23
|
+
# Set the name from its context on this type:
|
24
|
+
stringified_fields.each {|k, v| v.respond_to?("name=") && v.name = k }
|
25
|
+
stringified_fields["__typename"] = GraphQL::Field.new do |f|
|
26
|
+
f.name "__typename"
|
27
|
+
f.description "The name of this type"
|
28
|
+
f.type -> { !GraphQL::STRING_TYPE }
|
29
|
+
f.resolve -> (o, a, c) { self.name }
|
30
|
+
end
|
31
|
+
@fields = stringified_fields
|
32
|
+
end
|
33
|
+
|
34
|
+
def field(type:, args: {}, property: nil, desc: "", deprecation_reason: nil)
|
35
|
+
GraphQL::AccessField.new(type: type, arguments: args, property: property, description: desc, deprecation_reason: deprecation_reason)
|
36
|
+
end
|
37
|
+
|
38
|
+
def arg(type:, desc: "", default_value: nil)
|
39
|
+
GraphQL::InputValue.new(type: type, description: desc, default_value: default_value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def type
|
43
|
+
@type ||= GraphQL::TypeDefiner.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def interfaces(new_interfaces=nil)
|
47
|
+
if new_interfaces.nil?
|
48
|
+
@interfaces
|
49
|
+
else
|
50
|
+
@interfaces = new_interfaces
|
51
|
+
new_interfaces.each {|i| i.possible_types << self }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def kind
|
56
|
+
GraphQL::TypeKinds::OBJECT
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
name
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class GraphQL::TypeDefiner
|
2
|
+
TYPES = {
|
3
|
+
Int: GraphQL::INT_TYPE,
|
4
|
+
String: GraphQL::STRING_TYPE,
|
5
|
+
Float: GraphQL::FLOAT_TYPE,
|
6
|
+
Boolean: GraphQL::BOOLEAN_TYPE,
|
7
|
+
}
|
8
|
+
|
9
|
+
TYPES.each do |method_name, type|
|
10
|
+
define_method(method_name) { type }
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](type)
|
14
|
+
GraphQL::ListType.new(of_type: type)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class GraphQL::Union
|
2
|
+
include GraphQL::NonNullWithBang
|
3
|
+
attr_reader :name, :possible_types
|
4
|
+
def initialize(name, types)
|
5
|
+
if types.length < 2
|
6
|
+
raise ArgumentError, "Union #{name} must be defined with 2 or more types, not #{types.length}"
|
7
|
+
end
|
8
|
+
|
9
|
+
non_object_types = types.select {|t| t.kind != GraphQL::TypeKinds::OBJECT}
|
10
|
+
if non_object_types.any?
|
11
|
+
types_string = non_object_types.map{|t| "#{t.name} #{t.kind}"}.join(", ")
|
12
|
+
raise ArgumentError, "Unions can only consist of Object types, but #{name} has non-object types: #{types_string}"
|
13
|
+
end
|
14
|
+
|
15
|
+
@name = name
|
16
|
+
@possible_types = types
|
17
|
+
end
|
18
|
+
|
19
|
+
def kind; GraphQL::TypeKinds::UNION; end
|
20
|
+
|
21
|
+
def include?(type)
|
22
|
+
possible_types.include?(type)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Find a type in this union for a given object.
|
26
|
+
# Reimplement if needed
|
27
|
+
def resolve_type(object)
|
28
|
+
type_name = object.class.name
|
29
|
+
possible_types.find {|t| t.name == type_name}
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"<GraphQL::Union #{name} [#{possible_types.map(&:name).join(", ")}]>"
|
34
|
+
end
|
35
|
+
end
|