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
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
|