graphql 1.11.12 → 1.12.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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +5 -5
- data/lib/generators/graphql/relay_generator.rb +63 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +1 -1
- data/lib/generators/graphql/templates/query_type.erb +1 -3
- data/lib/generators/graphql/templates/schema.erb +8 -35
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/visitor.rb +9 -1
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +22 -2
- data/lib/graphql/backtrace/tracer.rb +40 -9
- data/lib/graphql/backtrace.rb +28 -19
- data/lib/graphql/backwards_compatibility.rb +1 -0
- data/lib/graphql/compatibility/execution_specification.rb +1 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
- data/lib/graphql/dataloader/null_dataloader.rb +21 -0
- data/lib/graphql/dataloader/request.rb +24 -0
- data/lib/graphql/dataloader/request_all.rb +22 -0
- data/lib/graphql/dataloader/source.rb +93 -0
- data/lib/graphql/dataloader.rb +197 -0
- data/lib/graphql/define/assign_global_id_field.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +32 -2
- data/lib/graphql/define/type_definer.rb +5 -5
- data/lib/graphql/deprecated_dsl.rb +5 -0
- data/lib/graphql/enum_type.rb +2 -0
- data/lib/graphql/execution/errors.rb +4 -0
- data/lib/graphql/execution/execute.rb +7 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -14
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
- data/lib/graphql/execution/interpreter/runtime.rb +210 -124
- data/lib/graphql/execution/interpreter.rb +10 -6
- data/lib/graphql/execution/multiplex.rb +20 -6
- data/lib/graphql/function.rb +4 -0
- data/lib/graphql/input_object_type.rb +2 -0
- data/lib/graphql/interface_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +50 -23
- data/lib/graphql/language/nodes.rb +0 -5
- data/lib/graphql/language/visitor.rb +0 -1
- data/lib/graphql/object_type.rb +2 -0
- data/lib/graphql/pagination/connection.rb +5 -1
- data/lib/graphql/pagination/connections.rb +6 -16
- data/lib/graphql/query/context.rb +4 -0
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/query.rb +2 -0
- data/lib/graphql/relay/base_connection.rb +7 -0
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -0
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema/argument.rb +30 -10
- data/lib/graphql/schema/build_from_definition.rb +145 -58
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive.rb +76 -0
- data/lib/graphql/schema/enum.rb +3 -0
- data/lib/graphql/schema/enum_value.rb +13 -7
- data/lib/graphql/schema/field/connection_extension.rb +3 -2
- data/lib/graphql/schema/field.rb +28 -10
- data/lib/graphql/schema/input_object.rb +36 -28
- data/lib/graphql/schema/interface.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +3 -3
- data/lib/graphql/schema/member/has_arguments.rb +24 -6
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +4 -0
- data/lib/graphql/schema/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
- data/lib/graphql/schema/resolver.rb +7 -0
- data/lib/graphql/schema/subscription.rb +19 -1
- data/lib/graphql/schema/timeout_middleware.rb +2 -0
- data/lib/graphql/schema/validation.rb +2 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
- data/lib/graphql/schema/validator/format_validator.rb +49 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/length_validator.rb +57 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/validator.rb +163 -0
- data/lib/graphql/schema.rb +72 -49
- data/lib/graphql/static_validation/base_visitor.rb +0 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +4 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -6
- data/lib/graphql/static_validation/validator.rb +12 -14
- data/lib/graphql/subscriptions.rb +17 -20
- data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/types/relay/base_connection.rb +2 -92
- data/lib/graphql/types/relay/base_edge.rb +2 -35
- data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +1 -19
- data/lib/graphql/types/relay/nodes_field.rb +1 -19
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/union_type.rb +2 -0
- data/lib/graphql/upgrader/member.rb +1 -0
- data/lib/graphql/upgrader/schema.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +38 -4
- metadata +34 -9
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 433f1170eb17ab192761efcd8c27cf9efe5f952ab47b501baca270e33d6007cd
|
4
|
+
data.tar.gz: c56045f746385ae37ebd0f82116aad10782e9265c13e0e85e39488ef3db02c74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d580c78b6b659602067fcfd3043eff7ef2b20da1d50c1ca2b234614d864e1a232cb65e7456cfdf85764523f30bd5232823ea19b4664208aef875cc68e2e5fc9
|
7
|
+
data.tar.gz: 172bc16fadfeee1f022646498dd2ce359bd885fb96ddbeeab50f7583d27811501e583194dd582a7cf47d63545c2fe00c4fa4625b6b247155f537ff4a6de60ac1
|
@@ -43,9 +43,6 @@ module Graphql
|
|
43
43
|
# post "/graphql", to: "graphql#execute"
|
44
44
|
# ```
|
45
45
|
#
|
46
|
-
# Accept a `--relay` option which adds
|
47
|
-
# The root `node(id: ID!)` field.
|
48
|
-
#
|
49
46
|
# Accept a `--batch` option which adds `GraphQL::Batch` setup.
|
50
47
|
#
|
51
48
|
# Use `--no-graphiql` to skip `graphiql-rails` installation.
|
@@ -79,8 +76,8 @@ module Graphql
|
|
79
76
|
|
80
77
|
class_option :relay,
|
81
78
|
type: :boolean,
|
82
|
-
default:
|
83
|
-
desc: "Include
|
79
|
+
default: true,
|
80
|
+
desc: "Include installation of Relay conventions (nodes, connections, edges)"
|
84
81
|
|
85
82
|
class_option :batch,
|
86
83
|
type: :boolean,
|
@@ -164,7 +161,10 @@ if Rails.env.development?
|
|
164
161
|
RUBY
|
165
162
|
end
|
166
163
|
end
|
164
|
+
end
|
167
165
|
|
166
|
+
if options[:relay]
|
167
|
+
generate("graphql:relay")
|
168
168
|
end
|
169
169
|
|
170
170
|
if gemfile_modified?
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rails/generators/base'
|
3
|
+
require_relative 'core'
|
4
|
+
|
5
|
+
module Graphql
|
6
|
+
module Generators
|
7
|
+
class RelayGenerator < Rails::Generators::Base
|
8
|
+
include Core
|
9
|
+
|
10
|
+
desc "Add base types and fields for Relay-style nodes and connections"
|
11
|
+
source_root File.expand_path('../templates', __FILE__)
|
12
|
+
|
13
|
+
def install_relay
|
14
|
+
# Add Node, `node(id:)`, and `nodes(ids:)`
|
15
|
+
template("node_type.erb", "#{options[:directory]}/types/node_type.rb")
|
16
|
+
in_root do
|
17
|
+
fields = " # Add `node(id: ID!) and `nodes(ids: [ID!]!)`\n include GraphQL::Types::Relay::HasNodeField\n include GraphQL::Types::Relay::HasNodesField\n\n"
|
18
|
+
inject_into_file "#{options[:directory]}/types/query_type.rb", fields, after: /class .*QueryType\s*<\s*[^\s]+?\n/m, force: false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add connections and edges
|
22
|
+
template("base_connection.erb", "#{options[:directory]}/types/base_connection.rb")
|
23
|
+
template("base_edge.erb", "#{options[:directory]}/types/base_edge.rb")
|
24
|
+
connectionable_type_files = {
|
25
|
+
"#{options[:directory]}/types/base_object.rb" => /class .*BaseObject\s*<\s*[^\s]+?\n/m,
|
26
|
+
"#{options[:directory]}/types/base_union.rb" => /class .*BaseUnion\s*<\s*[^\s]+?\n/m,
|
27
|
+
"#{options[:directory]}/types/base_interface.rb" => /include GraphQL::Schema::Interface\n/m,
|
28
|
+
}
|
29
|
+
in_root do
|
30
|
+
connectionable_type_files.each do |type_class_file, sentinel|
|
31
|
+
inject_into_file type_class_file, " connection_type_class(Types::BaseConnection)\n", after: sentinel, force: false
|
32
|
+
inject_into_file type_class_file, " edge_type_class(Types::BaseEdge)\n", after: sentinel, force: false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Add object ID hooks & connection plugin
|
37
|
+
schema_code = <<-RUBY
|
38
|
+
|
39
|
+
# Relay-style Object Identification:
|
40
|
+
|
41
|
+
# Return a string UUID for `object`
|
42
|
+
def self.id_from_object(object, type_definition, query_ctx)
|
43
|
+
# Here's a simple implementation which:
|
44
|
+
# - joins the type name & object.id
|
45
|
+
# - encodes it with base64:
|
46
|
+
# GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Given a string UUID, find the object
|
50
|
+
def self.object_from_id(id, query_ctx)
|
51
|
+
# For example, to decode the UUIDs generated above:
|
52
|
+
# type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
|
53
|
+
#
|
54
|
+
# Then, based on `type_name` and `id`
|
55
|
+
# find an object in your application
|
56
|
+
# ...
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
inject_into_file schema_file_path, schema_code, before: /^end\n/m, force: false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
2
|
+
module Types
|
3
|
+
class BaseConnection < Types::BaseObject
|
4
|
+
# add `nodes` and `pageInfo` fields, as well as `edge_type(...)` and `node_nullable(...)` overrides
|
5
|
+
include GraphQL::Types::Relay::ConnectionBehaviors
|
6
|
+
end
|
7
|
+
end
|
8
|
+
<% end -%>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% module_namespacing_when_supported do -%>
|
2
2
|
module Types
|
3
3
|
class <%= type_ruby_name.split('::')[-1] %> < Types::BaseObject
|
4
|
-
<% if options.node %> implements GraphQL::Relay::Node
|
4
|
+
<% if options.node %> implements GraphQL::Types::Relay::Node
|
5
5
|
<% end %><% normalized_fields.each do |f| %> <%= f.to_ruby %>
|
6
6
|
<% end %> end
|
7
7
|
end
|
@@ -1,42 +1,15 @@
|
|
1
1
|
<% module_namespacing_when_supported do -%>
|
2
2
|
class <%= schema_name %> < GraphQL::Schema
|
3
3
|
query(Types::QueryType)
|
4
|
-
|
5
|
-
#
|
6
|
-
use GraphQL::
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
use GraphQL::Pagination::Connections
|
11
|
-
<% if options[:relay] %>
|
12
|
-
# Relay Object Identification:
|
13
|
-
|
14
|
-
# Return a string UUID for `object`
|
15
|
-
def self.id_from_object(object, type_definition, query_ctx)
|
16
|
-
# Here's a simple implementation which:
|
17
|
-
# - joins the type name & object.id
|
18
|
-
# - encodes it with base64:
|
19
|
-
# GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Given a string UUID, find the object
|
23
|
-
def self.object_from_id(id, query_ctx)
|
24
|
-
# For example, to decode the UUIDs generated above:
|
25
|
-
# type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
|
26
|
-
#
|
27
|
-
# Then, based on `type_name` and `id`
|
28
|
-
# find an object in your application
|
29
|
-
# ...
|
30
|
-
end
|
31
|
-
|
32
|
-
# Object Resolution
|
33
|
-
def self.resolve_type(type, obj, ctx)
|
4
|
+
<% if options[:batch] %>
|
5
|
+
# GraphQL::Batch setup:
|
6
|
+
use GraphQL::Batch
|
7
|
+
<% end %>
|
8
|
+
# Union and Interface Resolution
|
9
|
+
def self.resolve_type(abstract_type, obj, ctx)
|
34
10
|
# TODO: Implement this function
|
35
|
-
# to return the correct type for `obj`
|
11
|
+
# to return the correct object type for `obj`
|
36
12
|
raise(GraphQL::RequiredImplementationMissingError)
|
37
13
|
end
|
38
|
-
|
39
|
-
# GraphQL::Batch setup:
|
40
|
-
use GraphQL::Batch
|
41
|
-
<% end %>end
|
14
|
+
end
|
42
15
|
<% end -%>
|
@@ -3,6 +3,11 @@ module GraphQL
|
|
3
3
|
module Analysis
|
4
4
|
module_function
|
5
5
|
|
6
|
+
def use(schema_class)
|
7
|
+
schema = schema_class.is_a?(Class) ? schema_class : schema_class.target
|
8
|
+
schema.analysis_engine = self
|
9
|
+
end
|
10
|
+
|
6
11
|
# @return [void]
|
7
12
|
def analyze_multiplex(multiplex, analyzers)
|
8
13
|
multiplex.trace("analyze_multiplex", { multiplex: multiplex }) do
|
@@ -38,6 +43,8 @@ module GraphQL
|
|
38
43
|
# @param analyzers [Array<#call>] Objects that respond to `#call(memo, visit_type, irep_node)`
|
39
44
|
# @return [Array<Any>] Results from those analyzers
|
40
45
|
def analyze_query(query, analyzers, multiplex_states: [])
|
46
|
+
warn "Legacy analysis will be removed in GraphQL-Ruby 2.0, please upgrade to AST Analysis: https://graphql-ruby.org/queries/ast_analysis.html (schema: #{query.schema})"
|
47
|
+
|
41
48
|
query.trace("analyze_query", { query: query }) do
|
42
49
|
analyzers_to_run = analyzers.select do |analyzer|
|
43
50
|
if analyzer.respond_to?(:analyze?)
|
@@ -19,6 +19,7 @@ module GraphQL
|
|
19
19
|
@field_definitions = []
|
20
20
|
@argument_definitions = []
|
21
21
|
@directive_definitions = []
|
22
|
+
@rescued_errors = []
|
22
23
|
@query = query
|
23
24
|
@schema = query.schema
|
24
25
|
@response_path = []
|
@@ -32,6 +33,9 @@ module GraphQL
|
|
32
33
|
# @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
|
33
34
|
attr_reader :object_types
|
34
35
|
|
36
|
+
# @return [Array<GraphQL::AnalysisError]
|
37
|
+
attr_reader :rescued_errors
|
38
|
+
|
35
39
|
def visit
|
36
40
|
return unless @document
|
37
41
|
super
|
@@ -239,7 +243,11 @@ module GraphQL
|
|
239
243
|
|
240
244
|
def call_analyzers(method, node, parent)
|
241
245
|
@analyzers.each do |analyzer|
|
242
|
-
|
246
|
+
begin
|
247
|
+
analyzer.public_send(method, node, parent, self)
|
248
|
+
rescue AnalysisError => err
|
249
|
+
@rescued_errors << err
|
250
|
+
end
|
243
251
|
end
|
244
252
|
end
|
245
253
|
|
data/lib/graphql/analysis/ast.rb
CHANGED
@@ -13,7 +13,12 @@ module GraphQL
|
|
13
13
|
module_function
|
14
14
|
|
15
15
|
def use(schema_class)
|
16
|
-
schema_class.analysis_engine
|
16
|
+
if schema_class.analysis_engine == self
|
17
|
+
definition_line = caller(2, 1).first
|
18
|
+
warn("GraphQL::Analysis::AST is now the default; remove `use GraphQL::Analysis::AST` from the schema definition (#{definition_line})")
|
19
|
+
else
|
20
|
+
schema_class.analysis_engine = self
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
# Analyze a multiplex, and all queries within.
|
@@ -67,7 +72,11 @@ module GraphQL
|
|
67
72
|
|
68
73
|
visitor.visit
|
69
74
|
|
70
|
-
|
75
|
+
if visitor.rescued_errors.any?
|
76
|
+
visitor.rescued_errors
|
77
|
+
else
|
78
|
+
query_analyzers.map(&:result)
|
79
|
+
end
|
71
80
|
else
|
72
81
|
[]
|
73
82
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Backtrace
|
4
|
+
module LegacyTracer
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Implement the {GraphQL::Tracing} API.
|
8
|
+
def trace(key, metadata)
|
9
|
+
case key
|
10
|
+
when "lex", "parse"
|
11
|
+
# No context here, don't have a query yet
|
12
|
+
nil
|
13
|
+
when "execute_multiplex", "analyze_multiplex"
|
14
|
+
# No query context yet
|
15
|
+
nil
|
16
|
+
when "validate", "analyze_query", "execute_query", "execute_query_lazy"
|
17
|
+
query = metadata[:query] || metadata[:queries].first
|
18
|
+
push_data = query
|
19
|
+
multiplex = query.multiplex
|
20
|
+
when "execute_field", "execute_field_lazy"
|
21
|
+
# The interpreter passes `query:`, legacy passes `context:`
|
22
|
+
context = metadata[:context] || ((q = metadata[:query]) && q.context)
|
23
|
+
push_data = context
|
24
|
+
multiplex = context.query.multiplex
|
25
|
+
else
|
26
|
+
# Custom key, no backtrace data for this
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
if push_data
|
31
|
+
multiplex.context[:last_graphql_backtrace_context] = push_data
|
32
|
+
end
|
33
|
+
|
34
|
+
if key == "execute_multiplex"
|
35
|
+
begin
|
36
|
+
yield
|
37
|
+
rescue StandardError => err
|
38
|
+
# This is an unhandled error from execution,
|
39
|
+
# Re-raise it with a GraphQL trace.
|
40
|
+
potential_context = metadata[:multiplex].context[:last_graphql_backtrace_context]
|
41
|
+
|
42
|
+
if potential_context.is_a?(GraphQL::Query::Context) || potential_context.is_a?(GraphQL::Query::Context::FieldResolutionContext)
|
43
|
+
raise TracedError.new(err, potential_context)
|
44
|
+
else
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
ensure
|
48
|
+
metadata[:multiplex].context.delete(:last_graphql_backtrace_context)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -79,6 +79,25 @@ module GraphQL
|
|
79
79
|
# @return [Array] 5 items for a backtrace table (not `key`)
|
80
80
|
def build_rows(context_entry, rows:, top: false)
|
81
81
|
case context_entry
|
82
|
+
when Backtrace::Frame
|
83
|
+
field_alias = context_entry.ast_node.respond_to?(:alias) && context_entry.ast_node.alias
|
84
|
+
value = if top && @override_value
|
85
|
+
@override_value
|
86
|
+
else
|
87
|
+
@context.query.context.namespace(:interpreter)[:runtime].value_at(context_entry.path)
|
88
|
+
end
|
89
|
+
rows << [
|
90
|
+
"#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
|
91
|
+
"#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
|
92
|
+
"#{context_entry.object.object.inspect}",
|
93
|
+
context_entry.arguments.to_h.inspect,
|
94
|
+
Backtrace::InspectResult.inspect_result(value),
|
95
|
+
]
|
96
|
+
if (parent = context_entry.parent_frame)
|
97
|
+
build_rows(parent, rows: rows)
|
98
|
+
else
|
99
|
+
rows
|
100
|
+
end
|
82
101
|
when GraphQL::Query::Context::FieldResolutionContext
|
83
102
|
ctx = context_entry
|
84
103
|
field_name = "#{ctx.irep_node.owner_type.name}.#{ctx.field.name}"
|
@@ -112,15 +131,16 @@ module GraphQL
|
|
112
131
|
if object.is_a?(GraphQL::Schema::Object)
|
113
132
|
object = object.object
|
114
133
|
end
|
134
|
+
value = context_entry.namespace(:interpreter)[:runtime].value_at([])
|
115
135
|
rows << [
|
116
136
|
"#{position}",
|
117
137
|
"#{op_type}#{op_name ? " #{op_name}" : ""}",
|
118
138
|
"#{object.inspect}",
|
119
139
|
query.variables.to_h.inspect,
|
120
|
-
Backtrace::InspectResult.inspect_result(
|
140
|
+
Backtrace::InspectResult.inspect_result(value),
|
121
141
|
]
|
122
142
|
else
|
123
|
-
raise "Unexpected get_rows subject #{context_entry.inspect}"
|
143
|
+
raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
|
124
144
|
end
|
125
145
|
end
|
126
146
|
end
|
@@ -1,46 +1,77 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
class Backtrace
|
4
|
+
# TODO this is not fiber-friendly
|
4
5
|
module Tracer
|
5
6
|
module_function
|
6
7
|
|
7
8
|
# Implement the {GraphQL::Tracing} API.
|
8
9
|
def trace(key, metadata)
|
9
|
-
|
10
|
+
case key
|
10
11
|
when "lex", "parse"
|
11
12
|
# No context here, don't have a query yet
|
12
13
|
nil
|
13
14
|
when "execute_multiplex", "analyze_multiplex"
|
14
|
-
|
15
|
+
# No query context yet
|
16
|
+
nil
|
15
17
|
when "validate", "analyze_query", "execute_query", "execute_query_lazy"
|
16
|
-
metadata[:query] || metadata[:queries]
|
18
|
+
query = metadata[:query] || metadata[:queries].first
|
19
|
+
push_key = []
|
20
|
+
push_data = query
|
21
|
+
multiplex = query.multiplex
|
17
22
|
when "execute_field", "execute_field_lazy"
|
18
|
-
|
19
|
-
|
23
|
+
query = metadata[:query] || raise(ArgumentError, "Add `legacy: true` to use GraphQL::Backtrace without the interpreter runtime.")
|
24
|
+
context = query.context
|
25
|
+
multiplex = query.multiplex
|
26
|
+
push_key = metadata[:path].reject { |i| i.is_a?(Integer) }
|
27
|
+
parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]
|
28
|
+
if parent_frame.nil?
|
29
|
+
p push_key
|
30
|
+
binding.pry
|
31
|
+
end
|
32
|
+
if parent_frame.is_a?(GraphQL::Query)
|
33
|
+
parent_frame = parent_frame.context
|
34
|
+
end
|
35
|
+
|
36
|
+
push_data = Frame.new(
|
37
|
+
query: query,
|
38
|
+
path: push_key,
|
39
|
+
ast_node: metadata[:ast_node],
|
40
|
+
field: metadata[:field],
|
41
|
+
object: metadata[:object],
|
42
|
+
arguments: metadata[:arguments],
|
43
|
+
parent_frame: parent_frame,
|
44
|
+
)
|
20
45
|
else
|
21
46
|
# Custom key, no backtrace data for this
|
22
47
|
nil
|
23
48
|
end
|
24
49
|
|
25
50
|
if push_data
|
26
|
-
|
51
|
+
multiplex.context[:graphql_backtrace_contexts][push_key] = push_data
|
52
|
+
multiplex.context[:last_graphql_backtrace_context] = push_data
|
27
53
|
end
|
28
54
|
|
29
55
|
if key == "execute_multiplex"
|
56
|
+
multiplex_context = metadata[:multiplex].context
|
57
|
+
multiplex_context[:graphql_backtrace_contexts] = {}
|
30
58
|
begin
|
31
59
|
yield
|
32
60
|
rescue StandardError => err
|
33
61
|
# This is an unhandled error from execution,
|
34
62
|
# Re-raise it with a GraphQL trace.
|
35
|
-
potential_context =
|
63
|
+
potential_context = multiplex_context[:last_graphql_backtrace_context]
|
36
64
|
|
37
|
-
if potential_context.is_a?(GraphQL::Query::Context) ||
|
65
|
+
if potential_context.is_a?(GraphQL::Query::Context) ||
|
66
|
+
potential_context.is_a?(GraphQL::Query::Context::FieldResolutionContext) ||
|
67
|
+
potential_context.is_a?(Backtrace::Frame)
|
38
68
|
raise TracedError.new(err, potential_context)
|
39
69
|
else
|
40
70
|
raise
|
41
71
|
end
|
42
72
|
ensure
|
43
|
-
|
73
|
+
multiplex_context.delete(:graphql_backtrace_contexts)
|
74
|
+
multiplex_context.delete(:last_graphql_backtrace_context)
|
44
75
|
end
|
45
76
|
else
|
46
77
|
yield
|
data/lib/graphql/backtrace.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/backtrace/inspect_result"
|
3
|
+
require "graphql/backtrace/legacy_tracer"
|
3
4
|
require "graphql/backtrace/table"
|
4
5
|
require "graphql/backtrace/traced_error"
|
5
6
|
require "graphql/backtrace/tracer"
|
@@ -9,13 +10,12 @@ module GraphQL
|
|
9
10
|
# {TracedError} provides a GraphQL backtrace with arguments and return values.
|
10
11
|
# The underlying error is available as {TracedError#cause}.
|
11
12
|
#
|
12
|
-
# WARNING: {.enable} is not threadsafe because {GraphQL::Tracing.install} is not threadsafe.
|
13
|
-
#
|
14
13
|
# @example toggling backtrace annotation
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
14
|
+
# class MySchema < GraphQL::Schema
|
15
|
+
# if Rails.env.development? || Rails.env.test?
|
16
|
+
# use GraphQL::Backtrace
|
17
|
+
# end
|
18
|
+
# end
|
19
19
|
#
|
20
20
|
class Backtrace
|
21
21
|
include Enumerable
|
@@ -23,19 +23,13 @@ module GraphQL
|
|
23
23
|
|
24
24
|
def_delegators :to_a, :each, :[]
|
25
25
|
|
26
|
-
def self.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
GraphQL::Tracing.uninstall(Backtrace::Tracer)
|
34
|
-
nil
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.use(schema_defn)
|
38
|
-
schema_defn.tracer(self::Tracer)
|
26
|
+
def self.use(schema_defn, legacy: false)
|
27
|
+
tracer = if legacy
|
28
|
+
self::LegacyTracer
|
29
|
+
else
|
30
|
+
self::Tracer
|
31
|
+
end
|
32
|
+
schema_defn.tracer(tracer)
|
39
33
|
end
|
40
34
|
|
41
35
|
def initialize(context, value: nil)
|
@@ -51,5 +45,20 @@ module GraphQL
|
|
51
45
|
def to_a
|
52
46
|
@table.to_backtrace
|
53
47
|
end
|
48
|
+
|
49
|
+
# Used for internal bookkeeping
|
50
|
+
# @api private
|
51
|
+
class Frame
|
52
|
+
attr_reader :path, :query, :ast_node, :object, :field, :arguments, :parent_frame
|
53
|
+
def initialize(path:, query:, ast_node:, object:, field:, arguments:, parent_frame:)
|
54
|
+
@path = path
|
55
|
+
@query = query
|
56
|
+
@ast_node = ast_node
|
57
|
+
@field = field
|
58
|
+
@object = object
|
59
|
+
@arguments = arguments
|
60
|
+
@parent_frame = parent_frame
|
61
|
+
end
|
62
|
+
end
|
54
63
|
end
|
55
64
|
end
|
@@ -32,6 +32,7 @@ module GraphQL
|
|
32
32
|
# @param execution_strategy [<#new, #execute>] An execution strategy class
|
33
33
|
# @return [Class<Minitest::Test>] A test suite for this execution strategy
|
34
34
|
def self.build_suite(execution_strategy)
|
35
|
+
warn "#{self} will be removed from GraphQL-Ruby 2.0. There is no replacement, please open an issue on GitHub if you need support."
|
35
36
|
Class.new(Minitest::Test) do
|
36
37
|
class << self
|
37
38
|
attr_accessor :counter_schema, :specification_schema
|
@@ -7,6 +7,8 @@ module GraphQL
|
|
7
7
|
# @param execution_strategy [<#new, #execute>] An execution strategy class
|
8
8
|
# @return [Class<Minitest::Test>] A test suite for this execution strategy
|
9
9
|
def self.build_suite(execution_strategy)
|
10
|
+
warn "#{self} will be removed from GraphQL-Ruby 2.0. There is no replacement, please open an issue on GitHub if you need support."
|
11
|
+
|
10
12
|
Class.new(Minitest::Test) do
|
11
13
|
class << self
|
12
14
|
attr_accessor :lazy_schema
|
@@ -11,6 +11,8 @@ module GraphQL
|
|
11
11
|
# @yieldreturn [GraphQL::Language::Nodes::Document]
|
12
12
|
# @return [Class<Minitest::Test>] A test suite for this parse function
|
13
13
|
def self.build_suite(&block)
|
14
|
+
warn "#{self} will be removed from GraphQL-Ruby 2.0. There is no replacement, please open an issue on GitHub if you need support."
|
15
|
+
|
14
16
|
Class.new(Minitest::Test) do
|
15
17
|
include QueryAssertions
|
16
18
|
include ParseErrorSpecification
|
@@ -8,6 +8,8 @@ module GraphQL
|
|
8
8
|
# @yieldreturn [GraphQL::Language::Nodes::Document]
|
9
9
|
# @return [Class<Minitest::Test>] A test suite for this parse function
|
10
10
|
def self.build_suite(&block)
|
11
|
+
warn "#{self} will be removed from GraphQL-Ruby 2.0. There is no replacement, please open an issue on GitHub if you need support."
|
12
|
+
|
11
13
|
Class.new(Minitest::Test) do
|
12
14
|
@@parse_fn = block
|
13
15
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Dataloader
|
5
|
+
# The default implementation of dataloading -- all no-ops.
|
6
|
+
#
|
7
|
+
# The Dataloader interface isn't public, but it enables
|
8
|
+
# simple internal code while adding the option to add Dataloader.
|
9
|
+
class NullDataloader < Dataloader
|
10
|
+
def enqueue
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
|
14
|
+
# These are all no-ops because code was
|
15
|
+
# executed sychronously.
|
16
|
+
def run; end
|
17
|
+
def yield; end
|
18
|
+
def yielded?; false; end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Dataloader
|
4
|
+
# @see Source#request which returns an instance of this
|
5
|
+
class Request
|
6
|
+
def initialize(source, key)
|
7
|
+
@source = source
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
# Call this method to cause the current Fiber to wait for the results of this request.
|
12
|
+
#
|
13
|
+
# @return [Object] the object loaded for `key`
|
14
|
+
def load
|
15
|
+
if @source.results.key?(@key)
|
16
|
+
@source.results[@key]
|
17
|
+
else
|
18
|
+
@source.sync
|
19
|
+
@source.results[@key]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|