graphql 1.4.5 → 1.5.3
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/generators/graphql/enum_generator.rb +33 -0
- data/lib/generators/graphql/function_generator.rb +15 -0
- data/lib/generators/graphql/install_generator.rb +118 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +17 -0
- data/lib/generators/graphql/mutation_generator.rb +19 -0
- data/lib/generators/graphql/object_generator.rb +34 -0
- data/lib/generators/graphql/templates/enum.erb +4 -0
- data/lib/generators/graphql/templates/function.erb +17 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +32 -0
- data/lib/generators/graphql/templates/interface.erb +4 -0
- data/lib/generators/graphql/templates/loader.erb +15 -0
- data/lib/generators/graphql/templates/mutation.erb +12 -0
- data/lib/generators/graphql/templates/object.erb +5 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/schema.erb +34 -0
- data/lib/generators/graphql/templates/union.erb +4 -0
- data/lib/generators/graphql/type_generator.rb +78 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql.rb +10 -0
- data/lib/graphql/analysis/analyze_query.rb +1 -1
- data/lib/graphql/analysis/query_complexity.rb +6 -50
- data/lib/graphql/analysis/query_depth.rb +1 -1
- data/lib/graphql/argument.rb +21 -0
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +3 -3
- data/lib/graphql/define.rb +1 -0
- data/lib/graphql/define/assign_argument.rb +3 -19
- data/lib/graphql/define/assign_mutation_function.rb +34 -0
- data/lib/graphql/define/assign_object_field.rb +26 -14
- data/lib/graphql/define/defined_object_proxy.rb +21 -0
- data/lib/graphql/define/instance_definable.rb +61 -11
- data/lib/graphql/directive.rb +6 -1
- data/lib/graphql/execution/directive_checks.rb +1 -0
- data/lib/graphql/execution/execute.rb +14 -9
- data/lib/graphql/execution/field_result.rb +1 -0
- data/lib/graphql/execution/lazy.rb +8 -17
- data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -0
- data/lib/graphql/execution/lazy/resolve.rb +1 -0
- data/lib/graphql/execution/selection_result.rb +1 -0
- data/lib/graphql/execution/typecast.rb +39 -26
- data/lib/graphql/field.rb +15 -3
- data/lib/graphql/field/resolve.rb +3 -3
- data/lib/graphql/function.rb +134 -0
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/internal_representation.rb +1 -1
- data/lib/graphql/internal_representation/node.rb +35 -107
- data/lib/graphql/internal_representation/rewrite.rb +189 -183
- data/lib/graphql/internal_representation/visit.rb +38 -0
- data/lib/graphql/introspection/input_value_type.rb +10 -1
- data/lib/graphql/introspection/schema_type.rb +1 -1
- data/lib/graphql/language/lexer.rb +6 -3
- data/lib/graphql/language/lexer.rl +6 -3
- data/lib/graphql/object_type.rb +53 -13
- data/lib/graphql/query.rb +30 -14
- data/lib/graphql/query/arguments.rb +2 -0
- data/lib/graphql/query/context.rb +2 -2
- data/lib/graphql/query/literal_input.rb +9 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +2 -2
- data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
- data/lib/graphql/relay.rb +1 -0
- data/lib/graphql/relay/array_connection.rb +1 -1
- data/lib/graphql/relay/base_connection.rb +34 -15
- data/lib/graphql/relay/connection_resolve.rb +7 -2
- data/lib/graphql/relay/mutation.rb +45 -4
- data/lib/graphql/relay/node.rb +18 -6
- data/lib/graphql/relay/range_add.rb +45 -0
- data/lib/graphql/relay/relation_connection.rb +17 -2
- data/lib/graphql/runtime_type_error.rb +1 -0
- data/lib/graphql/schema.rb +40 -5
- data/lib/graphql/schema/base_64_encoder.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +56 -21
- data/lib/graphql/schema/default_parse_error.rb +10 -0
- data/lib/graphql/schema/loader.rb +8 -1
- data/lib/graphql/schema/null_mask.rb +1 -0
- data/lib/graphql/schema/validation.rb +35 -0
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/arguments_validator.rb +7 -4
- data/lib/graphql/static_validation/definition_dependencies.rb +183 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +28 -96
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +23 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -5
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -31
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +11 -41
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +2 -2
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -7
- data/lib/graphql/static_validation/validation_context.rb +22 -1
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/string_type.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +12 -3
- data/spec/generators/graphql/enum_generator_spec.rb +29 -0
- data/spec/generators/graphql/function_generator_spec.rb +33 -0
- data/spec/generators/graphql/install_generator_spec.rb +185 -0
- data/spec/generators/graphql/interface_generator_spec.rb +32 -0
- data/spec/generators/graphql/loader_generator_spec.rb +31 -0
- data/spec/generators/graphql/mutation_generator_spec.rb +28 -0
- data/spec/generators/graphql/object_generator_spec.rb +42 -0
- data/spec/generators/graphql/union_generator_spec.rb +50 -0
- data/spec/graphql/analysis/query_complexity_spec.rb +2 -1
- data/spec/graphql/define/instance_definable_spec.rb +38 -0
- data/spec/graphql/directive/skip_directive_spec.rb +1 -0
- data/spec/graphql/directive_spec.rb +18 -0
- data/spec/graphql/execution/typecast_spec.rb +41 -46
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/function_spec.rb +128 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +166 -129
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/language/lexer_spec.rb +6 -0
- data/spec/graphql/object_type_spec.rb +73 -2
- data/spec/graphql/query/arguments_spec.rb +28 -0
- data/spec/graphql/query/variables_spec.rb +7 -1
- data/spec/graphql/query_spec.rb +30 -0
- data/spec/graphql/relay/base_connection_spec.rb +26 -8
- data/spec/graphql/relay/connection_resolve_spec.rb +45 -0
- data/spec/graphql/relay/connection_type_spec.rb +21 -0
- data/spec/graphql/relay/node_spec.rb +30 -2
- data/spec/graphql/relay/range_add_spec.rb +113 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +114 -0
- data/spec/graphql/schema/loader_spec.rb +1 -0
- data/spec/graphql/schema/printer_spec.rb +2 -2
- data/spec/graphql/schema/validation_spec.rb +80 -11
- data/spec/graphql/schema/warden_spec.rb +10 -10
- data/spec/graphql/schema_spec.rb +18 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +16 -0
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +50 -3
- data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +27 -0
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +57 -0
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
- data/spec/graphql/string_type_spec.rb +7 -0
- data/spec/spec_helper.rb +3 -3
- data/spec/support/base_generator_test.rb +7 -0
- data/spec/support/dummy/schema.rb +32 -30
- data/spec/support/star_wars/schema.rb +81 -23
- metadata +98 -20
- data/lib/graphql/internal_representation/selection.rb +0 -85
@@ -22,8 +22,13 @@ module GraphQL
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def build_connection(nodes, args, parent, ctx)
|
25
|
-
|
26
|
-
|
25
|
+
if nodes.is_a? GraphQL::ExecutionError
|
26
|
+
ctx.add_error(nodes)
|
27
|
+
nil
|
28
|
+
else
|
29
|
+
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(nodes)
|
30
|
+
connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: parent, context: ctx)
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
@@ -48,6 +48,45 @@ module GraphQL
|
|
48
48
|
# # }
|
49
49
|
# # }}
|
50
50
|
#
|
51
|
+
# @example Using a GraphQL::Function
|
52
|
+
# class UpdateAttributes < GraphQL::Function
|
53
|
+
# attr_reader :model, :return_as, :arguments
|
54
|
+
#
|
55
|
+
# def initialize(model:, return_as:, attributes:)
|
56
|
+
# @model = model
|
57
|
+
# @arguments = {}
|
58
|
+
# attributes.each do |name, type|
|
59
|
+
# arg_name = name.to_s
|
60
|
+
# @arguments[arg_name] = GraphQL::Argument.define(name: arg_name, type: type)
|
61
|
+
# end
|
62
|
+
# @arguments["id"] = GraphQL::Argument.define(name: "id", type: !GraphQL::ID_TYPE)
|
63
|
+
# @return_as = return_as
|
64
|
+
# @attributes = attributes
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# def type
|
68
|
+
# fn = self
|
69
|
+
# GraphQL::ObjectType.define do
|
70
|
+
# name "Update#{fn.model.name}AttributesResponse"
|
71
|
+
# field :clientMutationId, types.ID
|
72
|
+
# field fn.return_as.keys[0], fn.return_as.values[0]
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# def call(obj, args, ctx)
|
77
|
+
# record = @model.find(args[:inputs][:id])
|
78
|
+
# new_values = {}
|
79
|
+
# @attributes.each { |a| new_values[a] = args[a] }
|
80
|
+
# record.update(new_values)
|
81
|
+
# { @return_as => record }
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# UpdateNameMutation = GraphQL::Relay::Mutation.define do
|
86
|
+
# name "UpdateName"
|
87
|
+
# function UpdateAttributes.new(model: Item, return_as: { item: ItemType }, attributes: {name: !types.String})
|
88
|
+
# end
|
89
|
+
|
51
90
|
class Mutation
|
52
91
|
include GraphQL::Define::InstanceDefinable
|
53
92
|
accepts_definitions(
|
@@ -56,6 +95,7 @@ module GraphQL
|
|
56
95
|
:return_interfaces,
|
57
96
|
input_field: GraphQL::Define::AssignArgument,
|
58
97
|
return_field: GraphQL::Define::AssignObjectField,
|
98
|
+
function: GraphQL::Define::AssignMutationFunction,
|
59
99
|
)
|
60
100
|
attr_accessor :name, :description, :fields, :arguments, :return_type, :return_interfaces
|
61
101
|
|
@@ -65,7 +105,6 @@ module GraphQL
|
|
65
105
|
:return_interfaces, :resolve=,
|
66
106
|
:field, :result_class, :input_type
|
67
107
|
)
|
68
|
-
|
69
108
|
# For backwards compat, but do we need this separate API?
|
70
109
|
alias :return_fields :fields
|
71
110
|
alias :input_fields :arguments
|
@@ -128,10 +167,12 @@ module GraphQL
|
|
128
167
|
name("#{relay_mutation.name}Input")
|
129
168
|
description("Autogenerated input type of #{relay_mutation.name}")
|
130
169
|
input_field :clientMutationId, types.String, "A unique identifier for the client performing the mutation."
|
131
|
-
relay_mutation.
|
170
|
+
relay_mutation.arguments.each do |input_field_name, field_obj|
|
132
171
|
kwargs = {}
|
133
|
-
|
134
|
-
|
172
|
+
if field_obj.default_value?
|
173
|
+
kwargs[:default_value] = field_obj.default_value
|
174
|
+
end
|
175
|
+
input_field(input_field_name, field_obj.type, field_obj.description, **kwargs)
|
135
176
|
end
|
136
177
|
mutation(relay_mutation)
|
137
178
|
end
|
data/lib/graphql/relay/node.rb
CHANGED
@@ -4,27 +4,39 @@ module GraphQL
|
|
4
4
|
# Helpers for working with Relay-specific Node objects.
|
5
5
|
module Node
|
6
6
|
# @return [GraphQL::Field] a field for finding objects by their global ID.
|
7
|
-
def self.field(
|
7
|
+
def self.field(**kwargs, &block)
|
8
8
|
# We have to define it fresh each time because
|
9
9
|
# its name will be modified and its description
|
10
10
|
# _may_ be modified.
|
11
|
-
GraphQL::Field.define do
|
11
|
+
field = GraphQL::Field.define do
|
12
12
|
type(GraphQL::Relay::Node.interface)
|
13
13
|
description("Fetches an object given its ID.")
|
14
14
|
argument(:id, !types.ID, "ID of the object.")
|
15
|
-
resolve(
|
15
|
+
resolve(GraphQL::Relay::Node::FindNode)
|
16
16
|
relay_node_field(true)
|
17
17
|
end
|
18
|
+
|
19
|
+
if kwargs.any? || block
|
20
|
+
field = field.redefine(kwargs, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
field
|
18
24
|
end
|
19
25
|
|
20
|
-
def self.plural_field(
|
21
|
-
GraphQL::Field.define do
|
26
|
+
def self.plural_field(**kwargs, &block)
|
27
|
+
field = GraphQL::Field.define do
|
22
28
|
type(!types[GraphQL::Relay::Node.interface])
|
23
29
|
description("Fetches a list of objects given a list of IDs.")
|
24
30
|
argument(:ids, !types[!types.ID], "IDs of the objects.")
|
25
|
-
resolve(
|
31
|
+
resolve(GraphQL::Relay::Node::FindNodes)
|
26
32
|
relay_nodes_field(true)
|
27
33
|
end
|
34
|
+
|
35
|
+
if kwargs.any? || block
|
36
|
+
field = field.redefine(kwargs, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
field
|
28
40
|
end
|
29
41
|
|
30
42
|
# @return [GraphQL::InterfaceType] The interface which all Relay types must implement
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Relay
|
4
|
+
# This provides some isolation from `GraphQL::Relay` internals.
|
5
|
+
#
|
6
|
+
# Given a list of items and a new item, it will provide a connection and an edge.
|
7
|
+
#
|
8
|
+
# The connection doesn't receive outside arguments, so the list of items
|
9
|
+
# should be ordered and paginated before providing it here.
|
10
|
+
#
|
11
|
+
# @example Adding a comment to list of comments
|
12
|
+
# post = Post.find(args[:postId])
|
13
|
+
# comments = post.comments
|
14
|
+
# new_comment = comments.build(body: args[:body])
|
15
|
+
# new_comment.save!
|
16
|
+
#
|
17
|
+
# range_add = GraphQL::Relay::RangeAdd.new(
|
18
|
+
# parent: post,
|
19
|
+
# collection: comments,
|
20
|
+
# item: new_comment,
|
21
|
+
# context: ctx,
|
22
|
+
# )
|
23
|
+
#
|
24
|
+
# response = {
|
25
|
+
# post: post,
|
26
|
+
# commentsConnection: range_add.connection,
|
27
|
+
# newCommentEdge: range_add.edge,
|
28
|
+
# }
|
29
|
+
class RangeAdd
|
30
|
+
attr_reader :edge, :connection, :parent
|
31
|
+
|
32
|
+
# @param collection [Object] The list of items to wrap in a connection
|
33
|
+
# @param item [Object] The newly-added item (will be wrapped in `edge_class`)
|
34
|
+
# @param parent [Object] The owner of `collection`, will be passed to the connection if provided
|
35
|
+
# @param context [GraphQL::Query::Context] The surrounding `ctx`, will be passed to the connection if provided (this is required for cursor encoders)
|
36
|
+
# @param edge_class [Class] The class to wrap `item` with
|
37
|
+
def initialize(collection:, item:, parent: nil, context: nil, edge_class: Relay::Edge)
|
38
|
+
connection_class = BaseConnection.connection_for_nodes(collection)
|
39
|
+
@parent = parent
|
40
|
+
@connection = connection_class.new(collection, {}, parent: parent, context: context)
|
41
|
+
@edge = edge_class.new(item, @connection)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -17,7 +17,7 @@ module GraphQL
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def has_next_page
|
20
|
-
!!(first &&
|
20
|
+
!!(first && paged_nodes && @has_next_page)
|
21
21
|
end
|
22
22
|
|
23
23
|
def has_previous_page
|
@@ -34,7 +34,22 @@ module GraphQL
|
|
34
34
|
|
35
35
|
# apply first / last limit results
|
36
36
|
def paged_nodes
|
37
|
-
@paged_nodes ||=
|
37
|
+
@paged_nodes ||= begin
|
38
|
+
if limit
|
39
|
+
limit_more = limit + 1
|
40
|
+
more_nodes = sliced_nodes.limit(limit_more).to_a
|
41
|
+
if more_nodes.size > limit
|
42
|
+
@has_next_page = true
|
43
|
+
more_nodes[0..-2]
|
44
|
+
else
|
45
|
+
@has_next_page = false
|
46
|
+
more_nodes
|
47
|
+
end
|
48
|
+
else
|
49
|
+
@has_next_page = false
|
50
|
+
sliced_nodes
|
51
|
+
end
|
52
|
+
end
|
38
53
|
end
|
39
54
|
|
40
55
|
# Apply cursors to edges
|
data/lib/graphql/schema.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/schema/base_64_encoder"
|
3
3
|
require "graphql/schema/catchall_middleware"
|
4
|
+
require "graphql/schema/default_parse_error"
|
4
5
|
require "graphql/schema/default_type_error"
|
5
6
|
require "graphql/schema/invalid_type_error"
|
6
7
|
require "graphql/schema/instrumented_field_map"
|
@@ -55,12 +56,12 @@ module GraphQL
|
|
55
56
|
:query, :mutation, :subscription,
|
56
57
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
57
58
|
:max_depth, :max_complexity,
|
58
|
-
:orphan_types, :resolve_type, :type_error,
|
59
|
+
:orphan_types, :resolve_type, :type_error, :parse_error,
|
59
60
|
:object_from_id, :id_from_object,
|
60
61
|
:default_mask,
|
61
62
|
:cursor_encoder,
|
62
63
|
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m }},
|
63
|
-
instrument: ->
|
64
|
+
instrument: ->(schema, type, instrumenter) { schema.instrumenters[type] << instrumenter },
|
64
65
|
query_analyzer: ->(schema, analyzer) { schema.query_analyzers << analyzer },
|
65
66
|
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
66
67
|
lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
|
@@ -103,6 +104,7 @@ module GraphQL
|
|
103
104
|
@object_from_id_proc = nil
|
104
105
|
@id_from_object_proc = nil
|
105
106
|
@type_error_proc = DefaultTypeError
|
107
|
+
@parse_error_proc = DefaultParseError
|
106
108
|
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
107
109
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
108
110
|
@cursor_encoder = Base64Encoder
|
@@ -148,6 +150,23 @@ module GraphQL
|
|
148
150
|
rescue_middleware.remove_handler(*args, &block)
|
149
151
|
end
|
150
152
|
|
153
|
+
# Validate a query string according to this schema.
|
154
|
+
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
|
155
|
+
# @return [Array<GraphQL::StaticValidation::Message>]
|
156
|
+
def validate(string_or_document, rules: nil)
|
157
|
+
doc = if string_or_document.is_a?(String)
|
158
|
+
GraphQL.parse(string_or_document)
|
159
|
+
else
|
160
|
+
string_or_document
|
161
|
+
end
|
162
|
+
query = GraphQL::Query.new(self, document: doc)
|
163
|
+
validator_opts = { schema: self }
|
164
|
+
rules && (validator_opts[:rules] = rules)
|
165
|
+
validator = GraphQL::StaticValidation::Validator.new(validator_opts)
|
166
|
+
res = validator.validate(query)
|
167
|
+
res[:errors]
|
168
|
+
end
|
169
|
+
|
151
170
|
def define(**kwargs, &block)
|
152
171
|
super
|
153
172
|
ensure_defined
|
@@ -316,6 +335,21 @@ module GraphQL
|
|
316
335
|
@type_error_proc = new_proc
|
317
336
|
end
|
318
337
|
|
338
|
+
# A function to call when {#execute} receives an invalid query string
|
339
|
+
#
|
340
|
+
# @see {DefaultParseError} is the default behavior.
|
341
|
+
# @param err [GraphQL::ParseError] The error encountered during parsing
|
342
|
+
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
343
|
+
# @return void
|
344
|
+
def parse_error(err, ctx)
|
345
|
+
@parse_error_proc.call(err, ctx)
|
346
|
+
end
|
347
|
+
|
348
|
+
# @param new_proc [#call] A new callable for handling parse errors during execution
|
349
|
+
def parse_error=(new_proc)
|
350
|
+
@parse_error_proc = new_proc
|
351
|
+
end
|
352
|
+
|
319
353
|
# Get a unique identifier from this object
|
320
354
|
# @param object [Any] An application object
|
321
355
|
# @param type [GraphQL::BaseType] The current type definition
|
@@ -342,10 +376,11 @@ module GraphQL
|
|
342
376
|
end
|
343
377
|
|
344
378
|
# Create schema from an IDL schema.
|
345
|
-
# @param definition_string String A schema definition string
|
379
|
+
# @param definition_string [String] A schema definition string
|
380
|
+
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
346
381
|
# @return [GraphQL::Schema] the schema described by `document`
|
347
|
-
def self.from_definition(
|
348
|
-
GraphQL::Schema::BuildFromDefinition.from_definition(
|
382
|
+
def self.from_definition(string, default_resolve: BuildFromDefinition::DefaultResolve)
|
383
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(string, default_resolve: default_resolve)
|
349
384
|
end
|
350
385
|
|
351
386
|
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
@@ -3,23 +3,57 @@ module GraphQL
|
|
3
3
|
class Schema
|
4
4
|
module BuildFromDefinition
|
5
5
|
class << self
|
6
|
-
def from_definition(definition_string)
|
6
|
+
def from_definition(definition_string, default_resolve:)
|
7
7
|
document = GraphQL::parse(definition_string)
|
8
|
-
Builder.build(document)
|
8
|
+
Builder.build(document, default_resolve: default_resolve)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
# @api private
|
13
|
+
module DefaultResolve
|
14
|
+
def self.call(type, field, obj, args, ctx)
|
15
|
+
if field.arguments.any?
|
16
|
+
obj.public_send(field.name, args, ctx)
|
17
|
+
else
|
18
|
+
obj.public_send(field.name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
class ResolveMap
|
25
|
+
def initialize(resolve_hash)
|
26
|
+
@resolve_hash = resolve_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(type, field, obj, args, ctx)
|
30
|
+
type_hash = @resolve_hash[type.name]
|
31
|
+
type_hash && (resolver = type_hash[field.name])
|
32
|
+
|
33
|
+
if resolver.nil?
|
34
|
+
raise(KeyError, "resolver not found for #{type.name}.#{field.name}")
|
35
|
+
else
|
36
|
+
resolver.call(obj, args, ctx)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
12
42
|
module Builder
|
13
43
|
extend self
|
14
44
|
|
15
|
-
def build(document)
|
45
|
+
def build(document, default_resolve: DefaultResolve)
|
16
46
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
17
47
|
|
48
|
+
if default_resolve.is_a?(Hash)
|
49
|
+
default_resolve = ResolveMap.new(default_resolve)
|
50
|
+
end
|
51
|
+
|
18
52
|
schema_definition = nil
|
19
53
|
types = {}
|
20
54
|
types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
|
21
55
|
directives = {}
|
22
|
-
type_resolver = ->
|
56
|
+
type_resolver = ->(type) { -> { resolve_type(types, type) } }
|
23
57
|
|
24
58
|
document.definitions.each do |definition|
|
25
59
|
case definition
|
@@ -29,7 +63,7 @@ module GraphQL
|
|
29
63
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
30
64
|
types[definition.name] = build_enum_type(definition, type_resolver)
|
31
65
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
32
|
-
types[definition.name] = build_object_type(definition, type_resolver)
|
66
|
+
types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
|
33
67
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
34
68
|
types[definition.name] = build_interface_type(definition, type_resolver)
|
35
69
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
@@ -81,7 +115,7 @@ module GraphQL
|
|
81
115
|
end
|
82
116
|
end
|
83
117
|
|
84
|
-
NullResolveType = ->
|
118
|
+
NullResolveType = ->(obj, ctx) {
|
85
119
|
raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution.")
|
86
120
|
}
|
87
121
|
|
@@ -128,11 +162,13 @@ module GraphQL
|
|
128
162
|
)
|
129
163
|
end
|
130
164
|
|
131
|
-
def build_object_type(object_type_definition, type_resolver)
|
132
|
-
|
165
|
+
def build_object_type(object_type_definition, type_resolver, default_resolve:)
|
166
|
+
type_def = nil
|
167
|
+
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
|
168
|
+
type_def = GraphQL::ObjectType.define(
|
133
169
|
name: object_type_definition.name,
|
134
170
|
description: object_type_definition.description,
|
135
|
-
fields: Hash[build_fields(object_type_definition.fields, type_resolver)],
|
171
|
+
fields: Hash[build_fields(object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)],
|
136
172
|
interfaces: object_type_definition.interfaces.map{ |interface_name| type_resolver.call(interface_name) },
|
137
173
|
)
|
138
174
|
end
|
@@ -209,11 +245,11 @@ module GraphQL
|
|
209
245
|
GraphQL::InterfaceType.define(
|
210
246
|
name: interface_type_definition.name,
|
211
247
|
description: interface_type_definition.description,
|
212
|
-
fields: Hash[build_fields(interface_type_definition.fields, type_resolver)],
|
248
|
+
fields: Hash[build_fields(interface_type_definition.fields, type_resolver, default_resolve: nil)],
|
213
249
|
)
|
214
250
|
end
|
215
251
|
|
216
|
-
def build_fields(field_definitions, type_resolver)
|
252
|
+
def build_fields(field_definitions, type_resolver, default_resolve:)
|
217
253
|
field_definitions.map do |field_definition|
|
218
254
|
field_arguments = Hash[field_definition.arguments.map do |argument|
|
219
255
|
kwargs = {}
|
@@ -232,16 +268,15 @@ module GraphQL
|
|
232
268
|
[argument.name, arg]
|
233
269
|
end]
|
234
270
|
|
235
|
-
|
236
|
-
field_definition.name,
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
]
|
271
|
+
field = GraphQL::Field.define(
|
272
|
+
name: field_definition.name,
|
273
|
+
description: field_definition.description,
|
274
|
+
type: type_resolver.call(field_definition.type),
|
275
|
+
arguments: field_arguments,
|
276
|
+
resolve: ->(obj, args, ctx) { default_resolve.call(field, obj, args, ctx) },
|
277
|
+
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
278
|
+
)
|
279
|
+
[field_definition.name, field]
|
245
280
|
end
|
246
281
|
end
|
247
282
|
|