graphql 2.4.3 → 2.4.13
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/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/visitor.rb +38 -41
- data/lib/graphql/analysis.rb +15 -12
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +95 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/dashboard.css +3 -0
- data/lib/graphql/dashboard/statics/dashboard.js +78 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +63 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +60 -0
- data/lib/graphql/dashboard.rb +142 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
- data/lib/graphql/dataloader/active_record_source.rb +26 -0
- data/lib/graphql/dataloader/async_dataloader.rb +21 -9
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/source.rb +3 -3
- data/lib/graphql/dataloader.rb +43 -14
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +67 -40
- data/lib/graphql/execution/interpreter.rb +16 -6
- data/lib/graphql/execution/multiplex.rb +0 -4
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +5 -15
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -7
- data/lib/graphql/language/lexer.rb +11 -4
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +2 -2
- data/lib/graphql/language/printer.rb +8 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +6 -5
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +20 -22
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.rb +1 -1
- data/lib/graphql/schema/argument.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +8 -7
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +12 -12
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +3 -1
- data/lib/graphql/schema/input_object.rb +70 -34
- data/lib/graphql/schema/interface.rb +3 -2
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +25 -17
- data/lib/graphql/schema/member/has_dataloader.rb +60 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +19 -1
- data/lib/graphql/schema/member/has_interfaces.rb +5 -5
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +11 -10
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/visibility/migration.rb +1 -0
- data/lib/graphql/schema/visibility/profile.rb +69 -237
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +169 -28
- data/lib/graphql/schema/warden.rb +18 -5
- data/lib/graphql/schema.rb +90 -43
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +1 -0
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +2 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +7 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -0
- data/lib/graphql/tracing/appsignal_trace.rb +12 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +11 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/new_relic_trace.rb +164 -41
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +4 -0
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +737 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +31 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +11 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +11 -0
- data/lib/graphql/tracing/statsd_trace.rb +15 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +128 -1
- data/lib/graphql/tracing.rb +30 -30
- data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +55 -47
- metadata +152 -10
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/schema/null_mask.rb +0 -11
@@ -7,6 +7,15 @@ module GraphQL
|
|
7
7
|
class Object < GraphQL::Schema::Member
|
8
8
|
extend GraphQL::Schema::Member::HasFields
|
9
9
|
extend GraphQL::Schema::Member::HasInterfaces
|
10
|
+
include Member::HasDataloader
|
11
|
+
|
12
|
+
# Raised when an Object doesn't have any field defined and hasn't explicitly opted out of this requirement
|
13
|
+
class FieldsAreRequiredError < GraphQL::Error
|
14
|
+
def initialize(object_type)
|
15
|
+
message = "Object types must have fields, but #{object_type.graphql_name} doesn't have any. Define a field for this type, remove it from your schema, or add `has_no_fields(true)` to its definition."
|
16
|
+
super(message)
|
17
|
+
end
|
18
|
+
end
|
10
19
|
|
11
20
|
# @return [Object] the application object this type is wrapping
|
12
21
|
attr_reader :object
|
@@ -57,20 +66,28 @@ module GraphQL
|
|
57
66
|
# @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
|
58
67
|
# @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
|
59
68
|
def authorized_new(object, context)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
context.query.current_trace.begin_authorized(self, object, context)
|
70
|
+
begin
|
71
|
+
maybe_lazy_auth_val = context.query.current_trace.authorized(query: context.query, type: self, object: object) do
|
72
|
+
begin
|
73
|
+
authorized?(object, context)
|
74
|
+
rescue GraphQL::UnauthorizedError => err
|
75
|
+
context.schema.unauthorized_object(err)
|
76
|
+
rescue StandardError => err
|
77
|
+
context.query.handle_or_reraise(err)
|
78
|
+
end
|
67
79
|
end
|
80
|
+
ensure
|
81
|
+
context.query.current_trace.end_authorized(self, object, context, maybe_lazy_auth_val)
|
68
82
|
end
|
69
83
|
|
70
84
|
auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
|
71
85
|
GraphQL::Execution::Lazy.new do
|
86
|
+
context.query.current_trace.begin_authorized(self, object, context)
|
72
87
|
context.query.current_trace.authorized_lazy(query: context.query, type: self, object: object) do
|
73
|
-
context.schema.sync_lazy(maybe_lazy_auth_val)
|
88
|
+
res = context.schema.sync_lazy(maybe_lazy_auth_val)
|
89
|
+
context.query.current_trace.end_authorized(self, object, context, res)
|
90
|
+
res
|
74
91
|
end
|
75
92
|
end
|
76
93
|
else
|
@@ -27,6 +27,7 @@ module GraphQL
|
|
27
27
|
include Schema::Member::HasPath
|
28
28
|
extend Schema::Member::HasPath
|
29
29
|
extend Schema::Member::HasDirectives
|
30
|
+
include Schema::Member::HasDataloader
|
30
31
|
|
31
32
|
# @param object [Object] The application object that this field is being resolved on
|
32
33
|
# @param context [GraphQL::Query::Context]
|
@@ -49,11 +50,6 @@ module GraphQL
|
|
49
50
|
# @return [GraphQL::Query::Context]
|
50
51
|
attr_reader :context
|
51
52
|
|
52
|
-
# @return [GraphQL::Dataloader]
|
53
|
-
def dataloader
|
54
|
-
context.dataloader
|
55
|
-
end
|
56
|
-
|
57
53
|
# @return [GraphQL::Schema::Field]
|
58
54
|
attr_reader :field
|
59
55
|
|
@@ -67,7 +63,7 @@ module GraphQL
|
|
67
63
|
# @api private
|
68
64
|
def resolve_with_support(**args)
|
69
65
|
# First call the ready? hook which may raise
|
70
|
-
raw_ready_val = if args.
|
66
|
+
raw_ready_val = if !args.empty?
|
71
67
|
ready?(**args)
|
72
68
|
else
|
73
69
|
ready?
|
@@ -88,7 +84,7 @@ module GraphQL
|
|
88
84
|
@prepared_arguments = loaded_args
|
89
85
|
Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
|
90
86
|
# Then call `authorized?`, which may raise or may return a lazy object
|
91
|
-
raw_authorized_val = if loaded_args.
|
87
|
+
raw_authorized_val = if !loaded_args.empty?
|
92
88
|
authorized?(**loaded_args)
|
93
89
|
else
|
94
90
|
authorized?
|
@@ -117,7 +113,7 @@ module GraphQL
|
|
117
113
|
|
118
114
|
# @api private {GraphQL::Schema::Mutation} uses this to clear the dataloader cache
|
119
115
|
def call_resolve(args_hash)
|
120
|
-
if args_hash.
|
116
|
+
if !args_hash.empty?
|
121
117
|
public_send(self.class.resolve_method, **args_hash)
|
122
118
|
else
|
123
119
|
public_send(self.class.resolve_method)
|
@@ -208,7 +204,7 @@ module GraphQL
|
|
208
204
|
end
|
209
205
|
|
210
206
|
# Avoid returning a lazy if none are needed
|
211
|
-
if prepare_lazies.
|
207
|
+
if !prepare_lazies.empty?
|
212
208
|
GraphQL::Execution::Lazy.all(prepare_lazies).then { prepared_args }
|
213
209
|
else
|
214
210
|
prepared_args
|
@@ -394,7 +390,7 @@ module GraphQL
|
|
394
390
|
if superclass.respond_to?(:extensions)
|
395
391
|
s_exts = superclass.extensions
|
396
392
|
if own_exts
|
397
|
-
if s_exts.
|
393
|
+
if !s_exts.empty?
|
398
394
|
own_exts + s_exts
|
399
395
|
else
|
400
396
|
own_exts
|
@@ -407,6 +403,11 @@ module GraphQL
|
|
407
403
|
end
|
408
404
|
end
|
409
405
|
|
406
|
+
def inherited(child_class)
|
407
|
+
child_class.description(description)
|
408
|
+
super
|
409
|
+
end
|
410
|
+
|
410
411
|
private
|
411
412
|
|
412
413
|
attr_reader :own_extensions
|
@@ -19,13 +19,22 @@ module GraphQL
|
|
19
19
|
# propagate null.
|
20
20
|
null false
|
21
21
|
|
22
|
+
# @api private
|
22
23
|
def initialize(object:, context:, field:)
|
23
24
|
super
|
24
25
|
# Figure out whether this is an update or an initial subscription
|
25
26
|
@mode = context.query.subscription_update? ? :update : :subscribe
|
27
|
+
@subscription_written = false
|
28
|
+
@original_arguments = nil
|
29
|
+
if (subs_ns = context.namespace(:subscriptions)) &&
|
30
|
+
(sub_insts = subs_ns[:subscriptions])
|
31
|
+
sub_insts[context.current_path] = self
|
32
|
+
end
|
26
33
|
end
|
27
34
|
|
35
|
+
# @api private
|
28
36
|
def resolve_with_support(**args)
|
37
|
+
@original_arguments = args # before `loads:` have been run
|
29
38
|
result = nil
|
30
39
|
unsubscribed = true
|
31
40
|
unsubscribed_result = catch :graphql_subscription_unsubscribed do
|
@@ -46,7 +55,9 @@ module GraphQL
|
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|
49
|
-
# Implement the {Resolve} API
|
58
|
+
# Implement the {Resolve} API.
|
59
|
+
# You can implement this if you want code to run for _both_ the initial subscription
|
60
|
+
# and for later updates. Or, implement {#subscribe} and {#update}
|
50
61
|
def resolve(**args)
|
51
62
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
52
63
|
# have an unexpected `@mode`
|
@@ -54,8 +65,9 @@ module GraphQL
|
|
54
65
|
end
|
55
66
|
|
56
67
|
# Wrap the user-defined `#subscribe` hook
|
68
|
+
# @api private
|
57
69
|
def resolve_subscribe(**args)
|
58
|
-
ret_val = args.
|
70
|
+
ret_val = !args.empty? ? subscribe(**args) : subscribe
|
59
71
|
if ret_val == :no_response
|
60
72
|
context.skip
|
61
73
|
else
|
@@ -71,8 +83,9 @@ module GraphQL
|
|
71
83
|
end
|
72
84
|
|
73
85
|
# Wrap the user-provided `#update` hook
|
86
|
+
# @api private
|
74
87
|
def resolve_update(**args)
|
75
|
-
ret_val = args.
|
88
|
+
ret_val = !args.empty? ? update(**args) : update
|
76
89
|
if ret_val == NO_UPDATE
|
77
90
|
context.namespace(:subscriptions)[:no_update] = true
|
78
91
|
context.skip
|
@@ -106,14 +119,13 @@ module GraphQL
|
|
106
119
|
throw :graphql_subscription_unsubscribed, update_value
|
107
120
|
end
|
108
121
|
|
109
|
-
READING_SCOPE = ::Object.new
|
110
122
|
# Call this method to provide a new subscription_scope; OR
|
111
123
|
# call it without an argument to get the subscription_scope
|
112
124
|
# @param new_scope [Symbol]
|
113
125
|
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
114
126
|
# @return [Symbol]
|
115
|
-
def self.subscription_scope(new_scope =
|
116
|
-
if new_scope !=
|
127
|
+
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
|
128
|
+
if new_scope != NOT_CONFIGURED
|
117
129
|
@subscription_scope = new_scope
|
118
130
|
@subscription_scope_optional = optional
|
119
131
|
elsif defined?(@subscription_scope)
|
@@ -150,6 +162,40 @@ module GraphQL
|
|
150
162
|
def self.topic_for(arguments:, field:, scope:)
|
151
163
|
Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
|
152
164
|
end
|
165
|
+
|
166
|
+
# Calls through to `schema.subscriptions` to register this subscription with the backend.
|
167
|
+
# This is automatically called by GraphQL-Ruby after a query finishes successfully,
|
168
|
+
# but if you need to commit the subscription during `#subscribe`, you can call it there.
|
169
|
+
# (This method also sets a flag showing that this subscription was already written.)
|
170
|
+
#
|
171
|
+
# If you call this method yourself, you may also need to {#unsubscribe}
|
172
|
+
# or call `subscriptions.delete_subscription` to clean up the database if the query crashes with an error
|
173
|
+
# later in execution.
|
174
|
+
# @return [void]
|
175
|
+
def write_subscription
|
176
|
+
if subscription_written?
|
177
|
+
raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`."
|
178
|
+
else
|
179
|
+
@subscription_written = true
|
180
|
+
context.schema.subscriptions.write_subscription(context.query, [event])
|
181
|
+
end
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return [Boolean] `true` if {#write_subscription} was called already
|
186
|
+
def subscription_written?
|
187
|
+
@subscription_written
|
188
|
+
end
|
189
|
+
|
190
|
+
# @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
|
191
|
+
def event
|
192
|
+
@event ||= Subscriptions::Event.new(
|
193
|
+
name: field.name,
|
194
|
+
arguments: @original_arguments,
|
195
|
+
context: context,
|
196
|
+
field: field,
|
197
|
+
)
|
198
|
+
end
|
153
199
|
end
|
154
200
|
end
|
155
201
|
end
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -11,7 +11,7 @@ module GraphQL
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
|
14
|
-
if types.
|
14
|
+
if !types.empty?
|
15
15
|
types.each do |t|
|
16
16
|
assert_valid_union_member(t)
|
17
17
|
type_memberships << type_membership_class.new(self, t, **options)
|
@@ -51,19 +51,36 @@ module GraphQL
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def validate(_object, context, value)
|
54
|
-
|
54
|
+
fully_matched_conditions = 0
|
55
|
+
partially_matched_conditions = 0
|
55
56
|
|
56
57
|
if !value.nil?
|
57
58
|
@one_of.each do |one_of_condition|
|
58
59
|
case one_of_condition
|
59
60
|
when Symbol
|
60
61
|
if value.key?(one_of_condition)
|
61
|
-
|
62
|
+
fully_matched_conditions += 1
|
62
63
|
end
|
63
64
|
when Array
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
any_match = false
|
66
|
+
full_match = true
|
67
|
+
|
68
|
+
one_of_condition.each do |k|
|
69
|
+
if value.key?(k)
|
70
|
+
any_match = true
|
71
|
+
else
|
72
|
+
full_match = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
partial_match = !full_match && any_match
|
77
|
+
|
78
|
+
if full_match
|
79
|
+
fully_matched_conditions += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
if partial_match
|
83
|
+
partially_matched_conditions += 1
|
67
84
|
end
|
68
85
|
else
|
69
86
|
raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
|
@@ -71,7 +88,7 @@ module GraphQL
|
|
71
88
|
end
|
72
89
|
end
|
73
90
|
|
74
|
-
if
|
91
|
+
if fully_matched_conditions == 1 && partially_matched_conditions == 0
|
75
92
|
nil # OK
|
76
93
|
else
|
77
94
|
@message || build_message(context)
|