graphql 1.9.18 → 1.13.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +21 -10
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +44 -7
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +6 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +28 -12
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- 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_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 +7 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +6 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +7 -3
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +5 -1
- data/lib/generators/graphql/templates/schema.erb +22 -27
- data/lib/generators/graphql/templates/union.erb +6 -2
- data/lib/generators/graphql/type_generator.rb +47 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +29 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +174 -67
- data/lib/graphql/analysis/ast/visitor.rb +16 -7
- data/lib/graphql/analysis/ast.rb +21 -11
- data/lib/graphql/argument.rb +8 -36
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +44 -5
- 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 +10 -4
- data/lib/graphql/boolean_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/parse_error_specification.rb +5 -9
- 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/date_encoding_error.rb +16 -0
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +1 -1
- data/lib/graphql/define/defined_object_proxy.rb +5 -8
- data/lib/graphql/define/instance_definable.rb +60 -110
- 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/deprecated_directive.rb +1 -12
- data/lib/graphql/directive/include_directive.rb +1 -1
- data/lib/graphql/directive/skip_directive.rb +1 -1
- data/lib/graphql/directive.rb +9 -6
- data/lib/graphql/enum_type.rb +14 -74
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +110 -8
- 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 +105 -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 +721 -386
- data/lib/graphql/execution/interpreter.rb +42 -19
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +50 -25
- data/lib/graphql/field.rb +15 -119
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/function.rb +5 -30
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +9 -25
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/interface_type.rb +10 -24
- 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/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +12 -6
- data/lib/graphql/introspection/entry_points.rb +9 -9
- 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 +41 -11
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +12 -12
- data/lib/graphql/introspection/type_type.rb +27 -17
- data/lib/graphql/introspection.rb +99 -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/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +116 -63
- data/lib/graphql/language/lexer.rb +53 -27
- data/lib/graphql/language/lexer.rl +5 -3
- data/lib/graphql/language/nodes.rb +67 -93
- data/lib/graphql/language/parser.rb +929 -896
- data/lib/graphql/language/parser.y +125 -102
- data/lib/graphql/language/printer.rb +11 -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 +3 -1
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +47 -58
- data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +226 -0
- data/lib/graphql/pagination/connections.rb +160 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +226 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/arguments.rb +6 -4
- data/lib/graphql/query/arguments_cache.rb +1 -2
- data/lib/graphql/query/context.rb +52 -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 +32 -6
- data/lib/graphql/query/literal_input.rb +31 -11
- 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 +6 -4
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +50 -10
- data/lib/graphql/query.rb +77 -18
- data/lib/graphql/railtie.rb +9 -1
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +12 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +30 -13
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +18 -4
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -2
- data/lib/graphql/relay/global_id_resolve.rb +1 -2
- data/lib/graphql/relay/mutation.rb +3 -87
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/relay/range_add.rb +27 -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 +18 -60
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +274 -18
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +320 -219
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- 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 +2 -2
- data/lib/graphql/schema/directive/skip.rb +2 -2
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +130 -6
- data/lib/graphql/schema/enum.rb +121 -12
- data/lib/graphql/schema/enum_value.rb +24 -7
- data/lib/graphql/schema/field/connection_extension.rb +46 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +465 -181
- data/lib/graphql/schema/field_extension.rb +89 -2
- data/lib/graphql/schema/find_inherited_value.rb +17 -1
- data/lib/graphql/schema/finder.rb +16 -14
- data/lib/graphql/schema/input_object.rb +172 -37
- data/lib/graphql/schema/interface.rb +39 -25
- data/lib/graphql/schema/introspection_system.rb +106 -38
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +65 -1
- data/lib/graphql/schema/loader.rb +145 -102
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +34 -28
- data/lib/graphql/schema/member/build_type.rb +19 -8
- data/lib/graphql/schema/member/cached_graphql_definition.rb +34 -2
- data/lib/graphql/schema/member/has_arguments.rb +206 -13
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- 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 +97 -32
- data/lib/graphql/schema/member/has_interfaces.rb +100 -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/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +11 -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 +37 -1
- data/lib/graphql/schema/object.rb +51 -38
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +40 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
- data/lib/graphql/schema/resolver.rb +133 -79
- data/lib/graphql/schema/scalar.rb +43 -3
- 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/traversal.rb +2 -2
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +19 -5
- data/lib/graphql/schema/union.rb +44 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +14 -4
- 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 +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +193 -34
- data/lib/graphql/schema.rb +882 -247
- data/lib/graphql/static_validation/all_rules.rb +2 -0
- data/lib/graphql/static_validation/base_visitor.rb +17 -10
- 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 +45 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
- 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/directives_are_in_valid_locations.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- 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/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +13 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +43 -9
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
- 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 +84 -30
- data/lib/graphql/subscriptions/instrumentation.rb +10 -6
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +117 -49
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +32 -15
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +66 -10
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +9 -1
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +15 -35
- 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 +16 -8
- data/lib/graphql/types/iso_8601_date_time.rb +32 -10
- data/lib/graphql/types/relay/base_connection.rb +6 -88
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
- data/lib/graphql/types/relay/default_relay.rb +31 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +64 -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 +3 -22
- data/lib/graphql/types/relay/nodes_field.rb +16 -18
- 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 +5 -25
- data/lib/graphql/unresolved_type_error.rb +2 -2
- 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 +87 -31
- data/readme.md +3 -6
- metadata +126 -124
- 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
|
@@ -3,11 +3,9 @@ module GraphQL
|
|
|
3
3
|
class Schema
|
|
4
4
|
class Scalar < GraphQL::Schema::Member
|
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
|
6
|
+
extend GraphQL::Schema::Member::ValidatesInput
|
|
6
7
|
|
|
7
8
|
class << self
|
|
8
|
-
extend Forwardable
|
|
9
|
-
def_delegators :graphql_definition, :coerce_isolated_input, :coerce_isolated_result
|
|
10
|
-
|
|
11
9
|
def coerce_input(val, ctx)
|
|
12
10
|
val
|
|
13
11
|
end
|
|
@@ -16,6 +14,8 @@ module GraphQL
|
|
|
16
14
|
val
|
|
17
15
|
end
|
|
18
16
|
|
|
17
|
+
prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
|
18
|
+
|
|
19
19
|
def to_graphql
|
|
20
20
|
type_defn = GraphQL::ScalarType.new
|
|
21
21
|
type_defn.name = graphql_name
|
|
@@ -24,6 +24,7 @@ module GraphQL
|
|
|
24
24
|
type_defn.coerce_input = method(:coerce_input)
|
|
25
25
|
type_defn.metadata[:type_class] = self
|
|
26
26
|
type_defn.default_scalar = default_scalar
|
|
27
|
+
type_defn.ast_node = ast_node
|
|
27
28
|
type_defn
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -31,12 +32,51 @@ module GraphQL
|
|
|
31
32
|
GraphQL::TypeKinds::SCALAR
|
|
32
33
|
end
|
|
33
34
|
|
|
35
|
+
def specified_by_url(new_url = nil)
|
|
36
|
+
if new_url
|
|
37
|
+
@specified_by_url = new_url
|
|
38
|
+
elsif defined?(@specified_by_url)
|
|
39
|
+
@specified_by_url
|
|
40
|
+
elsif superclass.respond_to?(:specified_by_url)
|
|
41
|
+
superclass.specified_by_url
|
|
42
|
+
else
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
34
47
|
def default_scalar(is_default = nil)
|
|
35
48
|
if !is_default.nil?
|
|
36
49
|
@default_scalar = is_default
|
|
37
50
|
end
|
|
38
51
|
@default_scalar
|
|
39
52
|
end
|
|
53
|
+
|
|
54
|
+
def default_scalar?
|
|
55
|
+
@default_scalar ||= false
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def validate_non_null_input(value, ctx, max_errors: nil)
|
|
59
|
+
result = Query::InputValidationResult.new
|
|
60
|
+
coerced_result = begin
|
|
61
|
+
ctx.query.with_error_handling do
|
|
62
|
+
coerce_input(value, ctx)
|
|
63
|
+
end
|
|
64
|
+
rescue GraphQL::CoercionError => err
|
|
65
|
+
err
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if coerced_result.nil?
|
|
69
|
+
str_value = if value == Float::INFINITY
|
|
70
|
+
""
|
|
71
|
+
else
|
|
72
|
+
" #{GraphQL::Language.serialize(value)}"
|
|
73
|
+
end
|
|
74
|
+
result.add_problem("Could not coerce value#{str_value} to #{graphql_name}")
|
|
75
|
+
elsif coerced_result.is_a?(GraphQL::CoercionError)
|
|
76
|
+
result.add_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
|
|
77
|
+
end
|
|
78
|
+
result
|
|
79
|
+
end
|
|
40
80
|
end
|
|
41
81
|
end
|
|
42
82
|
end
|
|
@@ -12,19 +12,9 @@ module GraphQL
|
|
|
12
12
|
#
|
|
13
13
|
# Also, `#unsubscribe` terminates the subscription.
|
|
14
14
|
class Subscription < GraphQL::Schema::Resolver
|
|
15
|
-
class EarlyTerminationError < StandardError
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Raised when `unsubscribe` is called; caught by `subscriptions.rb`
|
|
19
|
-
class UnsubscribedError < EarlyTerminationError
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Raised when `no_update` is returned; caught by `subscriptions.rb`
|
|
23
|
-
class NoUpdateError < EarlyTerminationError
|
|
24
|
-
end
|
|
25
15
|
extend GraphQL::Schema::Resolver::HasPayloadType
|
|
26
16
|
extend GraphQL::Schema::Member::HasFields
|
|
27
|
-
|
|
17
|
+
NO_UPDATE = :no_update
|
|
28
18
|
# The generated payload type is required; If there's no payload,
|
|
29
19
|
# propagate null.
|
|
30
20
|
null false
|
|
@@ -35,6 +25,22 @@ module GraphQL
|
|
|
35
25
|
@mode = context.query.subscription_update? ? :update : :subscribe
|
|
36
26
|
end
|
|
37
27
|
|
|
28
|
+
def resolve_with_support(**args)
|
|
29
|
+
result = nil
|
|
30
|
+
unsubscribed = true
|
|
31
|
+
catch :graphql_subscription_unsubscribed do
|
|
32
|
+
result = super
|
|
33
|
+
unsubscribed = false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if unsubscribed
|
|
38
|
+
context.skip
|
|
39
|
+
else
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
38
44
|
# Implement the {Resolve} API
|
|
39
45
|
def resolve(**args)
|
|
40
46
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
|
@@ -52,11 +58,9 @@ module GraphQL
|
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
|
|
55
|
-
#
|
|
61
|
+
# The default implementation returns nothing on subscribe.
|
|
56
62
|
# Override it to return an object or
|
|
57
|
-
# `:no_response` to return nothing.
|
|
58
|
-
#
|
|
59
|
-
# The default is `:no_response`.
|
|
63
|
+
# `:no_response` to (explicitly) return nothing.
|
|
60
64
|
def subscribe(args = {})
|
|
61
65
|
:no_response
|
|
62
66
|
end
|
|
@@ -64,15 +68,16 @@ module GraphQL
|
|
|
64
68
|
# Wrap the user-provided `#update` hook
|
|
65
69
|
def resolve_update(**args)
|
|
66
70
|
ret_val = args.any? ? update(**args) : update
|
|
67
|
-
if ret_val ==
|
|
68
|
-
|
|
71
|
+
if ret_val == NO_UPDATE
|
|
72
|
+
context.namespace(:subscriptions)[:no_update] = true
|
|
73
|
+
context.skip
|
|
69
74
|
else
|
|
70
75
|
ret_val
|
|
71
76
|
end
|
|
72
77
|
end
|
|
73
78
|
|
|
74
79
|
# The default implementation returns the root object.
|
|
75
|
-
# Override it to return
|
|
80
|
+
# Override it to return {NO_UPDATE} if you want to
|
|
76
81
|
# skip updates sometimes. Or override it to return a different object.
|
|
77
82
|
def update(args = {})
|
|
78
83
|
object
|
|
@@ -90,17 +95,20 @@ module GraphQL
|
|
|
90
95
|
|
|
91
96
|
# Call this to halt execution and remove this subscription from the system
|
|
92
97
|
def unsubscribe
|
|
93
|
-
|
|
98
|
+
context.namespace(:subscriptions)[:unsubscribed] = true
|
|
99
|
+
throw :graphql_subscription_unsubscribed
|
|
94
100
|
end
|
|
95
101
|
|
|
102
|
+
READING_SCOPE = ::Object.new
|
|
96
103
|
# Call this method to provide a new subscription_scope; OR
|
|
97
104
|
# call it without an argument to get the subscription_scope
|
|
98
105
|
# @param new_scope [Symbol]
|
|
106
|
+
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
|
99
107
|
# @return [Symbol]
|
|
100
|
-
|
|
101
|
-
def self.subscription_scope(new_scope = READING_SCOPE)
|
|
108
|
+
def self.subscription_scope(new_scope = READING_SCOPE, optional: false)
|
|
102
109
|
if new_scope != READING_SCOPE
|
|
103
110
|
@subscription_scope = new_scope
|
|
111
|
+
@subscription_scope_optional = optional
|
|
104
112
|
elsif defined?(@subscription_scope)
|
|
105
113
|
@subscription_scope
|
|
106
114
|
else
|
|
@@ -108,6 +116,34 @@ module GraphQL
|
|
|
108
116
|
end
|
|
109
117
|
end
|
|
110
118
|
|
|
119
|
+
def self.subscription_scope_optional?
|
|
120
|
+
if defined?(@subscription_scope_optional)
|
|
121
|
+
@subscription_scope_optional
|
|
122
|
+
else
|
|
123
|
+
find_inherited_value(:subscription_scope_optional, false)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# This is called during initial subscription to get a "name" for this subscription.
|
|
128
|
+
# Later, when `.trigger` is called, this will be called again to build another "name".
|
|
129
|
+
# Any subscribers with matching topic will begin the update flow.
|
|
130
|
+
#
|
|
131
|
+
# The default implementation creates a string using the field name, subscription scope, and argument keys and values.
|
|
132
|
+
# In that implementation, only `.trigger` calls with _exact matches_ result in updates to subscribers.
|
|
133
|
+
#
|
|
134
|
+
# To implement a filtered stream-type subscription flow, override this method to return a string with field name and subscription scope.
|
|
135
|
+
# Then, implement {#update} to compare its arguments to the current `object` and return {NO_UPDATE} when an
|
|
136
|
+
# update should be filtered out.
|
|
137
|
+
#
|
|
138
|
+
# @see {#update} for how to skip updates when an event comes with a matching topic.
|
|
139
|
+
# @param arguments [Hash<String => Object>] The arguments for this topic, in GraphQL-style (camelized strings)
|
|
140
|
+
# @param field [GraphQL::Schema::Field]
|
|
141
|
+
# @param scope [Object, nil] A value corresponding to `.trigger(... scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions).
|
|
142
|
+
# @return [String] An identifier corresponding to a stream of updates
|
|
143
|
+
def self.topic_for(arguments:, field:, scope:)
|
|
144
|
+
Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
|
|
145
|
+
end
|
|
146
|
+
|
|
111
147
|
# Overriding Resolver#field_options to include subscription_scope
|
|
112
148
|
def self.field_options
|
|
113
149
|
super.merge(
|
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
|
7
7
|
# to the `errors` key. Any already-resolved fields will be in the `data` key, so
|
|
8
8
|
# you'll get a partial response.
|
|
9
9
|
#
|
|
10
|
-
# You can subclass `GraphQL::Schema::Timeout` and override
|
|
10
|
+
# You can subclass `GraphQL::Schema::Timeout` and override `max_seconds` and/or `handle_timeout`
|
|
11
11
|
# to provide custom logic when a timeout error occurs.
|
|
12
12
|
#
|
|
13
13
|
# Note that this will stop a query _in between_ field resolutions, but
|
|
@@ -33,8 +33,6 @@ module GraphQL
|
|
|
33
33
|
# end
|
|
34
34
|
#
|
|
35
35
|
class Timeout
|
|
36
|
-
attr_reader :max_seconds
|
|
37
|
-
|
|
38
36
|
def self.use(schema, **options)
|
|
39
37
|
tracer = new(**options)
|
|
40
38
|
schema.tracer(tracer)
|
|
@@ -48,32 +46,39 @@ module GraphQL
|
|
|
48
46
|
def trace(key, data)
|
|
49
47
|
case key
|
|
50
48
|
when 'execute_multiplex'
|
|
51
|
-
timeout_state = {
|
|
52
|
-
timeout_at: Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + max_seconds * 1000,
|
|
53
|
-
timed_out: false
|
|
54
|
-
}
|
|
55
|
-
|
|
56
49
|
data.fetch(:multiplex).queries.each do |query|
|
|
50
|
+
timeout_duration_s = max_seconds(query)
|
|
51
|
+
timeout_state = if timeout_duration_s == false
|
|
52
|
+
# if the method returns `false`, don't apply a timeout
|
|
53
|
+
false
|
|
54
|
+
else
|
|
55
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
56
|
+
timeout_at = now + (max_seconds(query) * 1000)
|
|
57
|
+
{
|
|
58
|
+
timeout_at: timeout_at,
|
|
59
|
+
timed_out: false
|
|
60
|
+
}
|
|
61
|
+
end
|
|
57
62
|
query.context.namespace(self.class)[:state] = timeout_state
|
|
58
63
|
end
|
|
59
64
|
|
|
60
65
|
yield
|
|
61
66
|
when 'execute_field', 'execute_field_lazy'
|
|
62
|
-
|
|
63
|
-
timeout_state =
|
|
64
|
-
|
|
67
|
+
query_context = data[:context] || data[:query].context
|
|
68
|
+
timeout_state = query_context.namespace(self.class).fetch(:state)
|
|
69
|
+
# If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
|
|
70
|
+
if timeout_state != false && Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
|
|
65
71
|
error = if data[:context]
|
|
66
|
-
|
|
67
|
-
GraphQL::Schema::Timeout::TimeoutError.new(context.parent_type, context.field)
|
|
72
|
+
GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field)
|
|
68
73
|
else
|
|
69
74
|
field = data.fetch(:field)
|
|
70
75
|
GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field)
|
|
71
76
|
end
|
|
72
77
|
|
|
73
78
|
# Only invoke the timeout callback for the first timeout
|
|
74
|
-
|
|
79
|
+
if !timeout_state[:timed_out]
|
|
75
80
|
timeout_state[:timed_out] = true
|
|
76
|
-
handle_timeout(error, query)
|
|
81
|
+
handle_timeout(error, query_context.query)
|
|
77
82
|
end
|
|
78
83
|
|
|
79
84
|
error
|
|
@@ -85,6 +90,15 @@ module GraphQL
|
|
|
85
90
|
end
|
|
86
91
|
end
|
|
87
92
|
|
|
93
|
+
# Called at the start of each query.
|
|
94
|
+
# The default implementation returns the `max_seconds:` value from installing this plugin.
|
|
95
|
+
#
|
|
96
|
+
# @param query [GraphQL::Query] The query that's about to run
|
|
97
|
+
# @return [Integer, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
|
|
98
|
+
def max_seconds(query)
|
|
99
|
+
@max_seconds
|
|
100
|
+
end
|
|
101
|
+
|
|
88
102
|
# Invoked when a query times out.
|
|
89
103
|
# @param error [GraphQL::Schema::Timeout::TimeoutError]
|
|
90
104
|
# @param query [GraphQL::Error]
|
|
@@ -23,12 +23,14 @@ module GraphQL
|
|
|
23
23
|
# Bugsnag.notify(timeout_error, {query_string: query_ctx.query.query_string})
|
|
24
24
|
# end
|
|
25
25
|
#
|
|
26
|
+
# @api deprecated
|
|
27
|
+
# @see Schema::Timeout
|
|
26
28
|
class TimeoutMiddleware
|
|
27
29
|
# @param max_seconds [Numeric] how many seconds the query should be allowed to resolve new fields
|
|
28
30
|
def initialize(max_seconds:, context_key: nil, &block)
|
|
29
31
|
@max_seconds = max_seconds
|
|
30
32
|
if context_key
|
|
31
|
-
warn("TimeoutMiddleware's `context_key` is ignored, timeout data is now stored in isolated storage")
|
|
33
|
+
GraphQL::Deprecation.warn("TimeoutMiddleware's `context_key` is ignored, timeout data is now stored in isolated storage")
|
|
32
34
|
end
|
|
33
35
|
@error_handler = block
|
|
34
36
|
end
|
|
@@ -113,7 +113,7 @@ Some late-bound types couldn't be resolved:
|
|
|
113
113
|
# Find the starting points, then visit them
|
|
114
114
|
visit_roots = [member.query, member.mutation, member.subscription]
|
|
115
115
|
if @introspection
|
|
116
|
-
introspection_types = schema.introspection_system.
|
|
116
|
+
introspection_types = schema.introspection_system.types.values
|
|
117
117
|
visit_roots.concat(introspection_types)
|
|
118
118
|
if member.query
|
|
119
119
|
member.introspection_system.entry_points.each do |introspection_field|
|
|
@@ -173,7 +173,7 @@ Some late-bound types couldn't be resolved:
|
|
|
173
173
|
end
|
|
174
174
|
when Class
|
|
175
175
|
if member.respond_to?(:graphql_definition)
|
|
176
|
-
graphql_member = member.graphql_definition
|
|
176
|
+
graphql_member = member.graphql_definition(silence_deprecation_warning: true)
|
|
177
177
|
visit(schema, graphql_member, context_description)
|
|
178
178
|
else
|
|
179
179
|
raise GraphQL::Schema::InvalidTypeError.new("Unexpected traversal member: #{member} (#{member.class.name})")
|
|
@@ -5,29 +5,37 @@ module GraphQL
|
|
|
5
5
|
module TypeExpression
|
|
6
6
|
# Fetch a type from a type map by its AST specification.
|
|
7
7
|
# Return `nil` if not found.
|
|
8
|
-
# @param
|
|
8
|
+
# @param type_owner [#get_type] A thing for looking up types by name
|
|
9
9
|
# @param ast_node [GraphQL::Language::Nodes::AbstractNode]
|
|
10
|
-
# @return [GraphQL::
|
|
11
|
-
def self.build_type(
|
|
10
|
+
# @return [Class, GraphQL::Schema::NonNull, GraphQL::Schema:List]
|
|
11
|
+
def self.build_type(type_owner, ast_node)
|
|
12
12
|
case ast_node
|
|
13
13
|
when GraphQL::Language::Nodes::TypeName
|
|
14
|
-
|
|
14
|
+
type_owner.get_type(ast_node.name) # rubocop:disable Development/ContextIsPassedCop -- this is a `context` or `warden`, it's already query-aware
|
|
15
15
|
when GraphQL::Language::Nodes::NonNullType
|
|
16
16
|
ast_inner_type = ast_node.of_type
|
|
17
|
-
inner_type = build_type(
|
|
18
|
-
wrap_type(inner_type,
|
|
17
|
+
inner_type = build_type(type_owner, ast_inner_type)
|
|
18
|
+
wrap_type(inner_type, :to_non_null_type)
|
|
19
19
|
when GraphQL::Language::Nodes::ListType
|
|
20
20
|
ast_inner_type = ast_node.of_type
|
|
21
|
-
inner_type = build_type(
|
|
22
|
-
wrap_type(inner_type,
|
|
21
|
+
inner_type = build_type(type_owner, ast_inner_type)
|
|
22
|
+
wrap_type(inner_type, :to_list_type)
|
|
23
|
+
else
|
|
24
|
+
raise "Invariant: unexpected type from ast: #{ast_node.inspect}"
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
class << self
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def wrap_type(type, wrapper_method)
|
|
32
|
+
if type.nil?
|
|
33
|
+
nil
|
|
34
|
+
elsif wrapper_method == :to_list_type || wrapper_method == :to_non_null_type
|
|
35
|
+
type.public_send(wrapper_method)
|
|
36
|
+
else
|
|
37
|
+
raise ArgumentError, "Unexpected wrapper method: #{wrapper_method.inspect}"
|
|
38
|
+
end
|
|
31
39
|
end
|
|
32
40
|
end
|
|
33
41
|
end
|
|
@@ -4,11 +4,9 @@ module GraphQL
|
|
|
4
4
|
class Schema
|
|
5
5
|
# This class joins an object type to an abstract type (interface or union) of which
|
|
6
6
|
# it is a member.
|
|
7
|
-
#
|
|
8
|
-
# TODO: Not yet implemented for interfaces.
|
|
9
7
|
class TypeMembership
|
|
10
8
|
# @return [Class<GraphQL::Schema::Object>]
|
|
11
|
-
|
|
9
|
+
attr_accessor :object_type
|
|
12
10
|
|
|
13
11
|
# @return [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
|
14
12
|
attr_reader :abstract_type
|
|
@@ -26,9 +24,25 @@ module GraphQL
|
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
# @return [Boolean] if false, {#object_type} will be treated as _not_ a member of {#abstract_type}
|
|
29
|
-
def visible?(
|
|
30
|
-
|
|
27
|
+
def visible?(ctx)
|
|
28
|
+
warden = Warden.from_context(ctx)
|
|
29
|
+
(@object_type.respond_to?(:visible?) ? warden.visible_type?(@object_type, ctx) : true) &&
|
|
30
|
+
(@abstract_type.respond_to?(:visible?) ? warden.visible_type?(@abstract_type, ctx) : true)
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
def graphql_name
|
|
34
|
+
"#{@object_type.graphql_name}.#{@abstract_type.kind.interface? ? "implements" : "belongsTo" }.#{@abstract_type.graphql_name}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def path
|
|
38
|
+
graphql_name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def inspect
|
|
42
|
+
"#<#{self.class} #{@object_type.inspect} => #{@abstract_type.inspect}>"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
alias :type_class :itself
|
|
32
46
|
end
|
|
33
47
|
end
|
|
34
48
|
end
|
data/lib/graphql/schema/union.rb
CHANGED
|
@@ -3,17 +3,25 @@ module GraphQL
|
|
|
3
3
|
class Schema
|
|
4
4
|
class Union < GraphQL::Schema::Member
|
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
|
6
|
+
extend GraphQL::Schema::Member::HasUnresolvedTypeError
|
|
6
7
|
|
|
7
8
|
class << self
|
|
9
|
+
def inherited(child_class)
|
|
10
|
+
add_unresolved_type_error(child_class)
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
|
9
15
|
if types.any?
|
|
10
16
|
types.each do |t|
|
|
17
|
+
assert_valid_union_member(t)
|
|
11
18
|
type_memberships << type_membership_class.new(self, t, **options)
|
|
12
19
|
end
|
|
13
20
|
else
|
|
14
21
|
visible_types = []
|
|
22
|
+
warden = Warden.from_context(context)
|
|
15
23
|
type_memberships.each do |type_membership|
|
|
16
|
-
if
|
|
24
|
+
if warden.visible_type_membership?(type_membership, context)
|
|
17
25
|
visible_types << type_membership.object_type
|
|
18
26
|
end
|
|
19
27
|
end
|
|
@@ -21,10 +29,17 @@ module GraphQL
|
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
|
|
32
|
+
def all_possible_types
|
|
33
|
+
type_memberships.map(&:object_type)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
prepend GraphQL::Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
|
37
|
+
|
|
24
38
|
def to_graphql
|
|
25
39
|
type_defn = GraphQL::UnionType.new
|
|
26
40
|
type_defn.name = graphql_name
|
|
27
41
|
type_defn.description = description
|
|
42
|
+
type_defn.ast_node = ast_node
|
|
28
43
|
type_defn.type_memberships = type_memberships
|
|
29
44
|
if respond_to?(:resolve_type)
|
|
30
45
|
type_defn.resolve_type = method(:resolve_type)
|
|
@@ -45,11 +60,37 @@ module GraphQL
|
|
|
45
60
|
GraphQL::TypeKinds::UNION
|
|
46
61
|
end
|
|
47
62
|
|
|
48
|
-
private
|
|
49
|
-
|
|
50
63
|
def type_memberships
|
|
51
64
|
@type_memberships ||= []
|
|
52
65
|
end
|
|
66
|
+
|
|
67
|
+
# Update a type membership whose `.object_type` is a string or late-bound type
|
|
68
|
+
# so that the type membership's `.object_type` is the given `object_type`.
|
|
69
|
+
# (This is used for updating the union after the schema as lazily loaded the union member.)
|
|
70
|
+
# @api private
|
|
71
|
+
def assign_type_membership_object_type(object_type)
|
|
72
|
+
assert_valid_union_member(object_type)
|
|
73
|
+
type_memberships.each { |tm|
|
|
74
|
+
possible_type = tm.object_type
|
|
75
|
+
if possible_type.is_a?(String) && (possible_type == object_type.name)
|
|
76
|
+
# This is a match of Ruby class names, not graphql names,
|
|
77
|
+
# since strings are used to refer to constants.
|
|
78
|
+
tm.object_type = object_type
|
|
79
|
+
elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == object_type.graphql_name
|
|
80
|
+
tm.object_type = object_type
|
|
81
|
+
end
|
|
82
|
+
}
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def assert_valid_union_member(type_defn)
|
|
89
|
+
if type_defn.is_a?(Module) && !type_defn.is_a?(Class)
|
|
90
|
+
# it's an interface type, defined as a module
|
|
91
|
+
raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
53
94
|
end
|
|
54
95
|
end
|
|
55
96
|
end
|
|
@@ -27,8 +27,7 @@ module GraphQL
|
|
|
27
27
|
# @param node_id [String] A unique ID generated by {.encode}
|
|
28
28
|
# @return [Array<(String, String)>] The type name & value passed to {.encode}
|
|
29
29
|
def decode(node_id, separator: self.default_id_separator)
|
|
30
|
-
|
|
31
|
-
Base64Bp.urlsafe_decode64(node_id).split(separator, 2)
|
|
30
|
+
GraphQL::Schema::Base64Encoder.decode(node_id).split(separator, 2)
|
|
32
31
|
end
|
|
33
32
|
end
|
|
34
33
|
end
|
|
@@ -6,6 +6,8 @@ module GraphQL
|
|
|
6
6
|
# Its {RULES} contain objects that respond to `#call(type)`. Rules are
|
|
7
7
|
# looked up for given types (by class ancestry), then applied to
|
|
8
8
|
# the object until an error is returned.
|
|
9
|
+
#
|
|
10
|
+
# Remove this in GraphQL-Ruby 2.0 when schema instances are removed.
|
|
9
11
|
class Validation
|
|
10
12
|
# Lookup the rules for `object` based on its class,
|
|
11
13
|
# Then returns an error message or `nil`
|
|
@@ -133,9 +135,15 @@ module GraphQL
|
|
|
133
135
|
end
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
DEPRECATED_ARGUMENTS_ARE_OPTIONAL = ->(argument) {
|
|
139
|
+
if argument.deprecation_reason && argument.type.non_null?
|
|
140
|
+
"must be optional because it's deprecated"
|
|
141
|
+
end
|
|
142
|
+
}
|
|
143
|
+
|
|
136
144
|
TYPE_IS_VALID_INPUT_TYPE = ->(type) {
|
|
137
145
|
outer_type = type.type
|
|
138
|
-
inner_type = outer_type.
|
|
146
|
+
inner_type = outer_type.respond_to?(:unwrap) ? outer_type.unwrap : nil
|
|
139
147
|
|
|
140
148
|
case inner_type
|
|
141
149
|
when GraphQL::ScalarType, GraphQL::InputObjectType, GraphQL::EnumType
|
|
@@ -154,7 +162,7 @@ module GraphQL
|
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
SCHEMA_CAN_FETCH_IDS = ->(schema) {
|
|
157
|
-
has_node_field = schema.query && schema.query.
|
|
165
|
+
has_node_field = schema.query && schema.query.fields.each_value.any?(&:relay_node_field)
|
|
158
166
|
if has_node_field && schema.object_from_id_proc.nil?
|
|
159
167
|
"schema contains `node(id:...)` field, so you must define a `object_from_id -> (id, ctx) { ... }` function"
|
|
160
168
|
else
|
|
@@ -195,7 +203,7 @@ module GraphQL
|
|
|
195
203
|
RESERVED_TYPE_NAME = ->(type) {
|
|
196
204
|
if type.name.start_with?('__') && !type.introspection?
|
|
197
205
|
# TODO: make this a hard failure in a later version
|
|
198
|
-
warn("Name #{type.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
|
|
206
|
+
GraphQL::Deprecation.warn("Name #{type.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
|
|
199
207
|
nil
|
|
200
208
|
else
|
|
201
209
|
# ok name
|
|
@@ -205,7 +213,7 @@ module GraphQL
|
|
|
205
213
|
RESERVED_NAME = ->(named_thing) {
|
|
206
214
|
if named_thing.name.start_with?('__')
|
|
207
215
|
# TODO: make this a hard failure in a later version
|
|
208
|
-
warn("Name #{named_thing.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
|
|
216
|
+
GraphQL::Deprecation.warn("Name #{named_thing.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
|
|
209
217
|
nil
|
|
210
218
|
else
|
|
211
219
|
# no worries
|
|
@@ -265,8 +273,10 @@ module GraphQL
|
|
|
265
273
|
Rules::NAME_IS_STRING,
|
|
266
274
|
Rules::RESERVED_NAME,
|
|
267
275
|
Rules::DESCRIPTION_IS_STRING_OR_NIL,
|
|
276
|
+
Rules.assert_property(:deprecation_reason, String, NilClass),
|
|
268
277
|
Rules::TYPE_IS_VALID_INPUT_TYPE,
|
|
269
278
|
Rules::DEFAULT_VALUE_IS_VALID_FOR_TYPE,
|
|
279
|
+
Rules::DEPRECATED_ARGUMENTS_ARE_OPTIONAL,
|
|
270
280
|
],
|
|
271
281
|
GraphQL::BaseType => [
|
|
272
282
|
Rules::NAME_IS_STRING,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
class Schema
|
|
5
|
+
class Validator
|
|
6
|
+
# Use this to specifically reject values that respond to `.blank?` and respond truthy for that method.
|
|
7
|
+
#
|
|
8
|
+
# @example Require a non-empty string for an argument
|
|
9
|
+
# argument :name, String, required: true, validate: { allow_blank: false }
|
|
10
|
+
class AllowBlankValidator < Validator
|
|
11
|
+
def initialize(allow_blank_positional, allow_blank: nil, message: "%{validated} can't be blank", **default_options)
|
|
12
|
+
@message = message
|
|
13
|
+
super(**default_options)
|
|
14
|
+
@allow_blank = allow_blank.nil? ? allow_blank_positional : allow_blank
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def validate(_object, _context, value)
|
|
18
|
+
if value.respond_to?(:blank?) && value.blank?
|
|
19
|
+
if (value.nil? && @allow_null) || @allow_blank
|
|
20
|
+
# pass
|
|
21
|
+
else
|
|
22
|
+
@message
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
class Schema
|
|
5
|
+
class Validator
|
|
6
|
+
# Use this to specifically reject or permit `nil` values (given as `null` from GraphQL).
|
|
7
|
+
#
|
|
8
|
+
# @example require a non-null value for an argument if it is provided
|
|
9
|
+
# argument :name, String, required: false, validates: { allow_null: false }
|
|
10
|
+
class AllowNullValidator < Validator
|
|
11
|
+
MESSAGE = "%{validated} can't be null"
|
|
12
|
+
def initialize(allow_null_positional, allow_null: nil, message: MESSAGE, **default_options)
|
|
13
|
+
@message = message
|
|
14
|
+
super(**default_options)
|
|
15
|
+
@allow_null = allow_null.nil? ? allow_null_positional : allow_null
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate(_object, _context, value)
|
|
19
|
+
if value.nil? && !@allow_null
|
|
20
|
+
@message
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphQL
|
|
4
|
+
class Schema
|
|
5
|
+
class Validator
|
|
6
|
+
# Use this to specifically reject values from an argument.
|
|
7
|
+
#
|
|
8
|
+
# @example disallow certain values
|
|
9
|
+
#
|
|
10
|
+
# argument :favorite_non_prime, Integer, required: true,
|
|
11
|
+
# validates: { exclusion: { in: [2, 3, 5, 7, ... ]} }
|
|
12
|
+
#
|
|
13
|
+
class ExclusionValidator < Validator
|
|
14
|
+
# @param message [String]
|
|
15
|
+
# @param in [Array] The values to reject
|
|
16
|
+
def initialize(message: "%{validated} is reserved", in:, **default_options)
|
|
17
|
+
# `in` is a reserved word, so work around that
|
|
18
|
+
@in_list = binding.local_variable_get(:in)
|
|
19
|
+
@message = message
|
|
20
|
+
super(**default_options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate(_object, _context, value)
|
|
24
|
+
if permitted_empty_value?(value)
|
|
25
|
+
# pass
|
|
26
|
+
elsif @in_list.include?(value)
|
|
27
|
+
@message
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|