graphql 2.5.18 → 2.5.20
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/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +2 -1
- data/lib/graphql/dashboard.rb +9 -74
- data/lib/graphql/dataloader/null_dataloader.rb +7 -3
- data/lib/graphql/execution/batching/field_compatibility.rb +150 -0
- data/lib/graphql/execution/batching/field_resolve_step.rb +408 -0
- data/lib/graphql/execution/batching/prepare_object_step.rb +112 -0
- data/lib/graphql/execution/batching/runner.rb +352 -0
- data/lib/graphql/execution/batching/selections_step.rb +37 -0
- data/lib/graphql/execution/batching.rb +62 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/entry_points.rb +6 -2
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_null_error.rb +11 -5
- data/lib/graphql/query/context.rb +3 -2
- data/lib/graphql/query/null_context.rb +9 -3
- data/lib/graphql/schema/argument.rb +4 -0
- data/lib/graphql/schema/build_from_definition.rb +26 -6
- data/lib/graphql/schema/field.rb +76 -1
- data/lib/graphql/schema/member/has_dataloader.rb +9 -0
- data/lib/graphql/schema/member/has_fields.rb +3 -0
- data/lib/graphql/schema/resolver.rb +3 -1
- data/lib/graphql/schema/visibility.rb +1 -1
- data/lib/graphql/schema.rb +33 -7
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
- data/lib/graphql/tracing/detailed_trace.rb +20 -5
- data/lib/graphql/tracing/perfetto_trace.rb +48 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +8 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +4 -3
- data/lib/graphql/types/relay/has_node_field.rb +5 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +5 -8
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +14 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fab0bc8a5ed6bcbe53f688f9d0209a7c05808f9dd35fe487407825ee7b5b4000
|
|
4
|
+
data.tar.gz: 460c780b3ccc6c3b173aef304448c13c84e7f3e28f6b1eb2785e483ee615c848
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8919741b4446074f12cba8aba4ce72b97bb40e400f969d056629c57f3b94d57bc00cdb187784dec5eda4ce4e6c937e1ea856b7505ad40ce0692b2c2c596df43e
|
|
7
|
+
data.tar.gz: a559f8b81eb3148a85cc6e7aeb86023efb4f93ee9230fb72dc9e631e9cda7ae88dd05ab10af250bde8d4620eeb34804b4c81f78c30c58e9c670c58bd26090d01
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/active_record'
|
|
3
|
+
|
|
4
|
+
module Graphql
|
|
5
|
+
module Generators
|
|
6
|
+
class DetailedTraceGenerator < ::Rails::Generators::Base
|
|
7
|
+
include ::Rails::Generators::Migration
|
|
8
|
+
desc "Install GraphQL::Tracing::DetailedTrace for your schema"
|
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
10
|
+
|
|
11
|
+
class_option :redis,
|
|
12
|
+
type: :boolean,
|
|
13
|
+
default: false,
|
|
14
|
+
desc: "Use Redis for persistence instead of ActiveRecord"
|
|
15
|
+
|
|
16
|
+
def self.next_migration_number(dirname)
|
|
17
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def install_detailed_traces
|
|
21
|
+
|
|
22
|
+
schema_glob = File.expand_path("app/graphql/*_schema.rb", destination_root)
|
|
23
|
+
schema_file = Dir.glob(schema_glob).first
|
|
24
|
+
if !schema_file
|
|
25
|
+
raise ArgumentError, "Failed to find schema definition file (checked: #{schema_glob.inspect})"
|
|
26
|
+
end
|
|
27
|
+
schema_file_match = /( *)class ([A-Za-z:]+) < GraphQL::Schema/.match(File.read(schema_file))
|
|
28
|
+
schema_name = schema_file_match[2]
|
|
29
|
+
indent = schema_file_match[1] + " "
|
|
30
|
+
|
|
31
|
+
if !options.redis?
|
|
32
|
+
migration_template 'create_graphql_detailed_traces.erb', 'db/migrate/create_graphql_detailed_traces.rb'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
log :add_detailed_traces_plugin
|
|
36
|
+
sentinel = /< GraphQL::Schema\s*\n/m
|
|
37
|
+
code = <<-RUBY
|
|
38
|
+
#{indent}use GraphQL::Tracing::DetailedTrace#{options.redis? ? ", redis: raise(\"TODO: pass a connection to a persistent redis database\")" : ""}, limit: 50
|
|
39
|
+
|
|
40
|
+
#{indent}# When this returns true, DetailedTrace will trace the query
|
|
41
|
+
#{indent}# Could use `query.context`, `query.selected_operation_name`, `query.query_string` here
|
|
42
|
+
#{indent}# Could call out to Flipper, etc
|
|
43
|
+
#{indent}def self.detailed_trace?(query)
|
|
44
|
+
#{indent} rand <= 0.000_1 # one in ten thousand
|
|
45
|
+
#{indent}end
|
|
46
|
+
|
|
47
|
+
RUBY
|
|
48
|
+
|
|
49
|
+
in_root do
|
|
50
|
+
inject_into_file schema_file, code, after: sentinel, force: false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
routes_source = File.read(File.expand_path("config/routes.rb", destination_root))
|
|
54
|
+
already_has_dashboard = routes_source.include?("GraphQL::Dashboard") ||
|
|
55
|
+
routes_source.include?("Schema.dashboard") ||
|
|
56
|
+
routes_source.include?("GraphQL::Pro::Routes::Lazy")
|
|
57
|
+
|
|
58
|
+
if (!already_has_dashboard || behavior == :revoke)
|
|
59
|
+
log :route, "GraphQL::Dashboard"
|
|
60
|
+
shell.mute do
|
|
61
|
+
route <<~RUBY
|
|
62
|
+
# TODO: add authorization to this route and expose it in production
|
|
63
|
+
# See https://graphql-ruby.org/pro/dashboard.html#authorizing-the-dashboard
|
|
64
|
+
if Rails.env.development?
|
|
65
|
+
mount GraphQL::Dashboard, at: "/graphql/dashboard", schema: #{schema_name.inspect}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
RUBY
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
gem("google-protobuf")
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class CreateGraphqlDetailedTraces < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :graphql_detailed_traces, force: true do |t|
|
|
4
|
+
t.bigint :begin_ms, null: false
|
|
5
|
+
t.float :duration_ms, null: false
|
|
6
|
+
t.binary :trace_data, null: false
|
|
7
|
+
t.string :operation_name, null: false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "action_controller"
|
|
3
|
+
|
|
4
|
+
module Graphql
|
|
5
|
+
class Dashboard < Rails::Engine
|
|
6
|
+
class ApplicationController < ActionController::Base
|
|
7
|
+
protect_from_forgery with: :exception
|
|
8
|
+
prepend_view_path(File.expand_path("../views", __FILE__))
|
|
9
|
+
|
|
10
|
+
content_security_policy do |policy|
|
|
11
|
+
policy.default_src(:self) if policy.default_src(*policy.default_src).blank?
|
|
12
|
+
policy.connect_src(:self) if policy.connect_src(*policy.connect_src).blank?
|
|
13
|
+
policy.base_uri(:none) if policy.base_uri(*policy.base_uri).blank?
|
|
14
|
+
policy.font_src(:self) if policy.font_src(*policy.font_src).blank?
|
|
15
|
+
policy.img_src(:self, :data) if policy.img_src(*policy.img_src).blank?
|
|
16
|
+
policy.object_src(:none) if policy.object_src(*policy.object_src).blank?
|
|
17
|
+
policy.script_src(:self) if policy.script_src(*policy.script_src).blank?
|
|
18
|
+
policy.style_src(:self) if policy.style_src(*policy.style_src).blank?
|
|
19
|
+
policy.form_action(:self) if policy.form_action(*policy.form_action).blank?
|
|
20
|
+
policy.frame_ancestors(:none) if policy.frame_ancestors(*policy.frame_ancestors).blank?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def schema_class
|
|
24
|
+
@schema_class ||= begin
|
|
25
|
+
schema_param = request.query_parameters["schema"] || params[:schema]
|
|
26
|
+
case schema_param
|
|
27
|
+
when Class
|
|
28
|
+
schema_param
|
|
29
|
+
when String
|
|
30
|
+
schema_param.constantize
|
|
31
|
+
else
|
|
32
|
+
raise "Missing `params[:schema]`, please provide a class or string to `mount GraphQL::Dashboard, schema: ...`"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
helper_method :schema_class
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
ActiveSupport.run_load_hooks(:graphql_dashboard_application_controller, GraphQL::Dashboard::ApplicationController)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Graphql
|
|
3
|
+
class Dashboard < Rails::Engine
|
|
4
|
+
class StaticsController < ApplicationController
|
|
5
|
+
skip_forgery_protection
|
|
6
|
+
# Use an explicit list of files to avoid any chance of reading other files from disk
|
|
7
|
+
STATICS = {}
|
|
8
|
+
|
|
9
|
+
[
|
|
10
|
+
"icon.png",
|
|
11
|
+
"header-icon.png",
|
|
12
|
+
"charts.min.css",
|
|
13
|
+
"dashboard.css",
|
|
14
|
+
"dashboard.js",
|
|
15
|
+
"bootstrap-5.3.3.min.css",
|
|
16
|
+
"bootstrap-5.3.3.min.js",
|
|
17
|
+
].each do |static_file|
|
|
18
|
+
STATICS[static_file] = File.expand_path("../statics/#{static_file}", __FILE__)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def show
|
|
22
|
+
expires_in 1.year, public: true
|
|
23
|
+
if (filepath = STATICS[params[:id]])
|
|
24
|
+
render file: filepath
|
|
25
|
+
else
|
|
26
|
+
head :not_found
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require_relative "./installable"
|
|
2
3
|
module Graphql
|
|
3
4
|
class Dashboard < Rails::Engine
|
|
4
5
|
module Subscriptions
|
|
@@ -6,7 +7,7 @@ module Graphql
|
|
|
6
7
|
include Installable
|
|
7
8
|
|
|
8
9
|
def feature_installed?
|
|
9
|
-
schema_class.subscriptions.is_a?(GraphQL::Pro::Subscriptions)
|
|
10
|
+
defined?(GraphQL::Pro::Subscriptions) && schema_class.subscriptions.is_a?(GraphQL::Pro::Subscriptions)
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
INSTALLABLE_COMPONENT_HEADER_HTML = "GraphQL-Pro Subscriptions aren't installed on this schema yet.".html_safe
|
data/lib/graphql/dashboard.rb
CHANGED
|
@@ -35,6 +35,15 @@ module Graphql
|
|
|
35
35
|
class Dashboard < Rails::Engine
|
|
36
36
|
engine_name "graphql_dashboard"
|
|
37
37
|
isolate_namespace(Graphql::Dashboard)
|
|
38
|
+
|
|
39
|
+
autoload :ApplicationController, "graphql/dashboard/application_controller"
|
|
40
|
+
autoload :LandingsController, "graphql/dashboard/landings_controller"
|
|
41
|
+
autoload :StaticsController, "graphql/dashboard/statics_controller"
|
|
42
|
+
autoload :DetailedTraces, "graphql/dashboard/detailed_traces"
|
|
43
|
+
autoload :Subscriptions, "graphql/dashboard/subscriptions"
|
|
44
|
+
autoload :OperationStore, "graphql/dashboard/operation_store"
|
|
45
|
+
autoload :Limiters, "graphql/dashboard/limiters"
|
|
46
|
+
|
|
38
47
|
routes do
|
|
39
48
|
root "landings#show"
|
|
40
49
|
resources :statics, only: :show, constraints: { id: /[0-9A-Za-z\-.]+/ }
|
|
@@ -77,85 +86,11 @@ module Graphql
|
|
|
77
86
|
resources :subscriptions, only: [:show], constraints: { id: /[a-zA-Z0-9\-]+/ }
|
|
78
87
|
post "/subscriptions/clear_all", to: "subscriptions#clear_all", as: :clear_all
|
|
79
88
|
end
|
|
80
|
-
|
|
81
|
-
ApplicationController.include(Dashboard.routes.url_helpers)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
class ApplicationController < ActionController::Base
|
|
85
|
-
protect_from_forgery with: :exception
|
|
86
|
-
prepend_view_path(File.join(__FILE__, "../dashboard/views"))
|
|
87
|
-
|
|
88
|
-
content_security_policy do |policy|
|
|
89
|
-
policy.default_src(:self) if policy.default_src(*policy.default_src).blank?
|
|
90
|
-
policy.connect_src(:self) if policy.connect_src(*policy.connect_src).blank?
|
|
91
|
-
policy.base_uri(:none) if policy.base_uri(*policy.base_uri).blank?
|
|
92
|
-
policy.font_src(:self) if policy.font_src(*policy.font_src).blank?
|
|
93
|
-
policy.img_src(:self, :data) if policy.img_src(*policy.img_src).blank?
|
|
94
|
-
policy.object_src(:none) if policy.object_src(*policy.object_src).blank?
|
|
95
|
-
policy.script_src(:self) if policy.script_src(*policy.script_src).blank?
|
|
96
|
-
policy.style_src(:self) if policy.style_src(*policy.style_src).blank?
|
|
97
|
-
policy.form_action(:self) if policy.form_action(*policy.form_action).blank?
|
|
98
|
-
policy.frame_ancestors(:none) if policy.frame_ancestors(*policy.frame_ancestors).blank?
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def schema_class
|
|
102
|
-
@schema_class ||= begin
|
|
103
|
-
schema_param = request.query_parameters["schema"] || params[:schema]
|
|
104
|
-
case schema_param
|
|
105
|
-
when Class
|
|
106
|
-
schema_param
|
|
107
|
-
when String
|
|
108
|
-
schema_param.constantize
|
|
109
|
-
else
|
|
110
|
-
raise "Missing `params[:schema]`, please provide a class or string to `mount GraphQL::Dashboard, schema: ...`"
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
helper_method :schema_class
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
class LandingsController < ApplicationController
|
|
118
|
-
def show
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
class StaticsController < ApplicationController
|
|
123
|
-
skip_after_action :verify_same_origin_request
|
|
124
|
-
# Use an explicit list of files to avoid any chance of reading other files from disk
|
|
125
|
-
STATICS = {}
|
|
126
|
-
|
|
127
|
-
[
|
|
128
|
-
"icon.png",
|
|
129
|
-
"header-icon.png",
|
|
130
|
-
"charts.min.css",
|
|
131
|
-
"dashboard.css",
|
|
132
|
-
"dashboard.js",
|
|
133
|
-
"bootstrap-5.3.3.min.css",
|
|
134
|
-
"bootstrap-5.3.3.min.js",
|
|
135
|
-
].each do |static_file|
|
|
136
|
-
STATICS[static_file] = File.expand_path("../dashboard/statics/#{static_file}", __FILE__)
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def show
|
|
140
|
-
expires_in 1.year, public: true
|
|
141
|
-
if (filepath = STATICS[params[:id]])
|
|
142
|
-
render file: filepath
|
|
143
|
-
else
|
|
144
|
-
head :not_found
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
89
|
end
|
|
148
90
|
end
|
|
149
91
|
end
|
|
150
92
|
|
|
151
|
-
require 'graphql/dashboard/detailed_traces'
|
|
152
|
-
require 'graphql/dashboard/limiters'
|
|
153
|
-
require 'graphql/dashboard/operation_store'
|
|
154
|
-
require 'graphql/dashboard/subscriptions'
|
|
155
|
-
|
|
156
93
|
# Rails expects the engine to be called `Graphql::Dashboard`,
|
|
157
94
|
# but `GraphQL::Dashboard` is consistent with this gem's naming.
|
|
158
95
|
# So define both constants to refer to the same class.
|
|
159
96
|
GraphQL::Dashboard = Graphql::Dashboard
|
|
160
|
-
|
|
161
|
-
ActiveSupport.run_load_hooks(:graphql_dashboard_application_controller, GraphQL::Dashboard::ApplicationController)
|
|
@@ -37,13 +37,17 @@ module GraphQL
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def run_isolated
|
|
40
|
-
|
|
40
|
+
# Reuse this instance because execution code may already have a reference to _this_ `dataloader` inside the given block.
|
|
41
|
+
prev_lazies_at_depth = @lazies_at_depth
|
|
42
|
+
@lazies_at_depth = @lazies_at_depth.dup.clear
|
|
41
43
|
res = nil
|
|
42
|
-
|
|
44
|
+
append_job {
|
|
43
45
|
res = yield
|
|
44
46
|
}
|
|
45
|
-
|
|
47
|
+
run
|
|
46
48
|
res
|
|
49
|
+
ensure
|
|
50
|
+
@lazies_at_depth = prev_lazies_at_depth
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
def clear_cache; end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Execution
|
|
4
|
+
module Batching
|
|
5
|
+
module FieldCompatibility
|
|
6
|
+
def resolve_all_load_arguments(frs, object_from_id_receiver, arguments, argument_owner, context)
|
|
7
|
+
arg_defns = context.types.arguments(argument_owner)
|
|
8
|
+
arg_defns.each do |arg_defn|
|
|
9
|
+
if arg_defn.loads
|
|
10
|
+
if arguments.key?(arg_defn.keyword)
|
|
11
|
+
id = arguments.delete(arg_defn.keyword)
|
|
12
|
+
if !id.nil?
|
|
13
|
+
value = if arg_defn.type.list?
|
|
14
|
+
id.map { |inner_id|
|
|
15
|
+
object_from_id_receiver.load_and_authorize_application_object(arg_defn, inner_id, context)
|
|
16
|
+
}
|
|
17
|
+
else
|
|
18
|
+
object_from_id_receiver.load_and_authorize_application_object(arg_defn, id, context)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if frs.runner.resolves_lazies
|
|
22
|
+
value = frs.sync(value)
|
|
23
|
+
end
|
|
24
|
+
if value.is_a?(GraphQL::Error)
|
|
25
|
+
value.path = frs.path
|
|
26
|
+
return value
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
value = nil
|
|
30
|
+
end
|
|
31
|
+
arguments[arg_defn.keyword] = value
|
|
32
|
+
end
|
|
33
|
+
elsif (input_type = arg_defn.type.unwrap).kind.input_object? &&
|
|
34
|
+
(value = arguments[arg_defn.keyword]) # TODO lists
|
|
35
|
+
resolve_all_load_arguments(frs, object_from_id_receiver, value, input_type, context)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def resolve_batch(frs, objects, context, kwargs)
|
|
42
|
+
if @batch_mode && !:direct_send.equal?(@batch_mode)
|
|
43
|
+
return super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if !@resolver_class
|
|
47
|
+
maybe_err = resolve_all_load_arguments(frs, self, kwargs, self, context)
|
|
48
|
+
if maybe_err
|
|
49
|
+
return maybe_err
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
if extras.include?(:lookahead)
|
|
53
|
+
if kwargs.frozen?
|
|
54
|
+
kwargs = kwargs.dup
|
|
55
|
+
end
|
|
56
|
+
kwargs[:lookahead] = Execution::Lookahead.new(
|
|
57
|
+
query: context.query,
|
|
58
|
+
ast_nodes: frs.ast_nodes || Array(frs.ast_node),
|
|
59
|
+
field: self,
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if extras.include?(:ast_node)
|
|
64
|
+
if kwargs.frozen?
|
|
65
|
+
kwargs = kwargs.dup
|
|
66
|
+
end
|
|
67
|
+
kwargs[:ast_node] = frs.ast_node
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if @owner.method_defined?(@resolver_method)
|
|
71
|
+
results = []
|
|
72
|
+
frs.selections_step.graphql_objects.each_with_index do |obj_inst, idx|
|
|
73
|
+
if frs.object_is_authorized[idx]
|
|
74
|
+
if dynamic_introspection
|
|
75
|
+
obj_inst = @owner.wrap(obj_inst, context)
|
|
76
|
+
end
|
|
77
|
+
results << with_extensions(obj_inst, kwargs, context) do |obj, ruby_kwargs|
|
|
78
|
+
if ruby_kwargs.empty?
|
|
79
|
+
obj.public_send(@resolver_method)
|
|
80
|
+
else
|
|
81
|
+
obj.public_send(@resolver_method, **ruby_kwargs)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
results
|
|
87
|
+
elsif @resolver_class
|
|
88
|
+
objects.map do |o|
|
|
89
|
+
resolver_inst_kwargs = kwargs.dup
|
|
90
|
+
resolver_inst = @resolver_class.new(object: o, context: context, field: self)
|
|
91
|
+
maybe_err = resolve_all_load_arguments(frs, resolver_inst, resolver_inst_kwargs, self, context)
|
|
92
|
+
if maybe_err
|
|
93
|
+
next maybe_err
|
|
94
|
+
end
|
|
95
|
+
resolver_inst_kwargs = if @resolver_class < Schema::HasSingleInputArgument
|
|
96
|
+
resolver_inst_kwargs[:input]
|
|
97
|
+
else
|
|
98
|
+
resolver_inst_kwargs
|
|
99
|
+
end
|
|
100
|
+
with_extensions(o, resolver_inst_kwargs, context) do |obj, ruby_kwargs|
|
|
101
|
+
resolver_inst.object = obj
|
|
102
|
+
resolver_inst.prepared_arguments = ruby_kwargs
|
|
103
|
+
is_authed, new_return_value = resolver_inst.authorized?(**ruby_kwargs)
|
|
104
|
+
if frs.runner.resolves_lazies && frs.runner.schema.lazy?(is_authed)
|
|
105
|
+
is_authed, new_return_value = frs.runner.schema.sync_lazy(is_authed)
|
|
106
|
+
end
|
|
107
|
+
if is_authed
|
|
108
|
+
resolver_inst.call_resolve(ruby_kwargs)
|
|
109
|
+
else
|
|
110
|
+
new_return_value
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
rescue RuntimeError => err
|
|
114
|
+
err
|
|
115
|
+
rescue StandardError => stderr
|
|
116
|
+
begin
|
|
117
|
+
context.query.handle_or_reraise(stderr)
|
|
118
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
119
|
+
ex_err
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
elsif objects.first.is_a?(Hash)
|
|
123
|
+
objects.map { |o| o[method_sym] || o[graphql_name] }
|
|
124
|
+
elsif objects.first.is_a?(Interpreter::RawValue)
|
|
125
|
+
objects
|
|
126
|
+
else
|
|
127
|
+
# need to use connection extension if present, and extensions expect object type instances
|
|
128
|
+
if extensions.empty?
|
|
129
|
+
objects.map { |o| o.public_send(@method_sym)}
|
|
130
|
+
else
|
|
131
|
+
results = []
|
|
132
|
+
frs.selections_step.graphql_objects.each_with_index do |obj_inst, idx|
|
|
133
|
+
if frs.object_is_authorized[idx]
|
|
134
|
+
results << with_extensions(obj_inst, EmptyObjects::EMPTY_HASH, context) do |obj, arguments|
|
|
135
|
+
if arguments.empty?
|
|
136
|
+
obj.object.public_send(@method_sym)
|
|
137
|
+
else
|
|
138
|
+
obj.object.public_send(@method_sym, **arguments)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
results
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|