graphql 1.10.1 → 1.13.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/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +36 -6
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_generator.rb +2 -1
- data/lib/generators/graphql/object_generator.rb +54 -9
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -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/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +3 -1
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +21 -33
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +24 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +126 -109
- data/lib/graphql/analysis/ast/visitor.rb +13 -5
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/argument.rb +3 -3
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +34 -3
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +40 -9
- data/lib/graphql/backtrace.rb +28 -19
- data/lib/graphql/backwards_compatibility.rb +2 -1
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- 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 +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/defined_object_proxy.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +34 -4
- data/lib/graphql/define/type_definer.rb +5 -5
- data/lib/graphql/deprecated_dsl.rb +18 -5
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/directive.rb +4 -4
- data/lib/graphql/enum_type.rb +7 -1
- data/lib/graphql/execution/errors.rb +110 -7
- data/lib/graphql/execution/execute.rb +8 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +37 -25
- data/lib/graphql/execution/interpreter/runtime.rb +685 -421
- data/lib/graphql/execution/interpreter.rb +42 -13
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/execution/lookahead.rb +25 -110
- data/lib/graphql/execution/multiplex.rb +37 -25
- data/lib/graphql/field.rb +5 -1
- data/lib/graphql/function.rb +4 -0
- data/lib/graphql/input_object_type.rb +6 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/interface_type.rb +7 -0
- data/lib/graphql/internal_representation/document.rb +2 -2
- data/lib/graphql/internal_representation/rewrite.rb +1 -1
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +8 -4
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +9 -5
- data/lib/graphql/introspection/input_value_type.rb +15 -3
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -4
- data/lib/graphql/introspection/type_type.rb +16 -12
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +20 -5
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +73 -25
- data/lib/graphql/language/lexer.rb +4 -3
- data/lib/graphql/language/lexer.rl +3 -3
- data/lib/graphql/language/nodes.rb +51 -89
- data/lib/graphql/language/parser.rb +552 -530
- data/lib/graphql/language/parser.y +114 -99
- data/lib/graphql/language/printer.rb +7 -2
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -0
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/object_type.rb +44 -35
- data/lib/graphql/pagination/active_record_relation_connection.rb +14 -1
- data/lib/graphql/pagination/array_connection.rb +2 -2
- data/lib/graphql/pagination/connection.rb +75 -20
- data/lib/graphql/pagination/connections.rb +83 -31
- data/lib/graphql/pagination/relation_connection.rb +34 -14
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/arguments.rb +4 -3
- data/lib/graphql/query/arguments_cache.rb +1 -2
- data/lib/graphql/query/context.rb +42 -7
- data/lib/graphql/query/executor.rb +0 -1
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +24 -8
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +5 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +14 -4
- data/lib/graphql/query.rb +68 -13
- data/lib/graphql/railtie.rb +9 -1
- data/lib/graphql/rake_task.rb +12 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +26 -13
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/mutation.rb +1 -0
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/range_add.rb +23 -9
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/scalar_type.rb +16 -1
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +210 -12
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
- data/lib/graphql/schema/build_from_definition.rb +213 -86
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +78 -2
- data/lib/graphql/schema/enum.rb +80 -9
- data/lib/graphql/schema/enum_value.rb +17 -6
- data/lib/graphql/schema/field/connection_extension.rb +46 -30
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +285 -133
- data/lib/graphql/schema/find_inherited_value.rb +4 -1
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +97 -89
- data/lib/graphql/schema/interface.rb +24 -19
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/list.rb +7 -1
- data/lib/graphql/schema/loader.rb +137 -103
- data/lib/graphql/schema/member/accepts_definition.rb +8 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
- data/lib/graphql/schema/member/build_type.rb +14 -7
- data/lib/graphql/schema/member/has_arguments.rb +205 -12
- data/lib/graphql/schema/member/has_ast_node.rb +4 -1
- 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_fields.rb +95 -30
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/instrumentation.rb +0 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/middleware_chain.rb +1 -1
- data/lib/graphql/schema/mutation.rb +4 -0
- data/lib/graphql/schema/non_null.rb +5 -0
- data/lib/graphql/schema/object.rb +47 -46
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +16 -34
- data/lib/graphql/schema/relay_classic_mutation.rb +32 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
- data/lib/graphql/schema/resolver.rb +123 -63
- data/lib/graphql/schema/scalar.rb +11 -1
- data/lib/graphql/schema/subscription.rb +57 -21
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/timeout_middleware.rb +3 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +41 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +12 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/validator.rb +174 -0
- data/lib/graphql/schema/warden.rb +153 -28
- data/lib/graphql/schema.rb +364 -330
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +8 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +51 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -43
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -8
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
- data/lib/graphql/static_validation/validation_context.rb +9 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +42 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +118 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +81 -30
- data/lib/graphql/subscriptions/instrumentation.rb +0 -1
- data/lib/graphql/subscriptions/serialize.rb +33 -6
- data/lib/graphql/subscriptions/subscription_root.rb +15 -4
- data/lib/graphql/subscriptions.rb +88 -45
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
- data/lib/graphql/tracing/platform_tracing.rb +43 -17
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/scout_tracing.rb +11 -0
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +9 -33
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +10 -3
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +6 -90
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +53 -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 +2 -20
- data/lib/graphql/types/relay/nodes_field.rb +2 -20
- 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/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- 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 +65 -31
- data/readme.md +3 -6
- metadata +77 -112
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- data/lib/graphql/literal_validation_error.rb +0 -6
- 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
@@ -6,20 +6,13 @@ module GraphQL
|
|
6
6
|
#
|
7
7
|
# Attach as a plugin.
|
8
8
|
#
|
9
|
-
# @example Using new default connections
|
10
|
-
# class MySchema < GraphQL::Schema
|
11
|
-
# use GraphQL::Pagination::Connections
|
12
|
-
# end
|
13
|
-
#
|
14
9
|
# @example Adding a custom wrapper
|
15
10
|
# class MySchema < GraphQL::Schema
|
16
|
-
# use GraphQL::Pagination::Connections
|
17
11
|
# connections.add(MyApp::SearchResults, MyApp::SearchResultsConnection)
|
18
12
|
# end
|
19
13
|
#
|
20
14
|
# @example Removing default connection support for arrays (they can still be manually wrapped)
|
21
15
|
# class MySchema < GraphQL::Schema
|
22
|
-
# use GraphQL::Pagination::Connections
|
23
16
|
# connections.delete(Array)
|
24
17
|
# end
|
25
18
|
#
|
@@ -29,17 +22,14 @@ module GraphQL
|
|
29
22
|
end
|
30
23
|
|
31
24
|
def self.use(schema_defn)
|
32
|
-
if schema_defn.
|
33
|
-
|
34
|
-
else
|
35
|
-
# Unwrap a `.define` object
|
36
|
-
schema_defn = schema_defn.target
|
37
|
-
schema_defn.connections = self.new
|
38
|
-
schema_defn.class.connections = schema_defn.connections
|
25
|
+
if schema_defn.plugins.any? { |(plugin, args)| plugin == self }
|
26
|
+
GraphQL::Deprecation.warn("#{self} is now the default, remove `use #{self}` from #{caller(2,1).first}")
|
39
27
|
end
|
28
|
+
schema_defn.connections = self.new(schema: schema_defn)
|
40
29
|
end
|
41
30
|
|
42
|
-
def initialize
|
31
|
+
def initialize(schema:)
|
32
|
+
@schema = schema
|
43
33
|
@wrappers = {}
|
44
34
|
add_default
|
45
35
|
end
|
@@ -52,29 +42,86 @@ module GraphQL
|
|
52
42
|
@wrappers.delete(nodes_class)
|
53
43
|
end
|
54
44
|
|
55
|
-
|
56
|
-
|
57
|
-
|
45
|
+
def all_wrappers
|
46
|
+
all_wrappers = {}
|
47
|
+
@schema.ancestors.reverse_each do |schema_class|
|
48
|
+
if schema_class.respond_to?(:connections) && (c = schema_class.connections)
|
49
|
+
all_wrappers.merge!(c.wrappers)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
all_wrappers
|
53
|
+
end
|
54
|
+
|
55
|
+
def wrapper_for(items, wrappers: all_wrappers)
|
58
56
|
impl = nil
|
59
|
-
|
60
|
-
|
57
|
+
|
58
|
+
items.class.ancestors.each { |cls|
|
59
|
+
impl = wrappers[cls]
|
61
60
|
break if impl
|
62
61
|
}
|
63
62
|
|
64
|
-
|
65
|
-
|
63
|
+
impl
|
64
|
+
end
|
65
|
+
|
66
|
+
# Used by the runtime to wrap values in connection wrappers.
|
67
|
+
# @api Private
|
68
|
+
def wrap(field, parent, items, arguments, context)
|
69
|
+
return items if GraphQL::Execution::Interpreter::RawValue === items
|
70
|
+
wrappers = context ? context.namespace(:connections)[:all_wrappers] : all_wrappers
|
71
|
+
impl = wrapper_for(items, wrappers: wrappers)
|
72
|
+
|
73
|
+
if impl
|
74
|
+
impl.new(
|
75
|
+
items,
|
76
|
+
context: context,
|
77
|
+
parent: parent,
|
78
|
+
field: field,
|
79
|
+
max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
|
80
|
+
first: arguments[:first],
|
81
|
+
after: arguments[:after],
|
82
|
+
last: arguments[:last],
|
83
|
+
before: arguments[:before],
|
84
|
+
arguments: arguments,
|
85
|
+
edge_class: edge_class_for_field(field),
|
86
|
+
)
|
87
|
+
else
|
88
|
+
begin
|
89
|
+
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(items)
|
90
|
+
if parent.is_a?(GraphQL::Schema::Object)
|
91
|
+
parent = parent.object
|
92
|
+
end
|
93
|
+
connection_class.new(
|
94
|
+
items,
|
95
|
+
arguments,
|
96
|
+
field: field,
|
97
|
+
max_page_size: field.max_page_size,
|
98
|
+
parent: parent,
|
99
|
+
context: context,
|
100
|
+
)
|
101
|
+
rescue RuntimeError => err
|
102
|
+
if err.message.include?("No connection implementation to wrap")
|
103
|
+
raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
|
104
|
+
else
|
105
|
+
raise err
|
106
|
+
end
|
107
|
+
end
|
66
108
|
end
|
109
|
+
end
|
67
110
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
111
|
+
# use an override if there is one
|
112
|
+
# @api private
|
113
|
+
def edge_class_for_field(field)
|
114
|
+
conn_type = field.type.unwrap
|
115
|
+
conn_type_edge_type = conn_type.respond_to?(:edge_class) && conn_type.edge_class
|
116
|
+
if conn_type_edge_type && conn_type_edge_type != Relay::Edge
|
117
|
+
conn_type_edge_type
|
118
|
+
else
|
119
|
+
nil
|
120
|
+
end
|
77
121
|
end
|
122
|
+
protected
|
123
|
+
|
124
|
+
attr_reader :wrappers
|
78
125
|
|
79
126
|
private
|
80
127
|
|
@@ -102,6 +149,11 @@ module GraphQL
|
|
102
149
|
if defined?(Mongoid::Association::Referenced::HasMany::Targets::Enumerable)
|
103
150
|
add(Mongoid::Association::Referenced::HasMany::Targets::Enumerable, Pagination::MongoidRelationConnection)
|
104
151
|
end
|
152
|
+
|
153
|
+
# Mongoid 7.3+
|
154
|
+
if defined?(Mongoid::Association::Referenced::HasMany::Enumerable)
|
155
|
+
add(Mongoid::Association::Referenced::HasMany::Enumerable, Pagination::MongoidRelationConnection)
|
156
|
+
end
|
105
157
|
end
|
106
158
|
end
|
107
159
|
end
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
|
13
13
|
def has_previous_page
|
14
14
|
if @has_previous_page.nil?
|
15
|
-
@has_previous_page = if
|
15
|
+
@has_previous_page = if after_offset && after_offset > 0
|
16
16
|
true
|
17
17
|
elsif last
|
18
18
|
# See whether there are any nodes _before_ the current offset.
|
@@ -29,10 +29,14 @@ module GraphQL
|
|
29
29
|
|
30
30
|
def has_next_page
|
31
31
|
if @has_next_page.nil?
|
32
|
-
@has_next_page = if
|
32
|
+
@has_next_page = if before_offset && before_offset > 0
|
33
33
|
true
|
34
34
|
elsif first
|
35
|
-
|
35
|
+
if @nodes && @nodes.count < first
|
36
|
+
false
|
37
|
+
else
|
38
|
+
relation_larger_than(sliced_nodes, first)
|
39
|
+
end
|
36
40
|
else
|
37
41
|
false
|
38
42
|
end
|
@@ -44,11 +48,18 @@ module GraphQL
|
|
44
48
|
load_nodes
|
45
49
|
# index in nodes + existing offset + 1 (because it's offset, not index)
|
46
50
|
offset = nodes.index(item) + 1 + (@paged_nodes_offset || 0) + (relation_offset(items) || 0)
|
47
|
-
|
51
|
+
encode(offset.to_s)
|
48
52
|
end
|
49
53
|
|
50
54
|
private
|
51
55
|
|
56
|
+
# @param relation [Object] A database query object
|
57
|
+
# @param size [Integer] The value against which we check the relation size
|
58
|
+
# @return [Boolean] True if the number of items in this relation is larger than `size`
|
59
|
+
def relation_larger_than(relation, size)
|
60
|
+
relation_count(set_limit(relation, size + 1)) == size + 1
|
61
|
+
end
|
62
|
+
|
52
63
|
# @param relation [Object] A database query object
|
53
64
|
# @return [Integer, nil] The offset value, or nil if there isn't one
|
54
65
|
def relation_offset(relation)
|
@@ -105,40 +116,49 @@ module GraphQL
|
|
105
116
|
def sliced_nodes
|
106
117
|
@sliced_nodes ||= begin
|
107
118
|
paginated_nodes = items
|
108
|
-
@after_offset = after && offset_from_cursor(after)
|
109
|
-
@before_offset = before && offset_from_cursor(before)
|
110
119
|
|
111
|
-
if
|
120
|
+
if after_offset
|
112
121
|
previous_offset = relation_offset(items) || 0
|
113
|
-
paginated_nodes = set_offset(paginated_nodes, previous_offset +
|
122
|
+
paginated_nodes = set_offset(paginated_nodes, previous_offset + after_offset)
|
114
123
|
end
|
115
124
|
|
116
|
-
if
|
117
|
-
if
|
125
|
+
if before_offset && after_offset
|
126
|
+
if after_offset < before_offset
|
118
127
|
# Get the number of items between the two cursors
|
119
|
-
space_between =
|
128
|
+
space_between = before_offset - after_offset - 1
|
120
129
|
paginated_nodes = set_limit(paginated_nodes, space_between)
|
121
130
|
else
|
122
131
|
# TODO I think this is untested
|
123
132
|
# The cursors overextend one another to an empty set
|
124
133
|
paginated_nodes = null_relation(paginated_nodes)
|
125
134
|
end
|
126
|
-
elsif
|
135
|
+
elsif before_offset
|
127
136
|
# Use limit to cut off the tail of the relation
|
128
|
-
paginated_nodes = set_limit(paginated_nodes,
|
137
|
+
paginated_nodes = set_limit(paginated_nodes, before_offset - 1)
|
129
138
|
end
|
130
139
|
|
131
140
|
paginated_nodes
|
132
141
|
end
|
133
142
|
end
|
134
143
|
|
144
|
+
# @return [Integer, nil]
|
145
|
+
def before_offset
|
146
|
+
@before_offset ||= before && offset_from_cursor(before)
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [Integer, nil]
|
150
|
+
def after_offset
|
151
|
+
@after_offset ||= after && offset_from_cursor(after)
|
152
|
+
end
|
153
|
+
|
135
154
|
# Apply `first` and `last` to `sliced_nodes`,
|
136
155
|
# returning a new relation
|
137
156
|
def limited_nodes
|
138
157
|
@limited_nodes ||= begin
|
139
158
|
paginated_nodes = sliced_nodes
|
159
|
+
previous_limit = relation_limit(paginated_nodes)
|
140
160
|
|
141
|
-
if first && (
|
161
|
+
if first && (previous_limit.nil? || previous_limit > first)
|
142
162
|
# `first` would create a stricter limit that the one already applied, so add it
|
143
163
|
paginated_nodes = set_limit(paginated_nodes, first)
|
144
164
|
end
|
data/lib/graphql/parse_error.rb
CHANGED
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
include GraphQL::Dig
|
10
10
|
|
11
11
|
def self.construct_arguments_class(argument_owner)
|
12
|
-
argument_definitions = argument_owner.arguments
|
12
|
+
argument_definitions = argument_owner.arguments # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
13
13
|
argument_owner.arguments_class = Class.new(self) do
|
14
14
|
self.argument_owner = argument_owner
|
15
15
|
self.argument_definitions = argument_definitions
|
@@ -22,7 +22,7 @@ module GraphQL
|
|
22
22
|
method_names.each do |method_name|
|
23
23
|
# Don't define a helper method if it would override something.
|
24
24
|
if method_defined?(method_name)
|
25
|
-
warn(
|
25
|
+
GraphQL::Deprecation.warn(
|
26
26
|
"Unable to define a helper for argument with name '#{method_name}' "\
|
27
27
|
"as this is a reserved name. Add `method_access: false` to stop this warning."
|
28
28
|
)
|
@@ -86,7 +86,8 @@ module GraphQL
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
def_delegators :to_h, :keys, :values, :each
|
89
|
+
def_delegators :to_h, :keys, :values, :each
|
90
|
+
def_delegators :@argument_values, :any?
|
90
91
|
|
91
92
|
def prepare
|
92
93
|
self
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../query.rb
|
3
2
|
module GraphQL
|
4
3
|
class Query
|
5
4
|
module ArgumentsCache
|
@@ -8,7 +7,7 @@ module GraphQL
|
|
8
7
|
Hash.new do |h1, irep_or_ast_node|
|
9
8
|
h1[irep_or_ast_node] = Hash.new do |h2, definition|
|
10
9
|
ast_node = irep_or_ast_node.is_a?(GraphQL::InternalRepresentation::Node) ? irep_or_ast_node.ast_node : irep_or_ast_node
|
11
|
-
h2[definition] = if definition.arguments.empty?
|
10
|
+
h2[definition] = if definition.arguments(query.context).empty?
|
12
11
|
GraphQL::Query::Arguments::NO_ARGS
|
13
12
|
else
|
14
13
|
GraphQL::Query::LiteralInput.from_arguments(
|
@@ -1,6 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../execution/execute.rb
|
3
|
-
# test_via: ../execution/lazy.rb
|
4
2
|
module GraphQL
|
5
3
|
class Query
|
6
4
|
# Expose some query-specific info to field resolve functions.
|
@@ -34,7 +32,7 @@ module GraphQL
|
|
34
32
|
# Remove this child from the result value
|
35
33
|
# (used for null propagation and skip)
|
36
34
|
# @api private
|
37
|
-
def
|
35
|
+
def delete_child(child_ctx)
|
38
36
|
@value.delete(child_ctx.key)
|
39
37
|
end
|
40
38
|
|
@@ -158,6 +156,10 @@ module GraphQL
|
|
158
156
|
@scoped_context = {}
|
159
157
|
end
|
160
158
|
|
159
|
+
def dataloader
|
160
|
+
@dataloader ||= self[:dataloader] || (query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new)
|
161
|
+
end
|
162
|
+
|
161
163
|
# @api private
|
162
164
|
attr_writer :interpreter
|
163
165
|
|
@@ -167,8 +169,10 @@ module GraphQL
|
|
167
169
|
# @api private
|
168
170
|
attr_accessor :scoped_context
|
169
171
|
|
170
|
-
|
171
|
-
|
172
|
+
def []=(key, value)
|
173
|
+
@provided_values[key] = value
|
174
|
+
end
|
175
|
+
|
172
176
|
def_delegators :@query, :trace, :interpreter?
|
173
177
|
|
174
178
|
# @!method []=(key, value)
|
@@ -180,6 +184,34 @@ module GraphQL
|
|
180
184
|
@provided_values[key]
|
181
185
|
end
|
182
186
|
|
187
|
+
def delete(key)
|
188
|
+
if @scoped_context.key?(key)
|
189
|
+
@scoped_context.delete(key)
|
190
|
+
else
|
191
|
+
@provided_values.delete(key)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
196
|
+
|
197
|
+
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
198
|
+
if @scoped_context.key?(key)
|
199
|
+
@scoped_context[key]
|
200
|
+
elsif @provided_values.key?(key)
|
201
|
+
@provided_values[key]
|
202
|
+
elsif default != UNSPECIFIED_FETCH_DEFAULT
|
203
|
+
default
|
204
|
+
elsif block_given?
|
205
|
+
yield(self, key)
|
206
|
+
else
|
207
|
+
raise KeyError.new(key: key)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def dig(key, *other_keys)
|
212
|
+
@scoped_context.key?(key) ? @scoped_context.dig(key, *other_keys) : @provided_values.dig(key, *other_keys)
|
213
|
+
end
|
214
|
+
|
183
215
|
def to_h
|
184
216
|
@provided_values.merge(@scoped_context)
|
185
217
|
end
|
@@ -191,9 +223,12 @@ module GraphQL
|
|
191
223
|
|
192
224
|
# @return [GraphQL::Schema::Warden]
|
193
225
|
def warden
|
194
|
-
@warden ||= @query.warden
|
226
|
+
@warden ||= (@query && @query.warden)
|
195
227
|
end
|
196
228
|
|
229
|
+
# @api private
|
230
|
+
attr_writer :warden
|
231
|
+
|
197
232
|
# Get an isolated hash for `ns`. Doesn't affect user-provided storage.
|
198
233
|
# @param ns [Object] a usage-specific namespace identifier
|
199
234
|
# @return [Hash] namespaced storage
|
@@ -293,7 +328,7 @@ module GraphQL
|
|
293
328
|
end
|
294
329
|
when GraphQL::Execution::Execute::SKIP
|
295
330
|
@parent.skipped = true
|
296
|
-
@parent.
|
331
|
+
@parent.delete_child(self)
|
297
332
|
else
|
298
333
|
@value = new_value
|
299
334
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Query
|
7
|
+
# @api private
|
8
|
+
# @see Query#query_fingerprint
|
9
|
+
# @see Query#variables_fingerprint
|
10
|
+
# @see Query#fingerprint
|
11
|
+
module Fingerprint
|
12
|
+
# Make an obfuscated hash of the given string (either a query string or variables JSON)
|
13
|
+
# @param string [String]
|
14
|
+
# @return [String] A normalized, opaque hash
|
15
|
+
def self.generate(input_str)
|
16
|
+
# Implemented to be:
|
17
|
+
# - Short (and uniform) length
|
18
|
+
# - Stable
|
19
|
+
# - Irreversibly Opaque (don't want to leak variable values)
|
20
|
+
# - URL-friendly
|
21
|
+
bytes = Digest::SHA256.digest(input_str)
|
22
|
+
Base64.urlsafe_encode64(bytes)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -4,22 +4,39 @@ module GraphQL
|
|
4
4
|
class InputValidationResult
|
5
5
|
attr_accessor :problems
|
6
6
|
|
7
|
+
def initialize(valid: true, problems: nil)
|
8
|
+
@valid = valid
|
9
|
+
@problems = problems
|
10
|
+
end
|
11
|
+
|
7
12
|
def valid?
|
8
|
-
@
|
13
|
+
@valid
|
9
14
|
end
|
10
15
|
|
11
|
-
def add_problem(explanation, path = nil)
|
16
|
+
def add_problem(explanation, path = nil, extensions: nil, message: nil)
|
12
17
|
@problems ||= []
|
13
|
-
@
|
18
|
+
@valid = false
|
19
|
+
problem = { "path" => path || [], "explanation" => explanation }
|
20
|
+
if extensions
|
21
|
+
problem["extensions"] = extensions
|
22
|
+
end
|
23
|
+
if message
|
24
|
+
problem["message"] = message
|
25
|
+
end
|
26
|
+
@problems.push(problem)
|
14
27
|
end
|
15
28
|
|
16
29
|
def merge_result!(path, inner_result)
|
17
30
|
return if inner_result.valid?
|
18
31
|
|
19
|
-
inner_result.problems
|
20
|
-
|
21
|
-
|
32
|
+
if inner_result.problems
|
33
|
+
inner_result.problems.each do |p|
|
34
|
+
item_path = [path, *p["path"]]
|
35
|
+
add_problem(p["explanation"], item_path, message: p["message"], extensions: p["extensions"])
|
36
|
+
end
|
22
37
|
end
|
38
|
+
# It could have been explicitly set on inner_result (if it had no problems)
|
39
|
+
@valid = false
|
23
40
|
end
|
24
41
|
end
|
25
42
|
end
|
@@ -62,7 +62,7 @@ module GraphQL
|
|
62
62
|
raise ArgumentError, "Unexpected ast_arguments: #{ast_arguments}"
|
63
63
|
end
|
64
64
|
|
65
|
-
argument_defns = argument_owner.arguments
|
65
|
+
argument_defns = argument_owner.arguments(context || GraphQL::Query::NullContext)
|
66
66
|
argument_defns.each do |arg_name, arg_defn|
|
67
67
|
ast_arg = indexed_arguments[arg_name]
|
68
68
|
# First, check the argument in the AST.
|
@@ -4,16 +4,28 @@ module GraphQL
|
|
4
4
|
# This object can be `ctx` in places where there is no query
|
5
5
|
class NullContext
|
6
6
|
class NullWarden < GraphQL::Schema::Warden
|
7
|
-
def
|
8
|
-
def
|
9
|
-
def visible_type?(
|
7
|
+
def visible_field?(field, ctx); true; end
|
8
|
+
def visible_argument?(arg, ctx); true; end
|
9
|
+
def visible_type?(type, ctx); true; end
|
10
|
+
def visible_enum_value?(ev, ctx); true; end
|
11
|
+
def visible_type_membership?(tm, ctx); true; end
|
10
12
|
end
|
11
13
|
|
12
|
-
|
14
|
+
class NullQuery
|
15
|
+
def with_error_handling
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class NullSchema < GraphQL::Schema
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :schema, :query, :warden, :dataloader
|
13
24
|
|
14
25
|
def initialize
|
15
|
-
@query =
|
16
|
-
@
|
26
|
+
@query = NullQuery.new
|
27
|
+
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
28
|
+
@schema = NullSchema
|
17
29
|
@warden = NullWarden.new(
|
18
30
|
GraphQL::Filter.new,
|
19
31
|
context: self,
|
@@ -23,16 +35,20 @@ module GraphQL
|
|
23
35
|
|
24
36
|
def [](key); end
|
25
37
|
|
38
|
+
def interpreter?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
26
42
|
class << self
|
27
43
|
extend Forwardable
|
28
44
|
|
29
45
|
def [](key); end
|
30
46
|
|
31
47
|
def instance
|
32
|
-
@instance
|
48
|
+
@instance ||= self.new
|
33
49
|
end
|
34
50
|
|
35
|
-
def_delegators :instance, :query, :schema, :
|
51
|
+
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
|
36
52
|
end
|
37
53
|
end
|
38
54
|
end
|
@@ -81,7 +81,7 @@ module GraphQL
|
|
81
81
|
# is added to the "errors" key.
|
82
82
|
def get_raw_value
|
83
83
|
begin
|
84
|
-
@field_ctx.schema.middleware.invoke([parent_type, target, field, arguments, @field_ctx])
|
84
|
+
@field_ctx.schema.middleware.invoke([parent_type, target, field, arguments, @field_ctx]) # rubocop:disable Development/ContextIsPassedCop -- unrelated
|
85
85
|
rescue GraphQL::ExecutionError => err
|
86
86
|
err
|
87
87
|
end
|
@@ -16,6 +16,7 @@ module GraphQL
|
|
16
16
|
# @param query_object [GraphQL::Query] the query object for this execution
|
17
17
|
# @return [Hash] a spec-compliant GraphQL result, as a hash
|
18
18
|
def execute(ast_operation, root_type, query_object)
|
19
|
+
GraphQL::Deprecation.warn "#{self.class} will be removed in GraphQL-Ruby 2.0, please upgrade to the Interpreter: https://graphql-ruby.org/queries/interpreter.html"
|
19
20
|
operation_resolution.resolve(
|
20
21
|
query_object.irep_selection,
|
21
22
|
root_type,
|
@@ -36,7 +36,7 @@ module GraphQL
|
|
36
36
|
@valid
|
37
37
|
end
|
38
38
|
|
39
|
-
# @return [Array<GraphQL::StaticValidation::Error >] Static validation errors for the query string
|
39
|
+
# @return [Array<GraphQL::StaticValidation::Error, GraphQL::Query::VariableValidationError>] Static validation errors for the query string
|
40
40
|
def validation_errors
|
41
41
|
ensure_has_validated
|
42
42
|
@validation_errors
|
@@ -72,7 +72,7 @@ module GraphQL
|
|
72
72
|
elsif @operation_name_error
|
73
73
|
@validation_errors << @operation_name_error
|
74
74
|
else
|
75
|
-
validation_result = @schema.static_validator.validate(@query, validate: @validate)
|
75
|
+
validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
76
76
|
@validation_errors.concat(validation_result[:errors])
|
77
77
|
@internal_representation = validation_result[:irep]
|
78
78
|
|
@@ -90,6 +90,9 @@ module GraphQL
|
|
90
90
|
end
|
91
91
|
|
92
92
|
@valid = @validation_errors.empty?
|
93
|
+
rescue SystemStackError => err
|
94
|
+
@valid = false
|
95
|
+
@schema.query_stack_error(@query, err)
|
93
96
|
end
|
94
97
|
|
95
98
|
# If there are max_* values, add them,
|
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
# a one level deep merge explicitly. However beyond that only show the
|
24
24
|
# latest value and problems.
|
25
25
|
super.merge({ "extensions" => { "value" => value, "problems" => validation_result.problems }}) do |key, oldValue, newValue|
|
26
|
-
if oldValue.respond_to?
|
26
|
+
if oldValue.respond_to?(:merge)
|
27
27
|
oldValue.merge(newValue)
|
28
28
|
else
|
29
29
|
newValue
|
@@ -34,7 +34,9 @@ module GraphQL
|
|
34
34
|
if validation_result.valid?
|
35
35
|
if value_was_provided
|
36
36
|
# Add the variable if a value was provided
|
37
|
-
memo[variable_name] = if
|
37
|
+
memo[variable_name] = if ctx.interpreter?
|
38
|
+
provided_value
|
39
|
+
elsif provided_value.nil?
|
38
40
|
nil
|
39
41
|
else
|
40
42
|
schema.error_handler.with_error_handling(context) do
|
@@ -42,11 +44,19 @@ module GraphQL
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
elsif default_value != nil
|
45
|
-
|
46
|
-
|
47
|
+
memo[variable_name] = if ctx.interpreter?
|
48
|
+
if default_value.is_a?(Language::Nodes::NullValue)
|
49
|
+
nil
|
50
|
+
else
|
51
|
+
default_value
|
52
|
+
end
|
53
|
+
else
|
54
|
+
# Add the variable if it wasn't provided but it has a default value (including `null`)
|
55
|
+
GraphQL::Query::LiteralInput.coerce(variable_type, default_value, self)
|
56
|
+
end
|
47
57
|
end
|
48
58
|
end
|
49
|
-
rescue GraphQL::
|
59
|
+
rescue GraphQL::ExecutionError => ex
|
50
60
|
# TODO: This should really include the path to the problematic node in the variable value
|
51
61
|
# like InputValidationResults generated by validate_non_null_input but unfortunately we don't
|
52
62
|
# have this information available in the coerce_input call chain. Note this path is the path
|