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
@@ -0,0 +1,222 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Language
|
4
|
+
# A custom printer used to print sanitized queries. It inlines provided variables
|
5
|
+
# within the query for facilitate logging and analysis of queries.
|
6
|
+
#
|
7
|
+
# The printer returns `nil` if the query is invalid.
|
8
|
+
#
|
9
|
+
# Since the GraphQL Ruby AST for a GraphQL query doesnt contain any reference
|
10
|
+
# on the type of fields or arguments, we have to track the current object, field
|
11
|
+
# and input type while printing the query.
|
12
|
+
#
|
13
|
+
# @example Printing a scrubbed string
|
14
|
+
# printer = QueryPrinter.new(query)
|
15
|
+
# puts printer.sanitized_query_string
|
16
|
+
#
|
17
|
+
# @see {Query#sanitized_query_string}
|
18
|
+
class SanitizedPrinter < GraphQL::Language::Printer
|
19
|
+
|
20
|
+
REDACTED = "\"<REDACTED>\""
|
21
|
+
|
22
|
+
def initialize(query, inline_variables: true)
|
23
|
+
@query = query
|
24
|
+
@current_type = nil
|
25
|
+
@current_field = nil
|
26
|
+
@current_input_type = nil
|
27
|
+
@inline_variables = inline_variables
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String, nil] A scrubbed query string, if the query was valid.
|
31
|
+
def sanitized_query_string
|
32
|
+
if query.valid?
|
33
|
+
print(query.document)
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def print_node(node, indent: "")
|
40
|
+
case node
|
41
|
+
when FalseClass, Float, Integer, String, TrueClass
|
42
|
+
if @current_argument && redact_argument_value?(@current_argument, node)
|
43
|
+
redacted_argument_value(@current_argument)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
when Array
|
48
|
+
old_input_type = @current_input_type
|
49
|
+
if @current_input_type && @current_input_type.list?
|
50
|
+
@current_input_type = @current_input_type.of_type
|
51
|
+
@current_input_type = @current_input_type.of_type if @current_input_type.non_null?
|
52
|
+
end
|
53
|
+
|
54
|
+
res = super
|
55
|
+
@current_input_type = old_input_type
|
56
|
+
res
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Indicates whether or not to redact non-null values for the given argument. Defaults to redacting all strings
|
63
|
+
# arguments but this can be customized by subclasses.
|
64
|
+
def redact_argument_value?(argument, value)
|
65
|
+
# Default to redacting any strings or custom scalars encoded as strings
|
66
|
+
type = argument.type.unwrap
|
67
|
+
value.is_a?(String) && type.kind.scalar? && (type.graphql_name == "String" || !type.default_scalar?)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the value to use for redacted versions of the given argument. Defaults to the
|
71
|
+
# string "<REDACTED>".
|
72
|
+
def redacted_argument_value(argument)
|
73
|
+
REDACTED
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_argument(argument)
|
77
|
+
# We won't have type information if we're recursing into a custom scalar
|
78
|
+
return super if @current_input_type && @current_input_type.kind.scalar?
|
79
|
+
|
80
|
+
arg_owner = @current_input_type || @current_directive || @current_field
|
81
|
+
old_current_argument = @current_argument
|
82
|
+
@current_argument = arg_owner.get_argument(argument.name, @query.context)
|
83
|
+
|
84
|
+
old_input_type = @current_input_type
|
85
|
+
@current_input_type = @current_argument.type.non_null? ? @current_argument.type.of_type : @current_argument.type
|
86
|
+
|
87
|
+
argument_value = if coerce_argument_value_to_list?(@current_input_type, argument.value)
|
88
|
+
[argument.value]
|
89
|
+
else
|
90
|
+
argument.value
|
91
|
+
end
|
92
|
+
res = "#{argument.name}: #{print_node(argument_value)}".dup
|
93
|
+
|
94
|
+
@current_input_type = old_input_type
|
95
|
+
@current_argument = old_current_argument
|
96
|
+
res
|
97
|
+
end
|
98
|
+
|
99
|
+
def coerce_argument_value_to_list?(type, value)
|
100
|
+
type.list? &&
|
101
|
+
!value.is_a?(Array) &&
|
102
|
+
!value.nil? &&
|
103
|
+
!value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
104
|
+
end
|
105
|
+
|
106
|
+
def print_variable_identifier(variable_id)
|
107
|
+
if @inline_variables
|
108
|
+
variable_value = query.variables[variable_id.name]
|
109
|
+
print_node(value_to_ast(variable_value, @current_input_type))
|
110
|
+
else
|
111
|
+
super
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def print_field(field, indent: "")
|
116
|
+
@current_field = query.get_field(@current_type, field.name)
|
117
|
+
old_type = @current_type
|
118
|
+
@current_type = @current_field.type.unwrap
|
119
|
+
res = super
|
120
|
+
@current_type = old_type
|
121
|
+
res
|
122
|
+
end
|
123
|
+
|
124
|
+
def print_inline_fragment(inline_fragment, indent: "")
|
125
|
+
old_type = @current_type
|
126
|
+
|
127
|
+
if inline_fragment.type
|
128
|
+
@current_type = query.get_type(inline_fragment.type.name)
|
129
|
+
end
|
130
|
+
|
131
|
+
res = super
|
132
|
+
|
133
|
+
@current_type = old_type
|
134
|
+
|
135
|
+
res
|
136
|
+
end
|
137
|
+
|
138
|
+
def print_fragment_definition(fragment_def, indent: "")
|
139
|
+
old_type = @current_type
|
140
|
+
@current_type = query.get_type(fragment_def.type.name)
|
141
|
+
|
142
|
+
res = super
|
143
|
+
|
144
|
+
@current_type = old_type
|
145
|
+
|
146
|
+
res
|
147
|
+
end
|
148
|
+
|
149
|
+
def print_directive(directive)
|
150
|
+
@current_directive = query.schema.directives[directive.name]
|
151
|
+
|
152
|
+
res = super
|
153
|
+
|
154
|
+
@current_directive = nil
|
155
|
+
res
|
156
|
+
end
|
157
|
+
|
158
|
+
# Print the operation definition but do not include the variable
|
159
|
+
# definitions since we will inline them within the query
|
160
|
+
def print_operation_definition(operation_definition, indent: "")
|
161
|
+
old_type = @current_type
|
162
|
+
@current_type = query.schema.public_send(operation_definition.operation_type)
|
163
|
+
|
164
|
+
if @inline_variables
|
165
|
+
out = "#{indent}#{operation_definition.operation_type}".dup
|
166
|
+
out << " #{operation_definition.name}" if operation_definition.name
|
167
|
+
out << print_directives(operation_definition.directives)
|
168
|
+
out << print_selections(operation_definition.selections, indent: indent)
|
169
|
+
else
|
170
|
+
out = super
|
171
|
+
end
|
172
|
+
|
173
|
+
@current_type = old_type
|
174
|
+
out
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def value_to_ast(value, type)
|
180
|
+
type = type.of_type if type.non_null?
|
181
|
+
|
182
|
+
if value.nil?
|
183
|
+
return GraphQL::Language::Nodes::NullValue.new(name: "null")
|
184
|
+
end
|
185
|
+
|
186
|
+
case type.kind.name
|
187
|
+
when "INPUT_OBJECT"
|
188
|
+
value = if value.respond_to?(:to_unsafe_h)
|
189
|
+
# for ActionController::Parameters
|
190
|
+
value.to_unsafe_h
|
191
|
+
else
|
192
|
+
value.to_h
|
193
|
+
end
|
194
|
+
|
195
|
+
arguments = value.map do |key, val|
|
196
|
+
sub_type = type.get_argument(key.to_s, @query.context).type
|
197
|
+
|
198
|
+
GraphQL::Language::Nodes::Argument.new(
|
199
|
+
name: key.to_s,
|
200
|
+
value: value_to_ast(val, sub_type)
|
201
|
+
)
|
202
|
+
end
|
203
|
+
GraphQL::Language::Nodes::InputObject.new(
|
204
|
+
arguments: arguments
|
205
|
+
)
|
206
|
+
when "LIST"
|
207
|
+
if value.is_a?(Array)
|
208
|
+
value.map { |v| value_to_ast(v, type.of_type) }
|
209
|
+
else
|
210
|
+
[value].map { |v| value_to_ast(v, type.of_type) }
|
211
|
+
end
|
212
|
+
when "ENUM"
|
213
|
+
GraphQL::Language::Nodes::Enum.new(name: value)
|
214
|
+
else
|
215
|
+
value
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
attr_reader :query
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -4,10 +4,6 @@ module GraphQL
|
|
4
4
|
# Emitted by the lexer and passed to the parser.
|
5
5
|
# Contains type, value and position data.
|
6
6
|
class Token
|
7
|
-
if !String.method_defined?(:-@)
|
8
|
-
using GraphQL::StringDedupBackport
|
9
|
-
end
|
10
|
-
|
11
7
|
# @return [Symbol] The kind of token this is
|
12
8
|
attr_reader :name
|
13
9
|
# @return [String] The text of this token
|
@@ -89,7 +89,7 @@ module GraphQL
|
|
89
89
|
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
90
90
|
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
91
91
|
def on_abstract_node(node, parent)
|
92
|
-
if node
|
92
|
+
if node.equal?(DELETE_NODE)
|
93
93
|
# This might be passed to `super(DELETE_NODE, ...)`
|
94
94
|
# by a user hook, don't want to keep visiting in that case.
|
95
95
|
nil
|
@@ -179,7 +179,7 @@ module GraphQL
|
|
179
179
|
# The user-provided hook returned a new node.
|
180
180
|
new_parent = new_parent && new_parent.replace_child(node, new_node)
|
181
181
|
return new_node, new_parent
|
182
|
-
elsif new_node
|
182
|
+
elsif new_node.equal?(DELETE_NODE)
|
183
183
|
# The user-provided hook requested to remove this node
|
184
184
|
new_parent = new_parent && new_parent.delete_child(node)
|
185
185
|
return nil, new_parent
|
data/lib/graphql/language.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/language/block_string"
|
3
3
|
require "graphql/language/printer"
|
4
|
+
require "graphql/language/sanitized_printer"
|
4
5
|
require "graphql/language/document_from_schema_definition"
|
5
6
|
require "graphql/language/generation"
|
6
7
|
require "graphql/language/lexer"
|
7
8
|
require "graphql/language/nodes"
|
9
|
+
require "graphql/language/cache"
|
8
10
|
require "graphql/language/parser"
|
9
11
|
require "graphql/language/token"
|
10
12
|
require "graphql/language/visitor"
|
@@ -4,13 +4,8 @@ module GraphQL
|
|
4
4
|
VALID_NAME_REGEX = /^[_a-zA-Z][_a-zA-Z0-9]*$/
|
5
5
|
|
6
6
|
def self.validate!(name)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
def self.valid?(name)
|
13
|
-
name =~ VALID_NAME_REGEX
|
7
|
+
name = name.is_a?(String) ? name : name.to_s
|
8
|
+
raise GraphQL::InvalidNameError.new(name, VALID_NAME_REGEX) unless name.match?(VALID_NAME_REGEX)
|
14
9
|
end
|
15
10
|
end
|
16
11
|
end
|
data/lib/graphql/object_type.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
module GraphQL
|
3
3
|
# @api deprecated
|
4
4
|
class ObjectType < GraphQL::BaseType
|
5
|
+
extend Define::InstanceDefinable::DeprecatedDefine
|
6
|
+
|
5
7
|
accepts_definitions :interfaces, :fields, :mutation, :relay_node_type, field: GraphQL::Define::AssignObjectField
|
6
8
|
accepts_definitions implements: ->(type, *interfaces, inherit: false) { type.implements(interfaces, inherit: inherit) }
|
7
9
|
|
@@ -17,17 +19,15 @@ module GraphQL
|
|
17
19
|
def initialize
|
18
20
|
super
|
19
21
|
@fields = {}
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
22
|
+
@clean_inherited_fields = nil
|
23
|
+
@structural_interface_type_memberships = []
|
24
|
+
@inherited_interface_type_memberships = []
|
23
25
|
end
|
24
26
|
|
25
27
|
def initialize_copy(other)
|
26
28
|
super
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@dirty_interfaces = other.dirty_interfaces.dup
|
30
|
-
@dirty_inherited_interfaces = other.dirty_inherited_interfaces.dup
|
29
|
+
@structural_interface_type_memberships = other.structural_interface_type_memberships.dup
|
30
|
+
@inherited_interface_type_memberships = other.inherited_interface_type_memberships.dup
|
31
31
|
@fields = other.fields.dup
|
32
32
|
end
|
33
33
|
|
@@ -35,18 +35,27 @@ module GraphQL
|
|
35
35
|
# @param new_interfaces [Array<GraphQL::Interface>] interfaces that this type implements
|
36
36
|
# @deprecated Use `implements` instead of `interfaces`.
|
37
37
|
def interfaces=(new_interfaces)
|
38
|
-
@
|
39
|
-
@
|
38
|
+
@structural_interface_type_memberships = []
|
39
|
+
@inherited_interface_type_memberships = []
|
40
40
|
@clean_inherited_fields = nil
|
41
|
-
|
42
|
-
@dirty_inherited_interfaces = []
|
43
|
-
@dirty_inherited_fields = {}
|
44
41
|
implements(new_interfaces, inherit: true)
|
45
42
|
end
|
46
43
|
|
47
|
-
def interfaces
|
48
|
-
|
49
|
-
|
44
|
+
def interfaces(ctx = GraphQL::Query::NullContext)
|
45
|
+
ensure_defined
|
46
|
+
visible_ifaces = []
|
47
|
+
unfiltered = ctx == GraphQL::Query::NullContext
|
48
|
+
[@structural_interface_type_memberships, @inherited_interface_type_memberships].each do |tms|
|
49
|
+
tms.each do |type_membership|
|
50
|
+
if unfiltered || type_membership.visible?(ctx)
|
51
|
+
# if this is derived from a class-based object, we have to
|
52
|
+
# get the `.graphql_definition` of the attached interface.
|
53
|
+
visible_ifaces << GraphQL::BaseType.resolve_related_type(type_membership.abstract_type)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
visible_ifaces
|
50
59
|
end
|
51
60
|
|
52
61
|
def kind
|
@@ -71,24 +80,30 @@ module GraphQL
|
|
71
80
|
# This declaration will be validated when the schema is defined.
|
72
81
|
# @param interfaces [Array<GraphQL::Interface>] add a new interface that this type implements
|
73
82
|
# @param inherits [Boolean] If true, copy the interfaces' field definitions to this type
|
74
|
-
def implements(interfaces, inherit: false)
|
83
|
+
def implements(interfaces, inherit: false, **options)
|
75
84
|
if !interfaces.is_a?(Array)
|
76
85
|
raise ArgumentError, "`implements(interfaces)` must be an array, not #{interfaces.class} (#{interfaces})"
|
77
86
|
end
|
78
|
-
|
79
|
-
@clean_interfaces = nil
|
80
87
|
@clean_inherited_fields = nil
|
81
|
-
|
82
|
-
|
88
|
+
|
89
|
+
type_memberships = inherit ? @inherited_interface_type_memberships : @structural_interface_type_memberships
|
90
|
+
interfaces.each do |iface|
|
91
|
+
iface = BaseType.resolve_related_type(iface)
|
92
|
+
if iface.is_a?(GraphQL::InterfaceType)
|
93
|
+
type_memberships << iface.type_membership_class.new(iface, self, **options)
|
94
|
+
end
|
95
|
+
end
|
83
96
|
end
|
84
97
|
|
85
98
|
def resolve_type_proc
|
86
99
|
nil
|
87
100
|
end
|
88
101
|
|
102
|
+
attr_writer :structural_interface_type_memberships
|
103
|
+
|
89
104
|
protected
|
90
105
|
|
91
|
-
attr_reader :
|
106
|
+
attr_reader :structural_interface_type_memberships, :inherited_interface_type_memberships
|
92
107
|
|
93
108
|
private
|
94
109
|
|
@@ -97,24 +112,18 @@ module GraphQL
|
|
97
112
|
end
|
98
113
|
|
99
114
|
def interface_fields
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
def load_interfaces
|
105
|
-
@clean_interfaces ||= begin
|
115
|
+
if @clean_inherited_fields
|
116
|
+
@clean_inherited_fields
|
117
|
+
else
|
106
118
|
ensure_defined
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
clean_inherited_ifaces.each do |iface|
|
111
|
-
# This will be found later in schema validation:
|
119
|
+
@clean_inherited_fields = {}
|
120
|
+
@inherited_interface_type_memberships.each do |type_membership|
|
121
|
+
iface = GraphQL::BaseType.resolve_related_type(type_membership.abstract_type)
|
112
122
|
if iface.is_a?(GraphQL::InterfaceType)
|
113
|
-
|
123
|
+
@clean_inherited_fields.merge!(iface.fields)
|
114
124
|
end
|
115
125
|
end
|
116
|
-
@clean_inherited_fields
|
117
|
-
clean_inherited_ifaces + clean_ifaces
|
126
|
+
@clean_inherited_fields
|
118
127
|
end
|
119
128
|
end
|
120
129
|
end
|
@@ -5,13 +5,26 @@ module GraphQL
|
|
5
5
|
module Pagination
|
6
6
|
# Customizes `RelationConnection` to work with `ActiveRecord::Relation`s.
|
7
7
|
class ActiveRecordRelationConnection < Pagination::RelationConnection
|
8
|
+
private
|
9
|
+
|
10
|
+
def relation_larger_than(relation, size)
|
11
|
+
initial_offset = relation.offset_value || 0
|
12
|
+
relation.offset(initial_offset + size).exists?
|
13
|
+
end
|
14
|
+
|
8
15
|
def relation_count(relation)
|
9
|
-
if relation.respond_to?(:unscope)
|
16
|
+
int_or_hash = if relation.respond_to?(:unscope)
|
10
17
|
relation.unscope(:order).count(:all)
|
11
18
|
else
|
12
19
|
# Rails 3
|
13
20
|
relation.count
|
14
21
|
end
|
22
|
+
if int_or_hash.is_a?(Integer)
|
23
|
+
int_or_hash
|
24
|
+
else
|
25
|
+
# Grouped relations return count-by-group hashes
|
26
|
+
int_or_hash.length
|
27
|
+
end
|
15
28
|
end
|
16
29
|
|
17
30
|
def relation_limit(relation)
|
@@ -21,7 +21,7 @@ module GraphQL
|
|
21
21
|
|
22
22
|
def cursor_for(item)
|
23
23
|
idx = items.find_index(item) + 1
|
24
|
-
|
24
|
+
encode(idx.to_s)
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
@@ -59,7 +59,7 @@ module GraphQL
|
|
59
59
|
sliced_nodes.count > first
|
60
60
|
elsif before
|
61
61
|
# The original array is longer than the `before` index
|
62
|
-
index_from_cursor(before) < items.length
|
62
|
+
index_from_cursor(before) < items.length + 1
|
63
63
|
else
|
64
64
|
false
|
65
65
|
end
|
@@ -15,50 +15,84 @@ module GraphQL
|
|
15
15
|
class PaginationImplementationMissingError < GraphQL::Error
|
16
16
|
end
|
17
17
|
|
18
|
-
# @return [Class] The class to use for wrapping items as `edges { ... }`. Defaults to `Connection::Edge`
|
19
|
-
def self.edge_class
|
20
|
-
self::Edge
|
21
|
-
end
|
22
|
-
|
23
18
|
# @return [Object] A list object, from the application. This is the unpaginated value passed into the connection.
|
24
19
|
attr_reader :items
|
25
20
|
|
26
21
|
# @return [GraphQL::Query::Context]
|
27
22
|
attr_accessor :context
|
28
23
|
|
24
|
+
# @return [Object] the object this collection belongs to
|
25
|
+
attr_accessor :parent
|
26
|
+
|
29
27
|
# Raw access to client-provided values. (`max_page_size` not applied to first or last.)
|
30
28
|
attr_accessor :before_value, :after_value, :first_value, :last_value
|
31
29
|
|
32
|
-
# @return [String, nil] the client-provided cursor
|
30
|
+
# @return [String, nil] the client-provided cursor. `""` is treated as `nil`.
|
33
31
|
def before
|
34
|
-
@
|
32
|
+
if defined?(@before)
|
33
|
+
@before
|
34
|
+
else
|
35
|
+
@before = @before_value == "" ? nil : @before_value
|
36
|
+
end
|
35
37
|
end
|
36
38
|
|
37
|
-
# @return [String, nil] the client-provided cursor
|
39
|
+
# @return [String, nil] the client-provided cursor. `""` is treated as `nil`.
|
38
40
|
def after
|
39
|
-
@
|
41
|
+
if defined?(@after)
|
42
|
+
@after
|
43
|
+
else
|
44
|
+
@after = @after_value == "" ? nil : @after_value
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
48
|
+
# @return [Hash<Symbol => Object>] The field arguments from the field that returned this connection
|
49
|
+
attr_accessor :arguments
|
50
|
+
|
42
51
|
# @param items [Object] some unpaginated collection item, like an `Array` or `ActiveRecord::Relation`
|
43
52
|
# @param context [Query::Context]
|
53
|
+
# @param parent [Object] The object this collection belongs to
|
44
54
|
# @param first [Integer, nil] The limit parameter from the client, if it provided one
|
45
55
|
# @param after [String, nil] A cursor for pagination, if the client provided one
|
46
56
|
# @param last [Integer, nil] Limit parameter from the client, if provided
|
47
57
|
# @param before [String, nil] A cursor for pagination, if the client provided one.
|
58
|
+
# @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
|
48
59
|
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
|
49
|
-
def initialize(items, context: nil, first: nil, after: nil, max_page_size:
|
60
|
+
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil)
|
50
61
|
@items = items
|
62
|
+
@parent = parent
|
51
63
|
@context = context
|
64
|
+
@field = field
|
52
65
|
@first_value = first
|
53
66
|
@after_value = after
|
54
67
|
@last_value = last
|
55
68
|
@before_value = before
|
56
|
-
@
|
69
|
+
@arguments = arguments
|
70
|
+
@edge_class = edge_class || self.class::Edge
|
71
|
+
# This is only true if the object was _initialized_ with an override
|
72
|
+
# or if one is assigned later.
|
73
|
+
@has_max_page_size_override = max_page_size != :not_given
|
74
|
+
@max_page_size = if max_page_size == :not_given
|
75
|
+
nil
|
76
|
+
else
|
77
|
+
max_page_size
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def max_page_size=(new_value)
|
82
|
+
@has_max_page_size_override = true
|
83
|
+
@max_page_size = new_value
|
57
84
|
end
|
58
85
|
|
59
|
-
attr_writer :max_page_size
|
60
86
|
def max_page_size
|
61
|
-
@
|
87
|
+
if @has_max_page_size_override
|
88
|
+
@max_page_size
|
89
|
+
else
|
90
|
+
context.schema.default_max_page_size
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def has_max_page_size_override?
|
95
|
+
@has_max_page_size_override
|
62
96
|
end
|
63
97
|
|
64
98
|
attr_writer :first
|
@@ -76,6 +110,15 @@ module GraphQL
|
|
76
110
|
end
|
77
111
|
end
|
78
112
|
|
113
|
+
# This is called by `Relay::RangeAdd` -- it can be overridden
|
114
|
+
# when `item` needs some modifications based on this connection's state.
|
115
|
+
#
|
116
|
+
# @param item [Object] An item newly added to `items`
|
117
|
+
# @return [Edge]
|
118
|
+
def range_add_edge(item)
|
119
|
+
edge_class.new(item, self)
|
120
|
+
end
|
121
|
+
|
79
122
|
attr_writer :last
|
80
123
|
# @return [Integer, nil] A clamped `last` value. (The underlying instance variable doesn't have limits on it)
|
81
124
|
def last
|
@@ -84,9 +127,15 @@ module GraphQL
|
|
84
127
|
|
85
128
|
# @return [Array<Edge>] {nodes}, but wrapped with Edge instances
|
86
129
|
def edges
|
87
|
-
@edges ||= nodes.map { |n|
|
130
|
+
@edges ||= nodes.map { |n| @edge_class.new(n, self) }
|
88
131
|
end
|
89
132
|
|
133
|
+
# @return [Class] A wrapper class for edges of this connection
|
134
|
+
attr_accessor :edge_class
|
135
|
+
|
136
|
+
# @return [GraphQL::Schema::Field] The field this connection was returned by
|
137
|
+
attr_accessor :field
|
138
|
+
|
90
139
|
# @return [Array<Object>] A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
|
91
140
|
def nodes
|
92
141
|
raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
|
@@ -147,23 +196,29 @@ module GraphQL
|
|
147
196
|
end
|
148
197
|
|
149
198
|
def decode(cursor)
|
150
|
-
context.schema.cursor_encoder.decode(cursor)
|
199
|
+
context.schema.cursor_encoder.decode(cursor, nonce: true)
|
200
|
+
end
|
201
|
+
|
202
|
+
def encode(cursor)
|
203
|
+
context.schema.cursor_encoder.encode(cursor, nonce: true)
|
151
204
|
end
|
152
205
|
|
153
206
|
# A wrapper around paginated items. It includes a {cursor} for pagination
|
154
207
|
# and could be extended with custom relationship-level data.
|
155
208
|
class Edge
|
156
|
-
|
209
|
+
attr_reader :node
|
210
|
+
|
211
|
+
def initialize(node, connection)
|
157
212
|
@connection = connection
|
158
|
-
@
|
213
|
+
@node = node
|
159
214
|
end
|
160
215
|
|
161
|
-
def
|
162
|
-
@
|
216
|
+
def parent
|
217
|
+
@connection.parent
|
163
218
|
end
|
164
219
|
|
165
220
|
def cursor
|
166
|
-
@connection.cursor_for(@
|
221
|
+
@cursor ||= @connection.cursor_for(@node)
|
167
222
|
end
|
168
223
|
end
|
169
224
|
end
|