graphql 0.16.0 → 2.0.15
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 +5 -5
- data/.yardopts +5 -0
- data/lib/generators/graphql/core.rb +69 -0
- data/lib/generators/graphql/enum_generator.rb +27 -0
- 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/install/templates/base_mutation.erb +10 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +12 -0
- data/lib/generators/graphql/install_generator.rb +197 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +21 -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 +30 -0
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +50 -0
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +49 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +22 -0
- data/lib/generators/graphql/templates/base_argument.erb +6 -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 +6 -0
- data/lib/generators/graphql/templates/base_field.erb +7 -0
- data/lib/generators/graphql/templates/base_input_object.erb +7 -0
- data/lib/generators/graphql/templates/base_interface.erb +9 -0
- data/lib/generators/graphql/templates/base_object.erb +7 -0
- data/lib/generators/graphql/templates/base_scalar.erb +6 -0
- data/lib/generators/graphql/templates/base_union.erb +6 -0
- data/lib/generators/graphql/templates/enum.erb +11 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +10 -0
- data/lib/generators/graphql/templates/loader.erb +19 -0
- data/lib/generators/graphql/templates/mutation.erb +16 -0
- 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 +10 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/scalar.erb +17 -0
- data/lib/generators/graphql/templates/schema.erb +30 -0
- data/lib/generators/graphql/templates/union.erb +9 -0
- data/lib/generators/graphql/type_generator.rb +135 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql/analysis/ast/analyzer.rb +84 -0
- data/lib/graphql/analysis/ast/field_usage.rb +57 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +22 -0
- data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
- data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
- data/lib/graphql/analysis/ast/query_depth.rb +55 -0
- data/lib/graphql/analysis/ast/visitor.rb +269 -0
- data/lib/graphql/analysis/ast.rb +81 -0
- data/lib/graphql/analysis.rb +2 -5
- data/lib/graphql/analysis_error.rb +1 -0
- data/lib/graphql/backtrace/inspect_result.rb +50 -0
- data/lib/graphql/backtrace/table.rb +141 -0
- data/lib/graphql/backtrace/traced_error.rb +54 -0
- data/lib/graphql/backtrace/tracer.rb +80 -0
- data/lib/graphql/backtrace.rb +58 -0
- data/lib/graphql/coercion_error.rb +13 -0
- data/lib/graphql/dataloader/null_dataloader.rb +24 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +164 -0
- data/lib/graphql/dataloader.rb +311 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/execution/directive_checks.rb +37 -0
- data/lib/graphql/execution/errors.rb +93 -0
- 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/execution_errors.rb +29 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +77 -0
- data/lib/graphql/execution/interpreter/runtime.rb +994 -0
- data/lib/graphql/execution/interpreter.rb +226 -0
- data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
- data/lib/graphql/execution/lazy.rb +75 -0
- data/lib/graphql/execution/lookahead.rb +311 -0
- data/lib/graphql/execution/multiplex.rb +45 -0
- data/lib/graphql/execution.rb +18 -0
- data/lib/graphql/execution_error.rb +34 -1
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +36 -0
- data/lib/graphql/introspection/base_object.rb +13 -0
- data/lib/graphql/introspection/directive_location_enum.rb +12 -5
- data/lib/graphql/introspection/directive_type.rb +30 -10
- data/lib/graphql/introspection/dynamic_fields.rb +12 -0
- data/lib/graphql/introspection/entry_points.rb +22 -0
- data/lib/graphql/introspection/enum_value_type.rb +21 -8
- data/lib/graphql/introspection/field_type.rb +26 -10
- data/lib/graphql/introspection/input_value_type.rb +64 -14
- data/lib/graphql/introspection/introspection_query.rb +7 -76
- data/lib/graphql/introspection/schema_type.rb +42 -17
- data/lib/graphql/introspection/type_kind_enum.rb +11 -5
- data/lib/graphql/introspection/type_type.rb +104 -16
- data/lib/graphql/introspection.rb +104 -13
- data/lib/graphql/invalid_name_error.rb +11 -0
- data/lib/graphql/invalid_null_error.rb +36 -8
- data/lib/graphql/language/block_string.rb +99 -0
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +41 -0
- data/lib/graphql/language/document_from_schema_definition.rb +335 -0
- data/lib/graphql/language/generation.rb +16 -86
- data/lib/graphql/language/lexer.rb +1436 -705
- data/lib/graphql/language/lexer.rl +172 -64
- data/lib/graphql/language/nodes.rb +617 -105
- data/lib/graphql/language/parser.rb +1524 -430
- data/lib/graphql/language/parser.y +348 -73
- data/lib/graphql/language/printer.rb +386 -0
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +16 -3
- data/lib/graphql/language/visitor.rb +169 -25
- data/lib/graphql/language.rb +30 -0
- data/lib/graphql/load_application_object_failed_error.rb +22 -0
- data/lib/graphql/name_validator.rb +11 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +79 -0
- data/lib/graphql/pagination/connection.rb +253 -0
- data/lib/graphql/pagination/connections.rb +135 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +228 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +24 -0
- data/lib/graphql/query/context.rb +266 -12
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +34 -7
- data/lib/graphql/query/null_context.rb +52 -0
- data/lib/graphql/query/result.rb +63 -0
- data/lib/graphql/query/validation_pipeline.rb +114 -0
- data/lib/graphql/query/variable_validation_error.rb +27 -3
- data/lib/graphql/query/variables.rb +75 -24
- data/lib/graphql/query.rb +359 -92
- data/lib/graphql/railtie.rb +13 -0
- data/lib/graphql/rake_task/validate.rb +63 -0
- data/lib/graphql/rake_task.rb +146 -0
- data/lib/graphql/relay/range_add.rb +52 -0
- data/lib/graphql/relay.rb +3 -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/runtime_type_error.rb +5 -0
- data/lib/graphql/schema/addition.rb +245 -0
- data/lib/graphql/schema/argument.rb +395 -0
- data/lib/graphql/schema/base_64_bp.rb +26 -0
- data/lib/graphql/schema/base_64_encoder.rb +21 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
- data/lib/graphql/schema/build_from_definition.rb +492 -0
- data/lib/graphql/schema/built_in_types.rb +12 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +60 -0
- data/lib/graphql/schema/directive.rb +212 -0
- data/lib/graphql/schema/enum.rb +176 -0
- data/lib/graphql/schema/enum_value.rb +77 -0
- data/lib/graphql/schema/field/connection_extension.rb +80 -0
- data/lib/graphql/schema/field/scope_extension.rb +22 -0
- data/lib/graphql/schema/field.rb +862 -0
- data/lib/graphql/schema/field_extension.rb +156 -0
- data/lib/graphql/schema/find_inherited_value.rb +36 -0
- data/lib/graphql/schema/finder.rb +155 -0
- data/lib/graphql/schema/input_object.rb +258 -0
- data/lib/graphql/schema/interface.rb +113 -0
- data/lib/graphql/schema/introspection_system.rb +164 -0
- data/lib/graphql/schema/invalid_type_error.rb +1 -0
- data/lib/graphql/schema/late_bound_type.rb +37 -0
- data/lib/graphql/schema/list.rb +86 -0
- data/lib/graphql/schema/loader.rb +228 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +124 -0
- data/lib/graphql/schema/member/build_type.rb +178 -0
- data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
- data/lib/graphql/schema/member/has_arguments.rb +376 -0
- 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 +113 -0
- data/lib/graphql/schema/member/has_fields.rb +163 -0
- data/lib/graphql/schema/member/has_interfaces.rb +88 -0
- data/lib/graphql/schema/member/has_path.rb +25 -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/relay_shortcuts.rb +73 -0
- data/lib/graphql/schema/member/scoped.rb +21 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +39 -0
- data/lib/graphql/schema/mutation.rb +85 -0
- data/lib/graphql/schema/non_null.rb +67 -0
- data/lib/graphql/schema/null_mask.rb +11 -0
- data/lib/graphql/schema/object.rb +117 -0
- data/lib/graphql/schema/printer.rb +72 -128
- data/lib/graphql/schema/relay_classic_mutation.rb +179 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +106 -0
- data/lib/graphql/schema/resolver.rb +402 -0
- data/lib/graphql/schema/scalar.rb +68 -0
- data/lib/graphql/schema/subscription.rb +148 -0
- data/lib/graphql/schema/timeout.rb +123 -0
- data/lib/graphql/schema/type_expression.rb +29 -5
- data/lib/graphql/schema/type_membership.rb +51 -0
- data/lib/graphql/schema/union.rb +81 -0
- data/lib/graphql/schema/unique_within_type.rb +34 -0
- 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 +413 -0
- data/lib/graphql/schema/wrapper.rb +24 -0
- data/lib/graphql/schema.rb +1179 -104
- data/lib/graphql/static_validation/all_rules.rb +14 -0
- data/lib/graphql/static_validation/base_visitor.rb +200 -0
- data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
- data/lib/graphql/static_validation/error.rb +46 -0
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +113 -22
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +59 -11
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +62 -8
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +20 -13
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +32 -26
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +21 -23
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +55 -18
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +390 -70
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +54 -37
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +26 -16
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +13 -19
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +22 -33
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- 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/mutation_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -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 +22 -21
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +56 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +36 -18
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +103 -39
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +22 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +92 -70
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/type_stack.rb +85 -24
- data/lib/graphql/static_validation/validation_context.rb +25 -46
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +46 -15
- data/lib/graphql/static_validation.rb +6 -3
- data/lib/graphql/string_encoding_error.rb +20 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +247 -0
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
- data/lib/graphql/subscriptions/event.rb +144 -0
- data/lib/graphql/subscriptions/instrumentation.rb +28 -0
- data/lib/graphql/subscriptions/serialize.rb +158 -0
- data/lib/graphql/subscriptions.rb +306 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +21 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +100 -0
- data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +122 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
- data/lib/graphql/tracing/scout_tracing.rb +54 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +94 -0
- data/lib/graphql/type_kinds.rb +50 -22
- data/lib/graphql/types/big_int.rb +23 -0
- data/lib/graphql/types/boolean.rb +18 -0
- data/lib/graphql/types/float.rb +19 -0
- data/lib/graphql/types/id.rb +24 -0
- data/lib/graphql/types/int.rb +36 -0
- data/lib/graphql/types/iso_8601_date.rb +45 -0
- data/lib/graphql/types/iso_8601_date_time.rb +76 -0
- data/lib/graphql/types/json.rb +25 -0
- data/lib/graphql/types/relay/base_connection.rb +49 -0
- data/lib/graphql/types/relay/base_edge.rb +29 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +154 -0
- data/lib/graphql/types/relay/default_relay.rb +21 -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 +15 -0
- data/lib/graphql/types/relay/node_behaviors.rb +19 -0
- data/lib/graphql/types/relay/page_info.rb +11 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +39 -0
- data/lib/graphql/types/string.rb +29 -0
- data/lib/graphql/types.rb +11 -0
- data/lib/graphql/unauthorized_error.rb +29 -0
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/unresolved_type_error.rb +35 -0
- data/lib/graphql/version.rb +2 -1
- data/lib/graphql.rb +86 -41
- data/readme.md +15 -101
- metadata +394 -279
- data/lib/graphql/analysis/analyze_query.rb +0 -73
- data/lib/graphql/analysis/max_query_complexity.rb +0 -25
- data/lib/graphql/analysis/max_query_depth.rb +0 -25
- data/lib/graphql/analysis/query_complexity.rb +0 -122
- data/lib/graphql/analysis/query_depth.rb +0 -54
- data/lib/graphql/argument.rb +0 -25
- data/lib/graphql/base_type.rb +0 -115
- data/lib/graphql/boolean_type.rb +0 -9
- data/lib/graphql/define/assign_argument.rb +0 -20
- data/lib/graphql/define/assign_enum_value.rb +0 -16
- data/lib/graphql/define/assign_object_field.rb +0 -21
- data/lib/graphql/define/assignment_dictionary.rb +0 -26
- data/lib/graphql/define/defined_object_proxy.rb +0 -32
- data/lib/graphql/define/instance_definable.rb +0 -79
- data/lib/graphql/define/non_null_with_bang.rb +0 -15
- data/lib/graphql/define/type_definer.rb +0 -30
- data/lib/graphql/define.rb +0 -8
- data/lib/graphql/directive/include_directive.rb +0 -10
- data/lib/graphql/directive/skip_directive.rb +0 -11
- data/lib/graphql/directive.rb +0 -49
- data/lib/graphql/enum_type.rb +0 -95
- data/lib/graphql/field.rb +0 -131
- data/lib/graphql/float_type.rb +0 -5
- data/lib/graphql/id_type.rb +0 -12
- data/lib/graphql/input_object_type.rb +0 -71
- data/lib/graphql/int_type.rb +0 -5
- data/lib/graphql/interface_type.rb +0 -38
- data/lib/graphql/internal_representation/node.rb +0 -81
- data/lib/graphql/internal_representation/rewrite.rb +0 -177
- data/lib/graphql/internal_representation.rb +0 -2
- data/lib/graphql/introspection/arguments_field.rb +0 -5
- data/lib/graphql/introspection/enum_values_field.rb +0 -13
- data/lib/graphql/introspection/fields_field.rb +0 -13
- data/lib/graphql/introspection/input_fields_field.rb +0 -12
- data/lib/graphql/introspection/interfaces_field.rb +0 -5
- data/lib/graphql/introspection/of_type_field.rb +0 -6
- data/lib/graphql/introspection/possible_types_field.rb +0 -11
- data/lib/graphql/introspection/schema_field.rb +0 -15
- data/lib/graphql/introspection/type_by_name_field.rb +0 -16
- data/lib/graphql/introspection/typename_field.rb +0 -15
- data/lib/graphql/list_type.rb +0 -46
- data/lib/graphql/non_null_type.rb +0 -43
- data/lib/graphql/object_type.rb +0 -93
- data/lib/graphql/query/arguments.rb +0 -76
- data/lib/graphql/query/directive_resolution.rb +0 -16
- data/lib/graphql/query/executor.rb +0 -45
- data/lib/graphql/query/literal_input.rb +0 -90
- data/lib/graphql/query/serial_execution/execution_context.rb +0 -31
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -82
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -27
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -42
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -107
- data/lib/graphql/query/serial_execution.rb +0 -41
- data/lib/graphql/query/type_resolver.rb +0 -25
- data/lib/graphql/scalar_type.rb +0 -53
- data/lib/graphql/schema/catchall_middleware.rb +0 -34
- data/lib/graphql/schema/middleware_chain.rb +0 -28
- data/lib/graphql/schema/possible_types.rb +0 -34
- data/lib/graphql/schema/reduce_types.rb +0 -68
- data/lib/graphql/schema/rescue_middleware.rb +0 -53
- data/lib/graphql/schema/timeout_middleware.rb +0 -67
- data/lib/graphql/schema/type_map.rb +0 -30
- data/lib/graphql/schema/validation.rb +0 -164
- data/lib/graphql/static_validation/arguments_validator.rb +0 -48
- data/lib/graphql/static_validation/message.rb +0 -36
- data/lib/graphql/string_type.rb +0 -5
- data/lib/graphql/union_type.rb +0 -38
- data/spec/graphql/analysis/analyze_query_spec.rb +0 -50
- data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -62
- data/spec/graphql/analysis/max_query_depth_spec.rb +0 -100
- data/spec/graphql/analysis/query_complexity_spec.rb +0 -235
- data/spec/graphql/analysis/query_depth_spec.rb +0 -80
- data/spec/graphql/argument_spec.rb +0 -20
- data/spec/graphql/base_type_spec.rb +0 -24
- data/spec/graphql/boolean_type_spec.rb +0 -20
- data/spec/graphql/define/instance_definable_spec.rb +0 -55
- data/spec/graphql/directive_spec.rb +0 -77
- data/spec/graphql/enum_type_spec.rb +0 -31
- data/spec/graphql/execution_error_spec.rb +0 -61
- data/spec/graphql/field_spec.rb +0 -92
- data/spec/graphql/float_type_spec.rb +0 -15
- data/spec/graphql/id_type_spec.rb +0 -32
- data/spec/graphql/input_object_type_spec.rb +0 -162
- data/spec/graphql/int_type_spec.rb +0 -15
- data/spec/graphql/interface_type_spec.rb +0 -56
- data/spec/graphql/internal_representation/rewrite_spec.rb +0 -120
- data/spec/graphql/introspection/directive_type_spec.rb +0 -50
- data/spec/graphql/introspection/input_value_type_spec.rb +0 -42
- data/spec/graphql/introspection/introspection_query_spec.rb +0 -10
- data/spec/graphql/introspection/schema_type_spec.rb +0 -45
- data/spec/graphql/introspection/type_type_spec.rb +0 -122
- data/spec/graphql/language/generation_spec.rb +0 -42
- data/spec/graphql/language/parser_spec.rb +0 -442
- data/spec/graphql/language/visitor_spec.rb +0 -49
- data/spec/graphql/list_type_spec.rb +0 -32
- data/spec/graphql/non_null_type_spec.rb +0 -31
- data/spec/graphql/object_type_spec.rb +0 -42
- data/spec/graphql/query/arguments_spec.rb +0 -25
- data/spec/graphql/query/context_spec.rb +0 -83
- data/spec/graphql/query/executor_spec.rb +0 -273
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -53
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -66
- data/spec/graphql/query/type_resolver_spec.rb +0 -8
- data/spec/graphql/query/variables_spec.rb +0 -28
- data/spec/graphql/query_spec.rb +0 -363
- data/spec/graphql/scalar_type_spec.rb +0 -61
- data/spec/graphql/schema/catchall_middleware_spec.rb +0 -32
- data/spec/graphql/schema/middleware_chain_spec.rb +0 -42
- data/spec/graphql/schema/printer_spec.rb +0 -190
- data/spec/graphql/schema/reduce_types_spec.rb +0 -102
- data/spec/graphql/schema/rescue_middleware_spec.rb +0 -33
- data/spec/graphql/schema/timeout_middleware_spec.rb +0 -180
- data/spec/graphql/schema/type_expression_spec.rb +0 -38
- data/spec/graphql/schema/validation_spec.rb +0 -219
- data/spec/graphql/schema_spec.rb +0 -23
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -63
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -48
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -34
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -39
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -60
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -31
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -48
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -47
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -39
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -44
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -49
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -25
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -42
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -44
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -63
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -37
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -53
- data/spec/graphql/static_validation/type_stack_spec.rb +0 -37
- data/spec/graphql/static_validation/validator_spec.rb +0 -69
- data/spec/graphql/string_type_spec.rb +0 -15
- data/spec/graphql/union_type_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -18
- data/spec/support/dairy_app.rb +0 -309
- data/spec/support/dairy_data.rb +0 -23
- data/spec/support/minimum_input_object.rb +0 -16
- data/spec/support/star_wars_data.rb +0 -71
- data/spec/support/star_wars_schema.rb +0 -76
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "set"
|
3
|
+
module GraphQL
|
4
|
+
class Subscriptions
|
5
|
+
# Serialization helpers for passing subscription data around.
|
6
|
+
# @api private
|
7
|
+
module Serialize
|
8
|
+
GLOBALID_KEY = "__gid__"
|
9
|
+
SYMBOL_KEY = "__sym__"
|
10
|
+
SYMBOL_KEYS_KEY = "__sym_keys__"
|
11
|
+
TIMESTAMP_KEY = "__timestamp__"
|
12
|
+
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%N%z" # eg '2020-01-01 23:59:59.123456789+05:00'
|
13
|
+
OPEN_STRUCT_KEY = "__ostruct__"
|
14
|
+
|
15
|
+
module_function
|
16
|
+
|
17
|
+
# @param str [String] A serialized object from {.dump}
|
18
|
+
# @return [Object] An object equivalent to the one passed to {.dump}
|
19
|
+
def load(str)
|
20
|
+
parsed_obj = JSON.parse(str)
|
21
|
+
load_value(parsed_obj)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param obj [Object] Some subscription-related data to dump
|
25
|
+
# @return [String] The stringified object
|
26
|
+
def dump(obj)
|
27
|
+
JSON.generate(dump_value(obj), quirks_mode: true)
|
28
|
+
end
|
29
|
+
|
30
|
+
# This is for turning objects into subscription scopes.
|
31
|
+
# It's a one-way transformation, can't reload this :'(
|
32
|
+
# @param obj [Object]
|
33
|
+
# @return [String]
|
34
|
+
def dump_recursive(obj)
|
35
|
+
case
|
36
|
+
when obj.is_a?(Array)
|
37
|
+
obj.map { |i| dump_recursive(i) }.join(':')
|
38
|
+
when obj.is_a?(Hash)
|
39
|
+
obj.map { |k, v| "#{dump_recursive(k)}:#{dump_recursive(v)}" }.join(":")
|
40
|
+
when obj.is_a?(GraphQL::Schema::InputObject)
|
41
|
+
dump_recursive(obj.to_h)
|
42
|
+
when obj.respond_to?(:to_gid_param)
|
43
|
+
obj.to_gid_param
|
44
|
+
when obj.respond_to?(:to_param)
|
45
|
+
obj.to_param
|
46
|
+
else
|
47
|
+
obj.to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
private
|
53
|
+
|
54
|
+
# @param value [Object] A parsed JSON object
|
55
|
+
# @return [Object] An object that load Global::Identification recursive
|
56
|
+
def load_value(value)
|
57
|
+
if value.is_a?(Array)
|
58
|
+
is_gids = (v1 = value[0]).is_a?(Hash) && v1.size == 1 && v1[GLOBALID_KEY]
|
59
|
+
if is_gids
|
60
|
+
# Assume it's an array of global IDs
|
61
|
+
ids = value.map { |v| v[GLOBALID_KEY] }
|
62
|
+
GlobalID::Locator.locate_many(ids)
|
63
|
+
else
|
64
|
+
value.map { |item| load_value(item) }
|
65
|
+
end
|
66
|
+
elsif value.is_a?(Hash)
|
67
|
+
if value.size == 1
|
68
|
+
case value.keys.first # there's only 1 key
|
69
|
+
when GLOBALID_KEY
|
70
|
+
GlobalID::Locator.locate(value[GLOBALID_KEY])
|
71
|
+
when SYMBOL_KEY
|
72
|
+
value[SYMBOL_KEY].to_sym
|
73
|
+
when TIMESTAMP_KEY
|
74
|
+
timestamp_class_name, *timestamp_args = value[TIMESTAMP_KEY]
|
75
|
+
timestamp_class = Object.const_get(timestamp_class_name)
|
76
|
+
if defined?(ActiveSupport::TimeWithZone) && timestamp_class <= ActiveSupport::TimeWithZone
|
77
|
+
zone_name, timestamp_s = timestamp_args
|
78
|
+
zone = ActiveSupport::TimeZone[zone_name]
|
79
|
+
raise "Zone #{zone_name} not found, unable to deserialize" unless zone
|
80
|
+
zone.strptime(timestamp_s, TIMESTAMP_FORMAT)
|
81
|
+
else
|
82
|
+
timestamp_s = timestamp_args.first
|
83
|
+
timestamp_class.strptime(timestamp_s, TIMESTAMP_FORMAT)
|
84
|
+
end
|
85
|
+
when OPEN_STRUCT_KEY
|
86
|
+
ostruct_values = load_value(value[OPEN_STRUCT_KEY])
|
87
|
+
OpenStruct.new(ostruct_values)
|
88
|
+
else
|
89
|
+
key = value.keys.first
|
90
|
+
{ key => load_value(value[key]) }
|
91
|
+
end
|
92
|
+
else
|
93
|
+
loaded_h = {}
|
94
|
+
sym_keys = value.fetch(SYMBOL_KEYS_KEY, [])
|
95
|
+
value.each do |k, v|
|
96
|
+
if k == SYMBOL_KEYS_KEY
|
97
|
+
next
|
98
|
+
end
|
99
|
+
if sym_keys.include?(k)
|
100
|
+
k = k.to_sym
|
101
|
+
end
|
102
|
+
loaded_h[k] = load_value(v)
|
103
|
+
end
|
104
|
+
loaded_h
|
105
|
+
end
|
106
|
+
else
|
107
|
+
value
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param obj [Object] Some subscription-related data to dump
|
112
|
+
# @return [Object] The object that converted Global::Identification
|
113
|
+
def dump_value(obj)
|
114
|
+
if obj.is_a?(Array)
|
115
|
+
obj.map{|item| dump_value(item)}
|
116
|
+
elsif obj.is_a?(Hash)
|
117
|
+
symbol_keys = nil
|
118
|
+
dumped_h = {}
|
119
|
+
obj.each do |k, v|
|
120
|
+
dumped_h[k.to_s] = dump_value(v)
|
121
|
+
if k.is_a?(Symbol)
|
122
|
+
symbol_keys ||= Set.new
|
123
|
+
symbol_keys << k.to_s
|
124
|
+
end
|
125
|
+
end
|
126
|
+
if symbol_keys
|
127
|
+
dumped_h[SYMBOL_KEYS_KEY] = symbol_keys.to_a
|
128
|
+
end
|
129
|
+
dumped_h
|
130
|
+
elsif obj.is_a?(Symbol)
|
131
|
+
{ SYMBOL_KEY => obj.to_s }
|
132
|
+
elsif obj.respond_to?(:to_gid_param)
|
133
|
+
{GLOBALID_KEY => obj.to_gid_param}
|
134
|
+
elsif defined?(ActiveSupport::TimeWithZone) && obj.is_a?(ActiveSupport::TimeWithZone) && obj.class.name != Time.name
|
135
|
+
# This handles a case where Rails prior to 7 would
|
136
|
+
# make the class ActiveSupport::TimeWithZone return "Time" for
|
137
|
+
# its name. In Rails 7, it will now return "ActiveSupport::TimeWithZone",
|
138
|
+
# which happens to be incompatible with expectations we have
|
139
|
+
# with what a Time class supports ( notably, strptime in `load_value` ).
|
140
|
+
#
|
141
|
+
# This now passes along the name of the zone, such that a future deserialization
|
142
|
+
# of this string will use the correct time zone from the ActiveSupport TimeZone
|
143
|
+
# list to produce the time.
|
144
|
+
#
|
145
|
+
{ TIMESTAMP_KEY => [obj.class.name, obj.time_zone.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
146
|
+
elsif obj.is_a?(Date) || obj.is_a?(Time)
|
147
|
+
# DateTime extends Date; for TimeWithZone, call `.utc` first.
|
148
|
+
{ TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
149
|
+
elsif obj.is_a?(OpenStruct)
|
150
|
+
{ OPEN_STRUCT_KEY => dump_value(obj.to_h) }
|
151
|
+
else
|
152
|
+
obj
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "securerandom"
|
3
|
+
require "graphql/subscriptions/broadcast_analyzer"
|
4
|
+
require "graphql/subscriptions/event"
|
5
|
+
require "graphql/subscriptions/instrumentation"
|
6
|
+
require "graphql/subscriptions/serialize"
|
7
|
+
require "graphql/subscriptions/action_cable_subscriptions"
|
8
|
+
require "graphql/subscriptions/default_subscription_resolve_extension"
|
9
|
+
|
10
|
+
module GraphQL
|
11
|
+
class Subscriptions
|
12
|
+
# Raised when either:
|
13
|
+
# - the triggered `event_name` doesn't match a field in the schema; or
|
14
|
+
# - one or more arguments don't match the field arguments
|
15
|
+
class InvalidTriggerError < GraphQL::Error
|
16
|
+
end
|
17
|
+
|
18
|
+
# Raised when either:
|
19
|
+
# - An initial subscription didn't have a value for `context[subscription_scope]`
|
20
|
+
# - Or, an update didn't pass `.trigger(..., scope:)`
|
21
|
+
# When raised, the initial subscription or update fails completely.
|
22
|
+
class SubscriptionScopeMissingError < GraphQL::Error
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see {Subscriptions#initialize} for options, concrete implementations may add options.
|
26
|
+
def self.use(defn, options = {})
|
27
|
+
schema = defn.is_a?(Class) ? defn : defn.target
|
28
|
+
|
29
|
+
if schema.subscriptions(inherited: false)
|
30
|
+
raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
|
31
|
+
end
|
32
|
+
|
33
|
+
instrumentation = Subscriptions::Instrumentation.new(schema: schema)
|
34
|
+
defn.instrument(:query, instrumentation)
|
35
|
+
options[:schema] = schema
|
36
|
+
schema.subscriptions = self.new(**options)
|
37
|
+
schema.add_subscription_extension_if_necessary
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param schema [Class] the GraphQL schema this manager belongs to
|
42
|
+
# @param validate_update [Boolean] If false, then validation is skipped when executing updates
|
43
|
+
def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest)
|
44
|
+
if broadcast
|
45
|
+
schema.query_analyzer(Subscriptions::BroadcastAnalyzer)
|
46
|
+
end
|
47
|
+
@default_broadcastable = default_broadcastable
|
48
|
+
@schema = schema
|
49
|
+
@validate_update = validate_update
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Boolean] Used when fields don't have `broadcastable:` explicitly set
|
53
|
+
attr_reader :default_broadcastable
|
54
|
+
|
55
|
+
# Fetch subscriptions matching this field + arguments pair
|
56
|
+
# And pass them off to the queue.
|
57
|
+
# @param event_name [String]
|
58
|
+
# @param args [Hash<String, Symbol => Object]
|
59
|
+
# @param object [Object]
|
60
|
+
# @param scope [Symbol, String]
|
61
|
+
# @param context [Hash]
|
62
|
+
# @return [void]
|
63
|
+
def trigger(event_name, args, object, scope: nil, context: {})
|
64
|
+
# Make something as context-like as possible, even though there isn't a current query:
|
65
|
+
dummy_query = GraphQL::Query.new(@schema, "", validate: false, context: context)
|
66
|
+
context = dummy_query.context
|
67
|
+
event_name = event_name.to_s
|
68
|
+
|
69
|
+
# Try with the verbatim input first:
|
70
|
+
field = @schema.get_field(@schema.subscription, event_name, context)
|
71
|
+
|
72
|
+
if field.nil?
|
73
|
+
# And if it wasn't found, normalize it:
|
74
|
+
normalized_event_name = normalize_name(event_name)
|
75
|
+
field = @schema.get_field(@schema.subscription, normalized_event_name, context)
|
76
|
+
if field.nil?
|
77
|
+
raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})"
|
78
|
+
end
|
79
|
+
else
|
80
|
+
# Since we found a field, the original input was already normalized
|
81
|
+
normalized_event_name = event_name
|
82
|
+
end
|
83
|
+
|
84
|
+
# Normalize symbol-keyed args to strings, try camelizing them
|
85
|
+
# Should this accept a real context somehow?
|
86
|
+
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
|
87
|
+
|
88
|
+
event = Subscriptions::Event.new(
|
89
|
+
name: normalized_event_name,
|
90
|
+
arguments: normalized_args,
|
91
|
+
field: field,
|
92
|
+
scope: scope,
|
93
|
+
)
|
94
|
+
execute_all(event, object)
|
95
|
+
end
|
96
|
+
|
97
|
+
# `event` was triggered on `object`, and `subscription_id` was subscribed,
|
98
|
+
# so it should be updated.
|
99
|
+
#
|
100
|
+
# Load `subscription_id`'s GraphQL data, re-evaluate the query and return the result.
|
101
|
+
#
|
102
|
+
# @param subscription_id [String]
|
103
|
+
# @param event [GraphQL::Subscriptions::Event] The event which was triggered
|
104
|
+
# @param object [Object] The value for the subscription field
|
105
|
+
# @return [GraphQL::Query::Result]
|
106
|
+
def execute_update(subscription_id, event, object)
|
107
|
+
# Lookup the saved data for this subscription
|
108
|
+
query_data = read_subscription(subscription_id)
|
109
|
+
if query_data.nil?
|
110
|
+
delete_subscription(subscription_id)
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
# Fetch the required keys from the saved data
|
115
|
+
query_string = query_data.fetch(:query_string)
|
116
|
+
variables = query_data.fetch(:variables)
|
117
|
+
context = query_data.fetch(:context)
|
118
|
+
operation_name = query_data.fetch(:operation_name)
|
119
|
+
execute_options = {
|
120
|
+
query: query_string,
|
121
|
+
context: context,
|
122
|
+
subscription_topic: event.topic,
|
123
|
+
operation_name: operation_name,
|
124
|
+
variables: variables,
|
125
|
+
root_value: object,
|
126
|
+
}
|
127
|
+
execute_options[:validate] = validate_update?(**execute_options)
|
128
|
+
result = @schema.execute(**execute_options)
|
129
|
+
subscriptions_context = result.context.namespace(:subscriptions)
|
130
|
+
if subscriptions_context[:no_update]
|
131
|
+
result = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
unsubscribed = subscriptions_context[:unsubscribed]
|
135
|
+
|
136
|
+
if unsubscribed
|
137
|
+
# `unsubscribe` was called, clean up on our side
|
138
|
+
# TODO also send `{more: false}` to client?
|
139
|
+
delete_subscription(subscription_id)
|
140
|
+
result = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
result
|
144
|
+
end
|
145
|
+
|
146
|
+
# Define this method to customize whether to validate
|
147
|
+
# this subscription when executing an update.
|
148
|
+
#
|
149
|
+
# @return [Boolean] defaults to `true`, or false if `validate: false` is provided.
|
150
|
+
def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:)
|
151
|
+
@validate_update
|
152
|
+
end
|
153
|
+
|
154
|
+
# Run the update query for this subscription and deliver it
|
155
|
+
# @see {#execute_update}
|
156
|
+
# @see {#deliver}
|
157
|
+
# @return [void]
|
158
|
+
def execute(subscription_id, event, object)
|
159
|
+
res = execute_update(subscription_id, event, object)
|
160
|
+
if !res.nil?
|
161
|
+
deliver(subscription_id, res)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Event `event` occurred on `object`,
|
166
|
+
# Update all subscribers.
|
167
|
+
# @param event [Subscriptions::Event]
|
168
|
+
# @param object [Object]
|
169
|
+
# @return [void]
|
170
|
+
def execute_all(event, object)
|
171
|
+
raise GraphQL::RequiredImplementationMissingError
|
172
|
+
end
|
173
|
+
|
174
|
+
# The system wants to send an update to this subscription.
|
175
|
+
# Read its data and return it.
|
176
|
+
# @param subscription_id [String]
|
177
|
+
# @return [Hash] Containing required keys
|
178
|
+
def read_subscription(subscription_id)
|
179
|
+
raise GraphQL::RequiredImplementationMissingError
|
180
|
+
end
|
181
|
+
|
182
|
+
# A subscription query was re-evaluated, returning `result`.
|
183
|
+
# The result should be send to `subscription_id`.
|
184
|
+
# @param subscription_id [String]
|
185
|
+
# @param result [Hash]
|
186
|
+
# @return [void]
|
187
|
+
def deliver(subscription_id, result)
|
188
|
+
raise GraphQL::RequiredImplementationMissingError
|
189
|
+
end
|
190
|
+
|
191
|
+
# `query` was executed and found subscriptions to `events`.
|
192
|
+
# Update the database to reflect this new state.
|
193
|
+
# @param query [GraphQL::Query]
|
194
|
+
# @param events [Array<GraphQL::Subscriptions::Event>]
|
195
|
+
# @return [void]
|
196
|
+
def write_subscription(query, events)
|
197
|
+
raise GraphQL::RequiredImplementationMissingError
|
198
|
+
end
|
199
|
+
|
200
|
+
# A subscription was terminated server-side.
|
201
|
+
# Clean up the database.
|
202
|
+
# @param subscription_id [String]
|
203
|
+
# @return void.
|
204
|
+
def delete_subscription(subscription_id)
|
205
|
+
raise GraphQL::RequiredImplementationMissingError
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [String] A new unique identifier for a subscription
|
209
|
+
def build_id
|
210
|
+
SecureRandom.uuid
|
211
|
+
end
|
212
|
+
|
213
|
+
# Convert a user-provided event name or argument
|
214
|
+
# to the equivalent in GraphQL.
|
215
|
+
#
|
216
|
+
# By default, it converts the identifier to camelcase.
|
217
|
+
# Override this in a subclass to change the transformation.
|
218
|
+
#
|
219
|
+
# @param event_or_arg_name [String, Symbol]
|
220
|
+
# @return [String]
|
221
|
+
def normalize_name(event_or_arg_name)
|
222
|
+
Schema::Member::BuildType.camelize(event_or_arg_name.to_s)
|
223
|
+
end
|
224
|
+
|
225
|
+
# @return [Boolean] if true, then a query like this one would be broadcasted
|
226
|
+
def broadcastable?(query_str, **query_options)
|
227
|
+
query = GraphQL::Query.new(@schema, query_str, **query_options)
|
228
|
+
if !query.valid?
|
229
|
+
raise "Invalid query: #{query.validation_errors.map(&:to_h).inspect}"
|
230
|
+
end
|
231
|
+
GraphQL::Analysis::AST.analyze_query(query, @schema.query_analyzers)
|
232
|
+
query.context.namespace(:subscriptions)[:subscription_broadcastable]
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
# Recursively normalize `args` as belonging to `arg_owner`:
|
238
|
+
# - convert symbols to strings,
|
239
|
+
# - if needed, camelize the string (using {#normalize_name})
|
240
|
+
# @param arg_owner [GraphQL::Field, GraphQL::BaseType]
|
241
|
+
# @param args [Hash, Array, Any] some GraphQL input value to coerce as `arg_owner`
|
242
|
+
# @return [Any] normalized arguments value
|
243
|
+
def normalize_arguments(event_name, arg_owner, args, context)
|
244
|
+
case arg_owner
|
245
|
+
when GraphQL::Schema::Field, Class
|
246
|
+
if arg_owner.is_a?(Class) && !arg_owner.kind.input_object?
|
247
|
+
# it's a type, but not an input object
|
248
|
+
return args
|
249
|
+
end
|
250
|
+
normalized_args = {}
|
251
|
+
missing_arg_names = []
|
252
|
+
args.each do |k, v|
|
253
|
+
arg_name = k.to_s
|
254
|
+
arg_defn = arg_owner.get_argument(arg_name, context)
|
255
|
+
if arg_defn
|
256
|
+
normalized_arg_name = arg_name
|
257
|
+
else
|
258
|
+
normalized_arg_name = normalize_name(arg_name)
|
259
|
+
arg_defn = arg_owner.get_argument(normalized_arg_name, context)
|
260
|
+
end
|
261
|
+
|
262
|
+
if arg_defn
|
263
|
+
if arg_defn.loads
|
264
|
+
normalized_arg_name = arg_defn.keyword.to_s
|
265
|
+
end
|
266
|
+
normalized = normalize_arguments(event_name, arg_defn.type, v, context)
|
267
|
+
normalized_args[normalized_arg_name] = normalized
|
268
|
+
else
|
269
|
+
# Couldn't find a matching argument definition
|
270
|
+
missing_arg_names << arg_name
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Backfill default values so that trigger arguments
|
275
|
+
# match query arguments.
|
276
|
+
arg_owner.arguments(context).each do |_name, arg_defn|
|
277
|
+
if arg_defn.default_value? && !normalized_args.key?(arg_defn.name)
|
278
|
+
default_value = arg_defn.default_value
|
279
|
+
# We don't have an underlying "object" here, so it can't call methods.
|
280
|
+
# This is broken.
|
281
|
+
normalized_args[arg_defn.name] = arg_defn.prepare_value(nil, default_value, context: context)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
if missing_arg_names.any?
|
286
|
+
arg_owner_name = if arg_owner.is_a?(GraphQL::Schema::Field)
|
287
|
+
arg_owner.path
|
288
|
+
elsif arg_owner.is_a?(Class)
|
289
|
+
arg_owner.graphql_name
|
290
|
+
else
|
291
|
+
arg_owner.to_s
|
292
|
+
end
|
293
|
+
raise InvalidTriggerError, "Can't trigger Subscription.#{event_name}, received undefined arguments: #{missing_arg_names.join(", ")}. (Should match arguments of #{arg_owner_name}.)"
|
294
|
+
end
|
295
|
+
|
296
|
+
normalized_args
|
297
|
+
when GraphQL::Schema::List
|
298
|
+
args.map { |a| normalize_arguments(event_name, arg_owner.of_type, a, context) }
|
299
|
+
when GraphQL::Schema::NonNull
|
300
|
+
normalize_arguments(event_name, arg_owner.of_type, args, context)
|
301
|
+
else
|
302
|
+
args
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql/tracing/notifications_tracing'
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module Tracing
|
7
|
+
# This implementation forwards events to ActiveSupport::Notifications
|
8
|
+
# with a `graphql` suffix.
|
9
|
+
#
|
10
|
+
# @see KEYS for event names
|
11
|
+
module ActiveSupportNotificationsTracing
|
12
|
+
# A cache of frequently-used keys to avoid needless string allocations
|
13
|
+
KEYS = NotificationsTracing::KEYS
|
14
|
+
NOTIFICATIONS_ENGINE = NotificationsTracing.new(ActiveSupport::Notifications) if defined?(ActiveSupport::Notifications)
|
15
|
+
|
16
|
+
def self.trace(key, metadata, &blk)
|
17
|
+
NOTIFICATIONS_ENGINE.trace(key, metadata, &blk)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Tracing
|
5
|
+
|
6
|
+
# This class uses the AppopticsAPM SDK from the appoptics_apm gem to create
|
7
|
+
# traces for GraphQL.
|
8
|
+
#
|
9
|
+
# There are 4 configurations available. They can be set in the
|
10
|
+
# appoptics_apm config file or in code. Please see:
|
11
|
+
# {https://docs.appoptics.com/kb/apm_tracing/ruby/configure}
|
12
|
+
#
|
13
|
+
# AppOpticsAPM::Config[:graphql][:enabled] = true|false
|
14
|
+
# AppOpticsAPM::Config[:graphql][:transaction_name] = true|false
|
15
|
+
# AppOpticsAPM::Config[:graphql][:sanitize_query] = true|false
|
16
|
+
# AppOpticsAPM::Config[:graphql][:remove_comments] = true|false
|
17
|
+
class AppOpticsTracing < GraphQL::Tracing::PlatformTracing
|
18
|
+
# These GraphQL events will show up as 'graphql.prep' spans
|
19
|
+
PREP_KEYS = ['lex', 'parse', 'validate', 'analyze_query', 'analyze_multiplex'].freeze
|
20
|
+
# These GraphQL events will show up as 'graphql.execute' spans
|
21
|
+
EXEC_KEYS = ['execute_multiplex', 'execute_query', 'execute_query_lazy'].freeze
|
22
|
+
|
23
|
+
# During auto-instrumentation this version of AppOpticsTracing is compared
|
24
|
+
# with the version provided in the appoptics_apm gem, so that the newer
|
25
|
+
# version of the class can be used
|
26
|
+
|
27
|
+
def self.version
|
28
|
+
Gem::Version.new('1.0.0')
|
29
|
+
end
|
30
|
+
|
31
|
+
self.platform_keys = {
|
32
|
+
'lex' => 'lex',
|
33
|
+
'parse' => 'parse',
|
34
|
+
'validate' => 'validate',
|
35
|
+
'analyze_query' => 'analyze_query',
|
36
|
+
'analyze_multiplex' => 'analyze_multiplex',
|
37
|
+
'execute_multiplex' => 'execute_multiplex',
|
38
|
+
'execute_query' => 'execute_query',
|
39
|
+
'execute_query_lazy' => 'execute_query_lazy'
|
40
|
+
}
|
41
|
+
|
42
|
+
def platform_trace(platform_key, _key, data)
|
43
|
+
return yield if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
44
|
+
|
45
|
+
layer = span_name(platform_key)
|
46
|
+
kvs = metadata(data, layer)
|
47
|
+
kvs[:Key] = platform_key if (PREP_KEYS + EXEC_KEYS).include?(platform_key)
|
48
|
+
|
49
|
+
transaction_name(kvs[:InboundQuery]) if kvs[:InboundQuery] && layer == 'graphql.execute'
|
50
|
+
|
51
|
+
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
52
|
+
kvs.clear # we don't have to send them twice
|
53
|
+
yield
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def platform_field_key(type, field)
|
58
|
+
"graphql.#{type.graphql_name}.#{field.graphql_name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def platform_authorized_key(type)
|
62
|
+
"graphql.authorized.#{type.graphql_name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def platform_resolve_type_key(type)
|
66
|
+
"graphql.resolve_type.#{type.graphql_name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def gql_config
|
72
|
+
::AppOpticsAPM::Config[:graphql] ||= {}
|
73
|
+
end
|
74
|
+
|
75
|
+
def transaction_name(query)
|
76
|
+
return if gql_config[:transaction_name] == false ||
|
77
|
+
::AppOpticsAPM::SDK.get_transaction_name
|
78
|
+
|
79
|
+
split_query = query.strip.split(/\W+/, 3)
|
80
|
+
split_query[0] = 'query' if split_query[0].empty?
|
81
|
+
name = "graphql.#{split_query[0..1].join('.')}"
|
82
|
+
|
83
|
+
::AppOpticsAPM::SDK.set_transaction_name(name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def multiplex_transaction_name(names)
|
87
|
+
return if gql_config[:transaction_name] == false ||
|
88
|
+
::AppOpticsAPM::SDK.get_transaction_name
|
89
|
+
|
90
|
+
name = "graphql.multiplex.#{names.join('.')}"
|
91
|
+
name = "#{name[0..251]}..." if name.length > 254
|
92
|
+
|
93
|
+
::AppOpticsAPM::SDK.set_transaction_name(name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def span_name(key)
|
97
|
+
return 'graphql.prep' if PREP_KEYS.include?(key)
|
98
|
+
return 'graphql.execute' if EXEC_KEYS.include?(key)
|
99
|
+
|
100
|
+
key[/^graphql\./] ? key : "graphql.#{key}"
|
101
|
+
end
|
102
|
+
|
103
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
104
|
+
def metadata(data, layer)
|
105
|
+
data.keys.map do |key|
|
106
|
+
case key
|
107
|
+
when :context
|
108
|
+
graphql_context(data[key], layer)
|
109
|
+
when :query
|
110
|
+
graphql_query(data[key])
|
111
|
+
when :query_string
|
112
|
+
graphql_query_string(data[key])
|
113
|
+
when :multiplex
|
114
|
+
graphql_multiplex(data[key])
|
115
|
+
when :path
|
116
|
+
[key, data[key].join(".")]
|
117
|
+
else
|
118
|
+
[key, data[key]]
|
119
|
+
end
|
120
|
+
end.flatten(2).each_slice(2).to_h.merge(Spec: 'graphql')
|
121
|
+
end
|
122
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
123
|
+
|
124
|
+
def graphql_context(context, layer)
|
125
|
+
context.errors && context.errors.each do |err|
|
126
|
+
AppOpticsAPM::API.log_exception(layer, err)
|
127
|
+
end
|
128
|
+
|
129
|
+
[[:Path, context.path.join('.')]]
|
130
|
+
end
|
131
|
+
|
132
|
+
def graphql_query(query)
|
133
|
+
return [] unless query
|
134
|
+
|
135
|
+
query_string = query.query_string
|
136
|
+
query_string = remove_comments(query_string) if gql_config[:remove_comments] != false
|
137
|
+
query_string = sanitize(query_string) if gql_config[:sanitize_query] != false
|
138
|
+
|
139
|
+
[[:InboundQuery, query_string],
|
140
|
+
[:Operation, query.selected_operation_name]]
|
141
|
+
end
|
142
|
+
|
143
|
+
def graphql_query_string(query_string)
|
144
|
+
query_string = remove_comments(query_string) if gql_config[:remove_comments] != false
|
145
|
+
query_string = sanitize(query_string) if gql_config[:sanitize_query] != false
|
146
|
+
|
147
|
+
[:InboundQuery, query_string]
|
148
|
+
end
|
149
|
+
|
150
|
+
def graphql_multiplex(data)
|
151
|
+
names = data.queries.map(&:operations).map(&:keys).flatten.compact
|
152
|
+
multiplex_transaction_name(names) if names.size > 1
|
153
|
+
|
154
|
+
[:Operations, names.join(', ')]
|
155
|
+
end
|
156
|
+
|
157
|
+
def sanitize(query)
|
158
|
+
return unless query
|
159
|
+
|
160
|
+
# remove arguments
|
161
|
+
query.gsub(/"[^"]*"/, '"?"') # strings
|
162
|
+
.gsub(/-?[0-9]*\.?[0-9]+e?[0-9]*/, '?') # ints + floats
|
163
|
+
.gsub(/\[[^\]]*\]/, '[?]') # arrays
|
164
|
+
end
|
165
|
+
|
166
|
+
def remove_comments(query)
|
167
|
+
return unless query
|
168
|
+
|
169
|
+
query.gsub(/#[^\n\r]*/, '')
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|