graphql 0.0.4 → 0.1.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/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
|