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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ea68c93a7c58f20140405e57455f817f587a89f7
|
4
|
+
data.tar.gz: 1c70ce478b3283ed412d7d27c0c373d039907579
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 226d8b3ec2ddfa287937c239caaaaa845a6e226fd821ac514d15de6ee0e12b40716286ef083b74f87f6302129abc2d0049fe1c5ab2cec231730ae296cb938060
|
7
|
+
data.tar.gz: 90420d7f666c395dfb827f27d24b6ead1ac7f8faaa5b342940b046cf9124485df6a8aac1f903ab22d307bec5cb48db01c0707c871d26c88c2e91638e508bf65b
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'GraphQL'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
14
|
+
end
|
15
|
+
|
16
|
+
Bundler::GemHelper.install_tasks
|
17
|
+
|
18
|
+
require 'rspec'
|
19
|
+
require 'rspec/core/rake_task'
|
20
|
+
|
21
|
+
RSpec::Core::RakeTask.new(:test) do |test|
|
22
|
+
test.verbose = false
|
23
|
+
test.rspec_opts = %w[--color --format documentation]
|
24
|
+
end
|
25
|
+
|
26
|
+
task default: :test
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'configuration'
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Configuration
|
5
|
+
|
6
|
+
class Configurable
|
7
|
+
|
8
|
+
|
9
|
+
def initialize(configuration)
|
10
|
+
@configuration = configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def method_missing(name, *args, &block)
|
15
|
+
if @configuration.respond_to?(name)
|
16
|
+
@configuration.send(name, *args, &block)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def self.new(*args, &block)
|
24
|
+
if args.size == 1 && !block_given? && args.first.is_a?(Base)
|
25
|
+
super args.first
|
26
|
+
else
|
27
|
+
configuration = self.configuration.new(*args, &block)
|
28
|
+
super(configuration)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def self.configuration
|
34
|
+
@configuration
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def self.configure_with(configuration)
|
39
|
+
raise RuntimeError.new("Configuration should be descendant of #{Slots}.") unless configuration < Base
|
40
|
+
@configuration = configuration
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative 'slot'
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Configuration
|
5
|
+
|
6
|
+
class Base
|
7
|
+
|
8
|
+
def initialize(*args, &block)
|
9
|
+
options = args.last.instance_of?(Hash) ? args.pop : {}
|
10
|
+
slots.each { |key, slot| options[(slot.singular || slot.name).to_sym] = args.shift if args.size > 0 }
|
11
|
+
options.each { |key, value| public_send(key, value) }
|
12
|
+
instance_eval(&block) if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def slots
|
16
|
+
self.class.slots
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def inherited(base)
|
21
|
+
base.instance_variable_set(:"@slots", @slots)
|
22
|
+
end
|
23
|
+
|
24
|
+
def slots
|
25
|
+
@slots ||= {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def slot(*args, &block)
|
29
|
+
slot = Slot.new(*args, &block)
|
30
|
+
define_accessors(slot)
|
31
|
+
slots[slot.name] = slot
|
32
|
+
end
|
33
|
+
|
34
|
+
def coerce(slot, *args, &block)
|
35
|
+
if args.size == 1 && !block_given?
|
36
|
+
value = args.first
|
37
|
+
return value if value.is_a?(slot.effective_type)
|
38
|
+
value = slot.coerce.nil? ? value : slot.coerce.call(value)
|
39
|
+
return value if value.is_a?(slot.effective_type)
|
40
|
+
return value if value.is_a?(Proc)
|
41
|
+
end
|
42
|
+
slot.effective_type.new(*args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def define_accessors(slot)
|
48
|
+
instance_variable_name = :"@#{slot.name}"
|
49
|
+
reader_name = :"#{slot.name}"
|
50
|
+
writer_name = :"#{slot.name}="
|
51
|
+
|
52
|
+
if slot.list?
|
53
|
+
list_instance_variable_name = instance_variable_name
|
54
|
+
list_reader_name = reader_name
|
55
|
+
instance_variable_name = :"@#{slot.singular}"
|
56
|
+
reader_name = :"#{slot.singular}"
|
57
|
+
writer_name = :"#{slot.singular}="
|
58
|
+
|
59
|
+
define_method(list_reader_name) do |items = []|
|
60
|
+
instance_variable_set(list_instance_variable_name, []) if instance_variable_get(list_instance_variable_name).nil?
|
61
|
+
items.each do |item|
|
62
|
+
public_send(reader_name, item)
|
63
|
+
end
|
64
|
+
instance_variable_get(list_instance_variable_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
define_method(writer_name) do |*args, &block|
|
70
|
+
if args.size > 0 || block_given?
|
71
|
+
value = self.class.coerce(slot, *args, &block)
|
72
|
+
|
73
|
+
raise RuntimeError.new "Cannot coerce." unless value.is_a?(slot.effective_type) || value.is_a?(Proc)
|
74
|
+
|
75
|
+
if slot.list?
|
76
|
+
public_send(:"#{slot.name}") << value
|
77
|
+
else
|
78
|
+
instance_variable_set(instance_variable_name, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
slot.list? ? nil : instance_variable_get(instance_variable_name)
|
82
|
+
end
|
83
|
+
|
84
|
+
alias_method reader_name, writer_name
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Configuration
|
3
|
+
|
4
|
+
class Slot
|
5
|
+
|
6
|
+
def initialize(*args, &block)
|
7
|
+
define_methods
|
8
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
9
|
+
options.keys.each { |key| options[key.to_sym] = options.delete(key) }
|
10
|
+
attributes.each { |name| options[name.to_sym] = args.shift if args.size > 0 }
|
11
|
+
options.each { |key, value| public_send(key, value) }
|
12
|
+
instance_eval(&block) if block_given?
|
13
|
+
validate!
|
14
|
+
end
|
15
|
+
|
16
|
+
def list?
|
17
|
+
type.is_a?(Array)
|
18
|
+
end
|
19
|
+
|
20
|
+
def effective_type
|
21
|
+
@effective_type ||= begin
|
22
|
+
t = list? ? type.first : type
|
23
|
+
t = t.call if t.is_a?(Proc)
|
24
|
+
t
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def errors
|
29
|
+
@errors ||= {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?
|
33
|
+
errors.size == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate
|
37
|
+
@errors = {}
|
38
|
+
attributes.each { |name| send(:"validate_#{name}") }
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def add_error(name, value)
|
44
|
+
(errors[name.to_sym] ||= []) << value
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate!
|
48
|
+
validate
|
49
|
+
raise StandardError.new("#{self.class.name} validation error: #{errors.keys} #{errors.inspect}") unless valid?
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_name
|
53
|
+
add_error(:name, "missing") if @name.nil?
|
54
|
+
add_error(:name, "should be a String or Symbold, got #{name}") unless @name.is_a?(String) or @name.is_a?(Symbol)
|
55
|
+
add_error(:name, "cannot be empty") if @name.is_a?(String) && name.size == 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_type
|
59
|
+
add_error(:type, "missing") if @type.nil?
|
60
|
+
|
61
|
+
if type.instance_of?(Array)
|
62
|
+
add_type_error unless @type.size == 1
|
63
|
+
add_type_error unless type_valid?(@type.first)
|
64
|
+
else
|
65
|
+
add_type_error unless type_valid?(@type)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def type_valid?(type)
|
70
|
+
type.is_a?(Class) || type.is_a?(Module) || type.is_a?(Proc)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_type_error
|
74
|
+
add_error(:type, "should be a Class, Module or Array of one Class or Module, got #{@type}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_coerce
|
78
|
+
return if @coerce.nil?
|
79
|
+
add_error(:coerce, "should be a Proc, got #{@coerce}") unless @coerce.is_a?(Proc)
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate_description
|
83
|
+
return if @description.nil?
|
84
|
+
add_error(:description, "should be a String, got #{@description}") unless @description.is_a?(String)
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate_null
|
88
|
+
return if @null.nil?
|
89
|
+
add_error(:null, "should be true or false, got #{@null}") unless !!@null == @null
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_singular
|
93
|
+
@singular = :"#{@name}_item" if list? && @singular.nil?
|
94
|
+
return if @singular.nil?
|
95
|
+
add_error(:singular, "should be a String or Symbold, got #{@singular}") unless @singular.is_a?(String) or @singular.is_a?(Symbol)
|
96
|
+
end
|
97
|
+
|
98
|
+
def define_methods
|
99
|
+
attributes.each do |key|
|
100
|
+
instance_variable_name = :"@#{key}"
|
101
|
+
|
102
|
+
define_singleton_method(:"#{key}") do |*args|
|
103
|
+
if args.size == 1
|
104
|
+
public_send(:"#{key}=", args.first)
|
105
|
+
else
|
106
|
+
instance_variable_get(instance_variable_name)
|
107
|
+
end
|
108
|
+
end unless methods.include?(:"#{key}")
|
109
|
+
|
110
|
+
define_singleton_method(:"#{key}=") do |value|
|
111
|
+
instance_variable_set(instance_variable_name, value)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def attributes
|
118
|
+
@attributes ||= [:name, :type, :coerce, :description, :null, :singular]
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'errors/error'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'celluloid/current'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
class Executor
|
6
|
+
|
7
|
+
class FutureCompleter
|
8
|
+
include Celluloid
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def self.complete_value(context, field_type, resolved_object, selection_set)
|
12
|
+
completer = resolved_object.is_a?(Celluloid::Future) ? instance.future : instance
|
13
|
+
completer.complete_value(context, field_type, resolved_object, selection_set)
|
14
|
+
end
|
15
|
+
|
16
|
+
def complete_value(context, field_type, resolved_object, selection_set)
|
17
|
+
return nil if resolved_object.nil?
|
18
|
+
|
19
|
+
resolved_object = resolved_object.value if resolved_object.is_a?(Celluloid::Future)
|
20
|
+
|
21
|
+
case field_type
|
22
|
+
when GraphQLNonNull
|
23
|
+
completed_object = complete_value(context, field_type.of_type, resolved_object, selection_set)
|
24
|
+
raise "Field error: expecting non null value" if completed_object.nil?
|
25
|
+
completed_object
|
26
|
+
when GraphQLList
|
27
|
+
resolved_object.map do |item|
|
28
|
+
complete_value(context, field_type.of_type, item, selection_set)
|
29
|
+
end
|
30
|
+
when GraphQLScalarType, GraphQLEnumType
|
31
|
+
field_type.serialize(resolved_object)
|
32
|
+
when GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType
|
33
|
+
field_type = field_type.resolve_type(resolved_object) if field_type.is_a?(GraphQLAbstractType)
|
34
|
+
selection_set.evaluate(context, field_type, resolved_object)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :document, :schema, :context
|
41
|
+
|
42
|
+
def initialize(document, schema)
|
43
|
+
@document = document
|
44
|
+
@schema = schema
|
45
|
+
@context = {
|
46
|
+
document: document,
|
47
|
+
schema: schema
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def execute(root = {}, params = {}, operation_name = nil)
|
52
|
+
raise GraphQLError, "At least one operation should be defined." if document.operations.size == 0
|
53
|
+
raise GraphQLError, "Operation name should be defined for more than one operation." if document.operations.size > 1 && operation_name.nil?
|
54
|
+
|
55
|
+
operation_name = document.operations.first.name if operation_name.nil?
|
56
|
+
operation = document.operation(operation_name)
|
57
|
+
|
58
|
+
raise GraphQLError, "Operation named '#{operation_name}' not found in document." if operation.nil?
|
59
|
+
|
60
|
+
context[:root] = root
|
61
|
+
context[:params] = params
|
62
|
+
|
63
|
+
materialize(operation.evaluate(context))
|
64
|
+
end
|
65
|
+
|
66
|
+
def materialize(data)
|
67
|
+
case data
|
68
|
+
when Hash
|
69
|
+
data.each do |key, value|
|
70
|
+
data[key] = value.value if value.is_a?(Celluloid::Future)
|
71
|
+
materialize(data[key])
|
72
|
+
end
|
73
|
+
when Array
|
74
|
+
data.each_with_index do |value, i|
|
75
|
+
data[i] = value.value if value.is_a?(Celluloid::Future)
|
76
|
+
materialize(data[i])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
data
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Introspection
|
3
|
+
|
4
|
+
SchemaMetaField = GraphQLField.new do
|
5
|
+
name '__schema'
|
6
|
+
type ! Schema__
|
7
|
+
|
8
|
+
description 'Access the current type schema of this server.'
|
9
|
+
|
10
|
+
resolve -> (root, params, context) { context[:schema] }
|
11
|
+
end
|
12
|
+
|
13
|
+
TypeMetaField = GraphQLField.new do
|
14
|
+
name '__type'
|
15
|
+
type Type__
|
16
|
+
|
17
|
+
description 'Request the type information of a single type.'
|
18
|
+
|
19
|
+
arg :name, ! GraphQLString
|
20
|
+
|
21
|
+
resolve -> (root, params, context) { context[:schema].type(params[:name]) }
|
22
|
+
end
|
23
|
+
|
24
|
+
TypeNameMetaField = GraphQLField.new do
|
25
|
+
name '__typename'
|
26
|
+
type ! GraphQLString
|
27
|
+
|
28
|
+
description 'The name of the current Object type at runtime.'
|
29
|
+
|
30
|
+
resolve -> (root, params, context) { context[:parent_type].name }
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.meta_field_map
|
34
|
+
[SchemaMetaField, TypeMetaField].reduce({}) { |memo, field| memo[field.name.to_sym] = field ; memo }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.meta_field_names
|
38
|
+
@meta_field_names ||= meta_field_map.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.meta_fields
|
42
|
+
@meta_fields ||= meta_field_map.values
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.meta_field(name)
|
46
|
+
meta_field_map[name.to_sym]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.meta_field?(name)
|
50
|
+
!!meta_field(name)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Introspection
|
3
|
+
|
4
|
+
Query = %Q(
|
5
|
+
query IntrospectionQuery {
|
6
|
+
__schema {
|
7
|
+
queryType { name }
|
8
|
+
mutationType { name }
|
9
|
+
types {
|
10
|
+
...FullType
|
11
|
+
}
|
12
|
+
directives {
|
13
|
+
name
|
14
|
+
description
|
15
|
+
args {
|
16
|
+
...InputValue
|
17
|
+
}
|
18
|
+
onOperation
|
19
|
+
onFragment
|
20
|
+
onField
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
fragment FullType on __Type {
|
25
|
+
kind
|
26
|
+
name
|
27
|
+
description
|
28
|
+
fields {
|
29
|
+
name
|
30
|
+
description
|
31
|
+
args {
|
32
|
+
...InputValue
|
33
|
+
}
|
34
|
+
type {
|
35
|
+
...TypeRef
|
36
|
+
}
|
37
|
+
isDeprecated
|
38
|
+
deprecationReason
|
39
|
+
}
|
40
|
+
inputFields {
|
41
|
+
...InputValue
|
42
|
+
}
|
43
|
+
interfaces {
|
44
|
+
...TypeRef
|
45
|
+
}
|
46
|
+
enumValues {
|
47
|
+
name
|
48
|
+
description
|
49
|
+
isDeprecated
|
50
|
+
deprecationReason
|
51
|
+
}
|
52
|
+
possibleTypes {
|
53
|
+
...TypeRef
|
54
|
+
}
|
55
|
+
}
|
56
|
+
fragment InputValue on __InputValue {
|
57
|
+
name
|
58
|
+
description
|
59
|
+
type { ...TypeRef }
|
60
|
+
defaultValue
|
61
|
+
}
|
62
|
+
fragment TypeRef on __Type {
|
63
|
+
kind
|
64
|
+
name
|
65
|
+
ofType {
|
66
|
+
kind
|
67
|
+
name
|
68
|
+
ofType {
|
69
|
+
kind
|
70
|
+
name
|
71
|
+
ofType {
|
72
|
+
kind
|
73
|
+
name
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
)
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Introspection
|
3
|
+
|
4
|
+
Schema__ = GraphQLObjectType.new do
|
5
|
+
|
6
|
+
name '__Schema'
|
7
|
+
|
8
|
+
description 'A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types ' +
|
9
|
+
'and directives on the server, as well as the entry points for query and mutation operations.'
|
10
|
+
|
11
|
+
field :types, -> { ! + ! Type__ } do
|
12
|
+
description 'A list of all types supported by this server.'
|
13
|
+
resolve -> (schema) { schema.type_map.values }
|
14
|
+
end
|
15
|
+
|
16
|
+
field :queryType, -> { ! Type__ } do
|
17
|
+
description 'The type that query operations will be rooted at.'
|
18
|
+
resolve -> (schema) { schema.query_type }
|
19
|
+
end
|
20
|
+
|
21
|
+
field :mutationType, -> { ! Type__ } do
|
22
|
+
description 'If this server supports mutation, the type that mutation operations will be rooted at.'
|
23
|
+
resolve -> (schema) { schema.mutation_type }
|
24
|
+
end
|
25
|
+
|
26
|
+
field :directives, -> { ! + ! Type__ } do
|
27
|
+
description 'A list of all directives supported by this server.'
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Directive__ = GraphQLObjectType.new do
|
33
|
+
|
34
|
+
name '__Directive'
|
35
|
+
|
36
|
+
field :name, ! GraphQLString
|
37
|
+
field :description, GraphQLString
|
38
|
+
|
39
|
+
field :args, -> { ! + ! InputValue__ }
|
40
|
+
|
41
|
+
field :onOperation, ! GraphQLBoolean, resolve: -> (directive) { directive.on_operation }
|
42
|
+
field :onFragment, ! GraphQLBoolean, resolve: -> (directive) { directive.on_fragment }
|
43
|
+
field :onField, ! GraphQLBoolean, resolve: -> (directive) { directive.on_field }
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
Type__ = GraphQLObjectType.new do
|
48
|
+
name '__Type'
|
49
|
+
|
50
|
+
field :name, GraphQLString, resolve: -> (type) { type.name rescue nil }
|
51
|
+
field :description, GraphQLString
|
52
|
+
|
53
|
+
field :kind, -> { ! TypeKind__ } do
|
54
|
+
resolve lambda { |type|
|
55
|
+
case type
|
56
|
+
when GraphQLScalarType then :scalar
|
57
|
+
when GraphQLObjectType then :object
|
58
|
+
when GraphQLInterfaceType then :interface
|
59
|
+
when GraphQLUnionType then :union
|
60
|
+
when GraphQLEnumType then :enum
|
61
|
+
when GraphQLInputObjectType then :input_object
|
62
|
+
when GraphQLList then :list
|
63
|
+
when GraphQLNonNull then :non_null
|
64
|
+
else raise RuntimeError.new("Unknown kind of type: #{type}")
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
field :fields, -> { + ! Field__ } do
|
70
|
+
arg :includeDeprecated, GraphQLBoolean, default_value: false
|
71
|
+
|
72
|
+
resolve lambda { |type, params|
|
73
|
+
return nil unless type.is_a?(GraphQLObjectType) || type.is_a?(GraphQLInterfaceType)
|
74
|
+
fields = type.fields
|
75
|
+
fields = fields.select { |field| !field.deprecation_reason } unless params[:includeDeprecated]
|
76
|
+
fields
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
field :interfaces, -> { + ! Type__ } do
|
81
|
+
resolve lambda { |type|
|
82
|
+
type.interfaces if type.is_a?(GraphQLObjectType)
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
field :possibleTypes, -> { + ! Type__ } do
|
87
|
+
resolve lambda { |type|
|
88
|
+
type.possible_types if type.is_a?(GraphQLInterfaceType) || type.is_a?(GraphQLUnionType)
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
field :enumValues, -> { + ! EnumValue__ } do
|
93
|
+
|
94
|
+
arg :includeDeprecated, GraphQLBoolean, default_value: false
|
95
|
+
|
96
|
+
resolve lambda { |type, params|
|
97
|
+
return nil unless type.is_a?(GraphQLEnumType)
|
98
|
+
values = type.values
|
99
|
+
values = values.select { |value| !value.deprecation_reason } unless params[:includeDeprecated]
|
100
|
+
values
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
field :inputFields, -> { + ! InputValue__ } do
|
105
|
+
resolve lambda { |type|
|
106
|
+
type.fields.values if type.is_a?(GraphQLInputObjectType)
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
field :ofType, -> { Type__ }, resolve: -> (type) { type.of_type rescue nil }
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
Field__ = GraphQLObjectType.new do
|
115
|
+
name '__Field'
|
116
|
+
|
117
|
+
field :name, ! GraphQLString
|
118
|
+
field :description, GraphQLString
|
119
|
+
field :args, -> { ! + ! InputValue__ }
|
120
|
+
field :type, -> { ! Type__ }
|
121
|
+
field :isDeprecated, ! GraphQLBoolean, resolve: -> (field) { !!field.deprecation_reason }
|
122
|
+
field :deprecationReason, GraphQLString, resolve: -> (field) { field.deprecation_reason }
|
123
|
+
end
|
124
|
+
|
125
|
+
InputValue__ = GraphQLObjectType.new do
|
126
|
+
name '__InputValue'
|
127
|
+
|
128
|
+
field :name, ! GraphQLString
|
129
|
+
field :description, GraphQLString
|
130
|
+
field :type, -> { ! Type__ }
|
131
|
+
field :defaultValue, GraphQLString, resolve: -> (value) { value.default_value }
|
132
|
+
end
|
133
|
+
|
134
|
+
EnumValue__ = GraphQLObjectType.new do
|
135
|
+
name '__EnumValue'
|
136
|
+
|
137
|
+
field :name, ! GraphQLString
|
138
|
+
field :description, GraphQLString
|
139
|
+
field :isDeprecated, ! GraphQLBoolean, resolve: -> (value) { !!value.deprecation_reason }
|
140
|
+
field :deprecationReason, GraphQLString, resolve: -> (value) { value.deprecation_reason }
|
141
|
+
end
|
142
|
+
|
143
|
+
TypeKind__ = GraphQLEnumType.new do
|
144
|
+
name '__TypeKind'
|
145
|
+
description 'An enum describing what kind of type a given __Type is'
|
146
|
+
|
147
|
+
value :SCALAR, :scalar, 'Indicates this type is a scalar.'
|
148
|
+
value :OBJECT, :object, 'Indicates this type is an object. `fields` and `interfaces` are valid fields.'
|
149
|
+
value :INTERFACE, :interface, 'Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.'
|
150
|
+
value :UNION, :union, 'Indicates this type is a union. `possibleTypes` is a valid field.'
|
151
|
+
value :ENUM, :enum, 'Indicates this type is an enum. `values` is a valid field.'
|
152
|
+
value :INPUT_OBJECT, :input_object, 'Indicates this type is an input object. `fields` is a valid field.'
|
153
|
+
value :LIST, :list, 'Indicates this type is a list. `ofType` is a valid field.'
|
154
|
+
value :NON_NULL, :non_null, 'Indicates this type is a non-null. `ofType` is a valid field.'
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|