graphql_cody 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +5 -0
- data/MIT-LICENSE +20 -0
- data/lib/generators/graphql/core.rb +74 -0
- data/lib/generators/graphql/enum_generator.rb +33 -0
- data/lib/generators/graphql/install_generator.rb +190 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +21 -0
- data/lib/generators/graphql/mutation_generator.rb +55 -0
- data/lib/generators/graphql/object_generator.rb +79 -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 +20 -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_mutation.erb +10 -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 +7 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
- data/lib/generators/graphql/templates/interface.erb +8 -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_type.erb +12 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +8 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/scalar.erb +15 -0
- data/lib/generators/graphql/templates/schema.erb +27 -0
- data/lib/generators/graphql/templates/union.erb +7 -0
- data/lib/generators/graphql/type_generator.rb +98 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql/analysis/analyze_query.rb +98 -0
- data/lib/graphql/analysis/ast/analyzer.rb +84 -0
- data/lib/graphql/analysis/ast/field_usage.rb +51 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -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 +56 -0
- data/lib/graphql/analysis/ast/visitor.rb +268 -0
- data/lib/graphql/analysis/ast.rb +91 -0
- data/lib/graphql/analysis/field_usage.rb +45 -0
- data/lib/graphql/analysis/max_query_complexity.rb +26 -0
- data/lib/graphql/analysis/max_query_depth.rb +26 -0
- data/lib/graphql/analysis/query_complexity.rb +88 -0
- data/lib/graphql/analysis/query_depth.rb +43 -0
- data/lib/graphql/analysis/reducer_state.rb +48 -0
- data/lib/graphql/analysis.rb +9 -0
- data/lib/graphql/analysis_error.rb +5 -0
- data/lib/graphql/argument.rb +131 -0
- data/lib/graphql/authorization.rb +82 -0
- data/lib/graphql/backtrace/inspect_result.rb +50 -0
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +159 -0
- data/lib/graphql/backtrace/traced_error.rb +54 -0
- data/lib/graphql/backtrace/tracer.rb +81 -0
- data/lib/graphql/backtrace.rb +64 -0
- data/lib/graphql/backwards_compatibility.rb +61 -0
- data/lib/graphql/base_type.rb +230 -0
- data/lib/graphql/boolean_type.rb +2 -0
- data/lib/graphql/coercion_error.rb +13 -0
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +200 -0
- data/lib/graphql/compatibility/execution_specification.rb +436 -0
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +111 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +215 -0
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +87 -0
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +79 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +266 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +682 -0
- data/lib/graphql/compatibility.rb +5 -0
- data/lib/graphql/dataloader/null_dataloader.rb +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/define/assign_argument.rb +12 -0
- data/lib/graphql/define/assign_connection.rb +13 -0
- data/lib/graphql/define/assign_enum_value.rb +18 -0
- data/lib/graphql/define/assign_global_id_field.rb +11 -0
- data/lib/graphql/define/assign_mutation_function.rb +34 -0
- data/lib/graphql/define/assign_object_field.rb +42 -0
- data/lib/graphql/define/defined_object_proxy.rb +53 -0
- data/lib/graphql/define/instance_definable.rb +240 -0
- data/lib/graphql/define/no_definition_error.rb +7 -0
- data/lib/graphql/define/non_null_with_bang.rb +16 -0
- data/lib/graphql/define/type_definer.rb +31 -0
- data/lib/graphql/define.rb +31 -0
- data/lib/graphql/deprecated_dsl.rb +55 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive/deprecated_directive.rb +2 -0
- data/lib/graphql/directive/include_directive.rb +2 -0
- data/lib/graphql/directive/skip_directive.rb +2 -0
- data/lib/graphql/directive.rb +107 -0
- data/lib/graphql/enum_type.rb +133 -0
- data/lib/graphql/execution/directive_checks.rb +37 -0
- data/lib/graphql/execution/errors.rb +163 -0
- data/lib/graphql/execution/execute.rb +333 -0
- data/lib/graphql/execution/flatten.rb +40 -0
- data/lib/graphql/execution/instrumentation.rb +92 -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 +103 -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 +70 -0
- data/lib/graphql/execution/interpreter/runtime.rb +949 -0
- data/lib/graphql/execution/interpreter.rb +122 -0
- data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
- data/lib/graphql/execution/lazy/resolve.rb +91 -0
- data/lib/graphql/execution/lazy.rb +83 -0
- data/lib/graphql/execution/lookahead.rb +307 -0
- data/lib/graphql/execution/multiplex.rb +214 -0
- data/lib/graphql/execution/typecast.rb +50 -0
- data/lib/graphql/execution.rb +11 -0
- data/lib/graphql/execution_error.rb +58 -0
- data/lib/graphql/field/resolve.rb +59 -0
- data/lib/graphql/field.rb +226 -0
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/float_type.rb +2 -0
- data/lib/graphql/function.rb +128 -0
- data/lib/graphql/id_type.rb +2 -0
- data/lib/graphql/input_object_type.rb +138 -0
- data/lib/graphql/int_type.rb +2 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +36 -0
- data/lib/graphql/interface_type.rb +72 -0
- data/lib/graphql/internal_representation/document.rb +27 -0
- data/lib/graphql/internal_representation/node.rb +206 -0
- data/lib/graphql/internal_representation/print.rb +51 -0
- data/lib/graphql/internal_representation/rewrite.rb +184 -0
- data/lib/graphql/internal_representation/scope.rb +88 -0
- data/lib/graphql/internal_representation/visit.rb +36 -0
- data/lib/graphql/internal_representation.rb +7 -0
- data/lib/graphql/introspection/base_object.rb +13 -0
- data/lib/graphql/introspection/directive_location_enum.rb +15 -0
- data/lib/graphql/introspection/directive_type.rb +29 -0
- data/lib/graphql/introspection/dynamic_fields.rb +17 -0
- data/lib/graphql/introspection/entry_points.rb +35 -0
- data/lib/graphql/introspection/enum_value_type.rb +23 -0
- data/lib/graphql/introspection/field_type.rb +28 -0
- data/lib/graphql/introspection/input_value_type.rb +67 -0
- data/lib/graphql/introspection/introspection_query.rb +7 -0
- data/lib/graphql/introspection/schema_type.rb +44 -0
- data/lib/graphql/introspection/type_kind_enum.rb +13 -0
- data/lib/graphql/introspection/type_type.rb +95 -0
- data/lib/graphql/introspection.rb +114 -0
- data/lib/graphql/invalid_name_error.rb +11 -0
- data/lib/graphql/invalid_null_error.rb +50 -0
- 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 +347 -0
- data/lib/graphql/language/generation.rb +24 -0
- data/lib/graphql/language/lexer.rb +1467 -0
- data/lib/graphql/language/lexer.rl +258 -0
- data/lib/graphql/language/nodes.rb +707 -0
- data/lib/graphql/language/parser.rb +1974 -0
- data/lib/graphql/language/parser.y +544 -0
- data/lib/graphql/language/printer.rb +366 -0
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +34 -0
- data/lib/graphql/language/visitor.rb +242 -0
- data/lib/graphql/language.rb +36 -0
- data/lib/graphql/list_type.rb +80 -0
- data/lib/graphql/load_application_object_failed_error.rb +22 -0
- data/lib/graphql/name_validator.rb +11 -0
- data/lib/graphql/non_null_type.rb +71 -0
- data/lib/graphql/object_type.rb +130 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +48 -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 +196 -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/arguments.rb +189 -0
- data/lib/graphql/query/arguments_cache.rb +24 -0
- data/lib/graphql/query/context.rb +371 -0
- data/lib/graphql/query/executor.rb +52 -0
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +43 -0
- data/lib/graphql/query/literal_input.rb +136 -0
- data/lib/graphql/query/null_context.rb +55 -0
- data/lib/graphql/query/result.rb +63 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +92 -0
- data/lib/graphql/query/serial_execution/operation_resolution.rb +19 -0
- data/lib/graphql/query/serial_execution/selection_resolution.rb +23 -0
- data/lib/graphql/query/serial_execution/value_resolution.rb +87 -0
- data/lib/graphql/query/serial_execution.rb +40 -0
- data/lib/graphql/query/validation_pipeline.rb +139 -0
- data/lib/graphql/query/variable_validation_error.rb +44 -0
- data/lib/graphql/query/variables.rb +78 -0
- data/lib/graphql/query.rb +454 -0
- data/lib/graphql/railtie.rb +117 -0
- data/lib/graphql/rake_task/validate.rb +63 -0
- data/lib/graphql/rake_task.rb +145 -0
- data/lib/graphql/relay/array_connection.rb +83 -0
- data/lib/graphql/relay/base_connection.rb +189 -0
- data/lib/graphql/relay/connection_instrumentation.rb +54 -0
- data/lib/graphql/relay/connection_resolve.rb +43 -0
- data/lib/graphql/relay/connection_type.rb +41 -0
- data/lib/graphql/relay/edge.rb +27 -0
- data/lib/graphql/relay/edge_type.rb +19 -0
- data/lib/graphql/relay/edges_instrumentation.rb +39 -0
- data/lib/graphql/relay/global_id_resolve.rb +18 -0
- data/lib/graphql/relay/mongo_relation_connection.rb +50 -0
- data/lib/graphql/relay/mutation/instrumentation.rb +23 -0
- data/lib/graphql/relay/mutation/resolve.rb +56 -0
- data/lib/graphql/relay/mutation/result.rb +38 -0
- data/lib/graphql/relay/mutation.rb +106 -0
- data/lib/graphql/relay/node.rb +39 -0
- data/lib/graphql/relay/page_info.rb +7 -0
- data/lib/graphql/relay/range_add.rb +59 -0
- data/lib/graphql/relay/relation_connection.rb +188 -0
- data/lib/graphql/relay/type_extensions.rb +32 -0
- data/lib/graphql/relay.rb +18 -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/scalar_type.rb +91 -0
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +383 -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 +477 -0
- data/lib/graphql/schema/built_in_types.rb +12 -0
- data/lib/graphql/schema/catchall_middleware.rb +35 -0
- data/lib/graphql/schema/default_parse_error.rb +10 -0
- data/lib/graphql/schema/default_type_error.rb +17 -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/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +60 -0
- data/lib/graphql/schema/directive.rb +210 -0
- data/lib/graphql/schema/enum.rb +193 -0
- data/lib/graphql/schema/enum_value.rb +97 -0
- data/lib/graphql/schema/field/connection_extension.rb +76 -0
- data/lib/graphql/schema/field/scope_extension.rb +22 -0
- data/lib/graphql/schema/field.rb +880 -0
- data/lib/graphql/schema/field_extension.rb +69 -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 +253 -0
- data/lib/graphql/schema/interface.rb +136 -0
- data/lib/graphql/schema/introspection_system.rb +169 -0
- data/lib/graphql/schema/invalid_type_error.rb +7 -0
- data/lib/graphql/schema/late_bound_type.rb +33 -0
- data/lib/graphql/schema/list.rb +75 -0
- data/lib/graphql/schema/loader.rb +226 -0
- data/lib/graphql/schema/member/accepts_definition.rb +159 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +129 -0
- data/lib/graphql/schema/member/build_type.rb +180 -0
- data/lib/graphql/schema/member/cached_graphql_definition.rb +31 -0
- data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
- data/lib/graphql/schema/member/has_arguments.rb +332 -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 +98 -0
- data/lib/graphql/schema/member/has_fields.rb +163 -0
- data/lib/graphql/schema/member/has_interfaces.rb +90 -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/instrumentation.rb +131 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -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 +161 -0
- data/lib/graphql/schema/middleware_chain.rb +82 -0
- data/lib/graphql/schema/mutation.rb +94 -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 +150 -0
- data/lib/graphql/schema/possible_types.rb +44 -0
- data/lib/graphql/schema/printer.rb +100 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +160 -0
- data/lib/graphql/schema/rescue_middleware.rb +60 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +96 -0
- data/lib/graphql/schema/resolver.rb +397 -0
- data/lib/graphql/schema/scalar.rb +69 -0
- data/lib/graphql/schema/subscription.rb +155 -0
- data/lib/graphql/schema/timeout.rb +123 -0
- data/lib/graphql/schema/timeout_middleware.rb +88 -0
- data/lib/graphql/schema/traversal.rb +228 -0
- data/lib/graphql/schema/type_expression.rb +43 -0
- data/lib/graphql/schema/type_membership.rb +48 -0
- data/lib/graphql/schema/union.rb +95 -0
- data/lib/graphql/schema/unique_within_type.rb +34 -0
- data/lib/graphql/schema/validation.rb +313 -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 +68 -0
- data/lib/graphql/schema/validator.rb +174 -0
- data/lib/graphql/schema/warden.rb +409 -0
- data/lib/graphql/schema/wrapper.rb +29 -0
- data/lib/graphql/schema.rb +1945 -0
- data/lib/graphql/static_validation/all_rules.rb +40 -0
- data/lib/graphql/static_validation/base_visitor.rb +217 -0
- data/lib/graphql/static_validation/default_visitor.rb +15 -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 +139 -0
- data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +66 -0
- 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 +71 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +23 -0
- 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 +65 -0
- 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 +30 -0
- 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 +73 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +418 -0
- 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 +73 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +39 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +21 -0
- 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 +37 -0
- 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 +32 -0
- 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/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/required_arguments_are_present.rb +37 -0
- 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 +50 -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 +46 -0
- 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 +153 -0
- 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 +39 -0
- 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 +155 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/type_stack.rb +216 -0
- data/lib/graphql/static_validation/validation_context.rb +49 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +96 -0
- data/lib/graphql/static_validation.rb +19 -0
- data/lib/graphql/string_encoding_error.rb +20 -0
- data/lib/graphql/string_type.rb +2 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +245 -0
- 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 +144 -0
- data/lib/graphql/subscriptions/instrumentation.rb +79 -0
- data/lib/graphql/subscriptions/serialize.rb +138 -0
- data/lib/graphql/subscriptions/subscription_root.rb +76 -0
- data/lib/graphql/subscriptions.rb +299 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +35 -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 +76 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
- data/lib/graphql/tracing/platform_tracing.rb +139 -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/skylight_tracing.rb +70 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +95 -0
- data/lib/graphql/type_kinds.rb +77 -0
- 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 +34 -0
- data/lib/graphql/types/iso_8601_date_time.rb +65 -0
- data/lib/graphql/types/json.rb +25 -0
- data/lib/graphql/types/relay/base_connection.rb +39 -0
- data/lib/graphql/types/relay/base_edge.rb +29 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +15 -0
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +25 -0
- data/lib/graphql/types/relay/nodes_field.rb +27 -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 +41 -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/union_type.rb +115 -0
- data/lib/graphql/unresolved_type_error.rb +35 -0
- data/lib/graphql/upgrader/member.rb +937 -0
- data/lib/graphql/upgrader/schema.rb +38 -0
- data/lib/graphql/version.rb +4 -0
- data/lib/graphql.rb +168 -0
- data/readme.md +49 -0
- metadata +714 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
# This plugin will stop resolving new fields after `max_seconds` have elapsed.
|
6
|
+
# After the time has passed, any remaining fields will be `nil`, with errors added
|
7
|
+
# to the `errors` key. Any already-resolved fields will be in the `data` key, so
|
8
|
+
# you'll get a partial response.
|
9
|
+
#
|
10
|
+
# You can subclass `GraphQL::Schema::Timeout` and override `max_seconds` and/or `handle_timeout`
|
11
|
+
# to provide custom logic when a timeout error occurs.
|
12
|
+
#
|
13
|
+
# Note that this will stop a query _in between_ field resolutions, but
|
14
|
+
# it doesn't interrupt long-running `resolve` functions. Be sure to use
|
15
|
+
# timeout options for external connections. For more info, see
|
16
|
+
# www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/
|
17
|
+
#
|
18
|
+
# @example Stop resolving fields after 2 seconds
|
19
|
+
# class MySchema < GraphQL::Schema
|
20
|
+
# use GraphQL::Schema::Timeout, max_seconds: 2
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example Notifying Bugsnag and logging a timeout
|
24
|
+
# class MyTimeout < GraphQL::Schema::Timeout
|
25
|
+
# def handle_timeout(error, query)
|
26
|
+
# Rails.logger.warn("GraphQL Timeout: #{error.message}: #{query.query_string}")
|
27
|
+
# Bugsnag.notify(error, {query_string: query.query_string})
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# class MySchema < GraphQL::Schema
|
32
|
+
# use MyTimeout, max_seconds: 2
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
class Timeout
|
36
|
+
def self.use(schema, **options)
|
37
|
+
tracer = new(**options)
|
38
|
+
schema.tracer(tracer)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param max_seconds [Numeric] how many seconds the query should be allowed to resolve new fields
|
42
|
+
def initialize(max_seconds:)
|
43
|
+
@max_seconds = max_seconds
|
44
|
+
end
|
45
|
+
|
46
|
+
def trace(key, data)
|
47
|
+
case key
|
48
|
+
when 'execute_multiplex'
|
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
|
62
|
+
query.context.namespace(self.class)[:state] = timeout_state
|
63
|
+
end
|
64
|
+
|
65
|
+
yield
|
66
|
+
when 'execute_field', 'execute_field_lazy'
|
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)
|
71
|
+
error = if data[:context]
|
72
|
+
GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field)
|
73
|
+
else
|
74
|
+
field = data.fetch(:field)
|
75
|
+
GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Only invoke the timeout callback for the first timeout
|
79
|
+
if !timeout_state[:timed_out]
|
80
|
+
timeout_state[:timed_out] = true
|
81
|
+
handle_timeout(error, query_context.query)
|
82
|
+
end
|
83
|
+
|
84
|
+
error
|
85
|
+
else
|
86
|
+
yield
|
87
|
+
end
|
88
|
+
else
|
89
|
+
yield
|
90
|
+
end
|
91
|
+
end
|
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
|
+
|
102
|
+
# Invoked when a query times out.
|
103
|
+
# @param error [GraphQL::Schema::Timeout::TimeoutError]
|
104
|
+
# @param query [GraphQL::Error]
|
105
|
+
def handle_timeout(error, query)
|
106
|
+
# override to do something interesting
|
107
|
+
end
|
108
|
+
|
109
|
+
# This error is raised when a query exceeds `max_seconds`.
|
110
|
+
# Since it's a child of {GraphQL::ExecutionError},
|
111
|
+
# its message will be added to the response's `errors` key.
|
112
|
+
#
|
113
|
+
# To raise an error that will stop query resolution, use a custom block
|
114
|
+
# to take this error and raise a new one which _doesn't_ descend from {GraphQL::ExecutionError},
|
115
|
+
# such as `RuntimeError`.
|
116
|
+
class TimeoutError < GraphQL::ExecutionError
|
117
|
+
def initialize(parent_type, field)
|
118
|
+
super("Timeout on #{parent_type.graphql_name}.#{field.graphql_name}")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "delegate"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
class Schema
|
6
|
+
# This middleware will stop resolving new fields after `max_seconds` have elapsed.
|
7
|
+
# After the time has passed, any remaining fields will be `nil`, with errors added
|
8
|
+
# to the `errors` key. Any already-resolved fields will be in the `data` key, so
|
9
|
+
# you'll get a partial response.
|
10
|
+
#
|
11
|
+
# You can provide a block which will be called with any timeout errors that occur.
|
12
|
+
#
|
13
|
+
# Note that this will stop a query _in between_ field resolutions, but
|
14
|
+
# it doesn't interrupt long-running `resolve` functions. Be sure to use
|
15
|
+
# timeout options for external connections. For more info, see
|
16
|
+
# www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/
|
17
|
+
#
|
18
|
+
# @example Stop resolving fields after 2 seconds
|
19
|
+
# MySchema.middleware << GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 2)
|
20
|
+
#
|
21
|
+
# @example Notifying Bugsnag on a timeout
|
22
|
+
# MySchema.middleware << GraphQL::Schema::TimeoutMiddleware(max_seconds: 1.5) do |timeout_error, query|
|
23
|
+
# Bugsnag.notify(timeout_error, {query_string: query_ctx.query.query_string})
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @api deprecated
|
27
|
+
# @see Schema::Timeout
|
28
|
+
class TimeoutMiddleware
|
29
|
+
# @param max_seconds [Numeric] how many seconds the query should be allowed to resolve new fields
|
30
|
+
def initialize(max_seconds:, context_key: nil, &block)
|
31
|
+
@max_seconds = max_seconds
|
32
|
+
if context_key
|
33
|
+
GraphQL::Deprecation.warn("TimeoutMiddleware's `context_key` is ignored, timeout data is now stored in isolated storage")
|
34
|
+
end
|
35
|
+
@error_handler = block
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(parent_type, parent_object, field_definition, field_args, query_context)
|
39
|
+
ns = query_context.namespace(self.class)
|
40
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
41
|
+
timeout_at = ns[:timeout_at] ||= now + @max_seconds
|
42
|
+
|
43
|
+
if timeout_at < now
|
44
|
+
on_timeout(parent_type, parent_object, field_definition, field_args, query_context)
|
45
|
+
else
|
46
|
+
yield
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# This is called when a field _would_ be resolved, except that we're over the time limit.
|
51
|
+
# @return [GraphQL::Schema::TimeoutMiddleware::TimeoutError] An error whose message will be added to the `errors` key
|
52
|
+
def on_timeout(parent_type, parent_object, field_definition, field_args, field_context)
|
53
|
+
err = GraphQL::Schema::TimeoutMiddleware::TimeoutError.new(parent_type, field_definition)
|
54
|
+
if @error_handler
|
55
|
+
query_proxy = TimeoutQueryProxy.new(field_context.query, field_context)
|
56
|
+
@error_handler.call(err, query_proxy)
|
57
|
+
end
|
58
|
+
err
|
59
|
+
end
|
60
|
+
|
61
|
+
# This behaves like {GraphQL::Query} but {#context} returns
|
62
|
+
# the _field-level_ context, not the query-level context.
|
63
|
+
# This means you can reliably get the `irep_node` and `path`
|
64
|
+
# from it after the fact.
|
65
|
+
class TimeoutQueryProxy < SimpleDelegator
|
66
|
+
def initialize(query, ctx)
|
67
|
+
@context = ctx
|
68
|
+
super(query)
|
69
|
+
end
|
70
|
+
|
71
|
+
attr_reader :context
|
72
|
+
end
|
73
|
+
|
74
|
+
# This error is raised when a query exceeds `max_seconds`.
|
75
|
+
# Since it's a child of {GraphQL::ExecutionError},
|
76
|
+
# its message will be added to the response's `errors` key.
|
77
|
+
#
|
78
|
+
# To raise an error that will stop query resolution, use a custom block
|
79
|
+
# to take this error and raise a new one which _doesn't_ descend from {GraphQL::ExecutionError},
|
80
|
+
# such as `RuntimeError`.
|
81
|
+
class TimeoutError < GraphQL::ExecutionError
|
82
|
+
def initialize(parent_type, field_defn)
|
83
|
+
super("Timeout on #{parent_type.name}.#{field_defn.name}")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
# Visit the members of this schema and build up artifacts for runtime.
|
5
|
+
# @api private
|
6
|
+
class Traversal
|
7
|
+
# @return [Hash<String => GraphQL::BaseType]
|
8
|
+
attr_reader :type_map
|
9
|
+
|
10
|
+
# @return [Hash<String => Hash<String => GraphQL::Field>>]
|
11
|
+
attr_reader :instrumented_field_map
|
12
|
+
|
13
|
+
# @return [Hash<String => Array<GraphQL::Field || GraphQL::Argument || GraphQL::Directive>]
|
14
|
+
attr_reader :type_reference_map
|
15
|
+
|
16
|
+
# @return [Hash<String => Array<GraphQL::BaseType>]
|
17
|
+
attr_reader :union_memberships
|
18
|
+
|
19
|
+
|
20
|
+
# @param schema [GraphQL::Schema]
|
21
|
+
def initialize(schema, introspection: true)
|
22
|
+
@schema = schema
|
23
|
+
@introspection = introspection
|
24
|
+
built_in_insts = [
|
25
|
+
GraphQL::Relay::ConnectionInstrumentation,
|
26
|
+
GraphQL::Relay::EdgesInstrumentation,
|
27
|
+
GraphQL::Relay::Mutation::Instrumentation,
|
28
|
+
]
|
29
|
+
|
30
|
+
if schema.query_execution_strategy != GraphQL::Execution::Interpreter
|
31
|
+
built_in_insts << GraphQL::Schema::Member::Instrumentation
|
32
|
+
end
|
33
|
+
|
34
|
+
@field_instrumenters =
|
35
|
+
schema.instrumenters[:field] +
|
36
|
+
built_in_insts +
|
37
|
+
schema.instrumenters[:field_after_built_ins]
|
38
|
+
|
39
|
+
# These fields have types specified by _name_,
|
40
|
+
# So we need to inspect the schema and find those types,
|
41
|
+
# then update their references.
|
42
|
+
@late_bound_fields = []
|
43
|
+
@type_map = {}
|
44
|
+
@instrumented_field_map = Hash.new { |h, k| h[k] = {} }
|
45
|
+
@type_reference_map = Hash.new { |h, k| h[k] = [] }
|
46
|
+
@union_memberships = Hash.new { |h, k| h[k] = [] }
|
47
|
+
visit(schema, schema, nil)
|
48
|
+
resolve_late_bound_fields
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# A brute-force appraoch to late binding.
|
54
|
+
# Just keep trying the whole list, hoping that they
|
55
|
+
# eventually all resolve.
|
56
|
+
# This could be replaced with proper dependency tracking.
|
57
|
+
def resolve_late_bound_fields
|
58
|
+
# This is a bit tricky, with the writes going to internal state.
|
59
|
+
prev_late_bound_fields = @late_bound_fields
|
60
|
+
# Things might get added here during `visit...`
|
61
|
+
# or they might be added manually if we can't find them by hand
|
62
|
+
@late_bound_fields = []
|
63
|
+
prev_late_bound_fields.each do |(owner_type, field_defn, dynamic_field)|
|
64
|
+
if @type_map.key?(field_defn.type.unwrap.name)
|
65
|
+
late_bound_return_type = field_defn.type
|
66
|
+
resolved_type = @type_map.fetch(late_bound_return_type.unwrap.name)
|
67
|
+
wrapped_resolved_type = rewrap_resolved_type(late_bound_return_type, resolved_type)
|
68
|
+
# Update the field definition in place? :thinking_face:
|
69
|
+
field_defn.type = wrapped_resolved_type
|
70
|
+
visit_field_on_type(@schema, owner_type, field_defn, dynamic_field: dynamic_field)
|
71
|
+
else
|
72
|
+
@late_bound_fields << [owner_type, field_defn, dynamic_field]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if @late_bound_fields.any?
|
77
|
+
# If we visited each field and failed to resolve _any_,
|
78
|
+
# then we're stuck.
|
79
|
+
if @late_bound_fields == prev_late_bound_fields
|
80
|
+
type_names = prev_late_bound_fields.map { |f| f[1] }.map(&:type).map(&:unwrap).map(&:name).uniq
|
81
|
+
raise <<-ERR
|
82
|
+
Some late-bound types couldn't be resolved:
|
83
|
+
|
84
|
+
- #{type_names}
|
85
|
+
- Found __* types: #{@type_map.keys.select { |k| k.start_with?("__") }}
|
86
|
+
ERR
|
87
|
+
else
|
88
|
+
resolve_late_bound_fields
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# The late-bound type may be wrapped with list or non-null types.
|
94
|
+
# Apply the same wrapping to the resolve type and
|
95
|
+
# return the maybe-wrapped type
|
96
|
+
def rewrap_resolved_type(late_bound_type, resolved_inner_type)
|
97
|
+
case late_bound_type
|
98
|
+
when GraphQL::NonNullType
|
99
|
+
rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_non_null_type
|
100
|
+
when GraphQL::ListType
|
101
|
+
rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_list_type
|
102
|
+
when GraphQL::Schema::LateBoundType
|
103
|
+
resolved_inner_type
|
104
|
+
else
|
105
|
+
raise "Unexpected late_bound_type: #{late_bound_type.inspect} (#{late_bound_type.class})"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def visit(schema, member, context_description)
|
110
|
+
case member
|
111
|
+
when GraphQL::Schema
|
112
|
+
member.directives.each { |name, directive| visit(schema, directive, "Directive #{name}") }
|
113
|
+
# Find the starting points, then visit them
|
114
|
+
visit_roots = [member.query, member.mutation, member.subscription]
|
115
|
+
if @introspection
|
116
|
+
introspection_types = schema.introspection_system.types.values
|
117
|
+
visit_roots.concat(introspection_types)
|
118
|
+
if member.query
|
119
|
+
member.introspection_system.entry_points.each do |introspection_field|
|
120
|
+
# Visit this so that arguments class is preconstructed
|
121
|
+
# Skip validation since it begins with "__"
|
122
|
+
visit_field_on_type(schema, member.query, introspection_field, dynamic_field: true)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
visit_roots.concat(member.orphan_types)
|
127
|
+
visit_roots.compact!
|
128
|
+
visit_roots.each { |t| visit(schema, t, t.name) }
|
129
|
+
when GraphQL::Directive
|
130
|
+
member.arguments.each do |name, argument|
|
131
|
+
@type_reference_map[argument.type.unwrap.to_s] << argument
|
132
|
+
visit(schema, argument.type, "Directive argument #{member.name}.#{name}")
|
133
|
+
end
|
134
|
+
# Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
|
135
|
+
# to be passed to a resolver proc
|
136
|
+
GraphQL::Query::Arguments.construct_arguments_class(member)
|
137
|
+
when GraphQL::BaseType
|
138
|
+
type_defn = member.unwrap
|
139
|
+
prev_type = @type_map[type_defn.name]
|
140
|
+
# Continue to visit this type if it's the first time we've seen it:
|
141
|
+
if prev_type.nil?
|
142
|
+
validate_type(type_defn, context_description)
|
143
|
+
@type_map[type_defn.name] = type_defn
|
144
|
+
case type_defn
|
145
|
+
when GraphQL::ObjectType
|
146
|
+
type_defn.interfaces.each { |i| visit(schema, i, "Interface on #{type_defn.name}") }
|
147
|
+
visit_fields(schema, type_defn)
|
148
|
+
when GraphQL::InterfaceType
|
149
|
+
visit_fields(schema, type_defn)
|
150
|
+
type_defn.orphan_types.each do |t|
|
151
|
+
visit(schema, t, "Orphan type for #{type_defn.name}")
|
152
|
+
end
|
153
|
+
when GraphQL::UnionType
|
154
|
+
type_defn.possible_types.each do |t|
|
155
|
+
@union_memberships[t.name] << type_defn
|
156
|
+
visit(schema, t, "Possible type for #{type_defn.name}")
|
157
|
+
end
|
158
|
+
when GraphQL::InputObjectType
|
159
|
+
type_defn.arguments.each do |name, arg|
|
160
|
+
@type_reference_map[arg.type.unwrap.to_s] << arg
|
161
|
+
visit(schema, arg.type, "Input field #{type_defn.name}.#{name}")
|
162
|
+
end
|
163
|
+
|
164
|
+
# Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
|
165
|
+
# to be passed to a resolver proc
|
166
|
+
if type_defn.arguments_class.nil?
|
167
|
+
GraphQL::Query::Arguments.construct_arguments_class(type_defn)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
elsif !prev_type.equal?(type_defn)
|
171
|
+
# If the previous entry in the map isn't the same object we just found, raise.
|
172
|
+
raise("Duplicate type definition found for name '#{type_defn.name}' at '#{context_description}' (#{prev_type.metadata[:type_class] || prev_type}, #{type_defn.metadata[:type_class] || type_defn})")
|
173
|
+
end
|
174
|
+
when Class
|
175
|
+
if member.respond_to?(:graphql_definition)
|
176
|
+
graphql_member = member.graphql_definition
|
177
|
+
visit(schema, graphql_member, context_description)
|
178
|
+
else
|
179
|
+
raise GraphQL::Schema::InvalidTypeError.new("Unexpected traversal member: #{member} (#{member.class.name})")
|
180
|
+
end
|
181
|
+
else
|
182
|
+
message = "Unexpected schema traversal member: #{member} (#{member.class.name})"
|
183
|
+
raise GraphQL::Schema::InvalidTypeError.new(message)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def visit_fields(schema, type_defn)
|
188
|
+
type_defn.all_fields.each do |field_defn|
|
189
|
+
visit_field_on_type(schema, type_defn, field_defn)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def visit_field_on_type(schema, type_defn, field_defn, dynamic_field: false)
|
194
|
+
base_return_type = field_defn.type.unwrap
|
195
|
+
if base_return_type.is_a?(GraphQL::Schema::LateBoundType)
|
196
|
+
@late_bound_fields << [type_defn, field_defn, dynamic_field]
|
197
|
+
return
|
198
|
+
end
|
199
|
+
if dynamic_field
|
200
|
+
# Don't apply instrumentation to dynamic fields since they're shared constants
|
201
|
+
instrumented_field_defn = field_defn
|
202
|
+
else
|
203
|
+
instrumented_field_defn = @field_instrumenters.reduce(field_defn) do |defn, inst|
|
204
|
+
inst.instrument(type_defn, defn)
|
205
|
+
end
|
206
|
+
@instrumented_field_map[type_defn.name][instrumented_field_defn.name] = instrumented_field_defn
|
207
|
+
end
|
208
|
+
@type_reference_map[instrumented_field_defn.type.unwrap.name] << instrumented_field_defn
|
209
|
+
visit(schema, instrumented_field_defn.type, "Field #{type_defn.name}.#{instrumented_field_defn.name}'s return type")
|
210
|
+
instrumented_field_defn.arguments.each do |name, arg|
|
211
|
+
@type_reference_map[arg.type.unwrap.to_s] << arg
|
212
|
+
visit(schema, arg.type, "Argument #{name} on #{type_defn.name}.#{instrumented_field_defn.name}")
|
213
|
+
end
|
214
|
+
|
215
|
+
# Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
|
216
|
+
# to be passed to a resolver proc
|
217
|
+
GraphQL::Query::Arguments.construct_arguments_class(instrumented_field_defn)
|
218
|
+
end
|
219
|
+
|
220
|
+
def validate_type(member, context_description)
|
221
|
+
error_message = GraphQL::Schema::Validation.validate(member)
|
222
|
+
if error_message
|
223
|
+
raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
# @api private
|
5
|
+
module TypeExpression
|
6
|
+
# Fetch a type from a type map by its AST specification.
|
7
|
+
# Return `nil` if not found.
|
8
|
+
# @param type_owner [#get_type] A thing for looking up types by name
|
9
|
+
# @param ast_node [GraphQL::Language::Nodes::AbstractNode]
|
10
|
+
# @return [Class, GraphQL::Schema::NonNull, GraphQL::Schema:List]
|
11
|
+
def self.build_type(type_owner, ast_node)
|
12
|
+
case ast_node
|
13
|
+
when GraphQL::Language::Nodes::TypeName
|
14
|
+
type_owner.get_type(ast_node.name) # rubocop:disable Development/ContextIsPassedCop -- this is a `context` or `warden`, it's already query-aware
|
15
|
+
when GraphQL::Language::Nodes::NonNullType
|
16
|
+
ast_inner_type = ast_node.of_type
|
17
|
+
inner_type = build_type(type_owner, ast_inner_type)
|
18
|
+
wrap_type(inner_type, :to_non_null_type)
|
19
|
+
when GraphQL::Language::Nodes::ListType
|
20
|
+
ast_inner_type = ast_node.of_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}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
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
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
# This class joins an object type to an abstract type (interface or union) of which
|
6
|
+
# it is a member.
|
7
|
+
class TypeMembership
|
8
|
+
# @return [Class<GraphQL::Schema::Object>]
|
9
|
+
attr_accessor :object_type
|
10
|
+
|
11
|
+
# @return [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
12
|
+
attr_reader :abstract_type
|
13
|
+
|
14
|
+
# Called when an object is hooked up to an abstract type, such as {Schema::Union.possible_types}
|
15
|
+
# or {Schema::Object.implements} (for interfaces).
|
16
|
+
#
|
17
|
+
# @param abstract_type [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
18
|
+
# @param object_type [Class<GraphQL::Schema::Object>]
|
19
|
+
# @param options [Hash] Any options passed to `.possible_types` or `.implements`
|
20
|
+
def initialize(abstract_type, object_type, **options)
|
21
|
+
@abstract_type = abstract_type
|
22
|
+
@object_type = object_type
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Boolean] if false, {#object_type} will be treated as _not_ a member of {#abstract_type}
|
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
|
+
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
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Union < GraphQL::Schema::Member
|
5
|
+
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
|
+
extend GraphQL::Schema::Member::HasUnresolvedTypeError
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def inherited(child_class)
|
10
|
+
add_unresolved_type_error(child_class)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
15
|
+
if types.any?
|
16
|
+
types.each do |t|
|
17
|
+
assert_valid_union_member(t)
|
18
|
+
type_memberships << type_membership_class.new(self, t, **options)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
visible_types = []
|
22
|
+
warden = Warden.from_context(context)
|
23
|
+
type_memberships.each do |type_membership|
|
24
|
+
if warden.visible_type_membership?(type_membership, context)
|
25
|
+
visible_types << type_membership.object_type
|
26
|
+
end
|
27
|
+
end
|
28
|
+
visible_types
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_possible_types
|
33
|
+
type_memberships.map(&:object_type)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_graphql
|
37
|
+
type_defn = GraphQL::UnionType.new
|
38
|
+
type_defn.name = graphql_name
|
39
|
+
type_defn.description = description
|
40
|
+
type_defn.ast_node = ast_node
|
41
|
+
type_defn.type_memberships = type_memberships
|
42
|
+
if respond_to?(:resolve_type)
|
43
|
+
type_defn.resolve_type = method(:resolve_type)
|
44
|
+
end
|
45
|
+
type_defn.metadata[:type_class] = self
|
46
|
+
type_defn
|
47
|
+
end
|
48
|
+
|
49
|
+
def type_membership_class(membership_class = nil)
|
50
|
+
if membership_class
|
51
|
+
@type_membership_class = membership_class
|
52
|
+
else
|
53
|
+
@type_membership_class || find_inherited_value(:type_membership_class, GraphQL::Schema::TypeMembership)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def kind
|
58
|
+
GraphQL::TypeKinds::UNION
|
59
|
+
end
|
60
|
+
|
61
|
+
def type_memberships
|
62
|
+
@type_memberships ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
# Update a type membership whose `.object_type` is a string or late-bound type
|
66
|
+
# so that the type membership's `.object_type` is the given `object_type`.
|
67
|
+
# (This is used for updating the union after the schema as lazily loaded the union member.)
|
68
|
+
# @api private
|
69
|
+
def assign_type_membership_object_type(object_type)
|
70
|
+
assert_valid_union_member(object_type)
|
71
|
+
type_memberships.each { |tm|
|
72
|
+
possible_type = tm.object_type
|
73
|
+
if possible_type.is_a?(String) && (possible_type == object_type.name)
|
74
|
+
# This is a match of Ruby class names, not graphql names,
|
75
|
+
# since strings are used to refer to constants.
|
76
|
+
tm.object_type = object_type
|
77
|
+
elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == object_type.graphql_name
|
78
|
+
tm.object_type = object_type
|
79
|
+
end
|
80
|
+
}
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def assert_valid_union_member(type_defn)
|
87
|
+
if type_defn.is_a?(Module) && !type_defn.is_a?(Class)
|
88
|
+
# it's an interface type, defined as a module
|
89
|
+
raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'graphql/schema/base_64_bp'
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
class Schema
|
6
|
+
module UniqueWithinType
|
7
|
+
class << self
|
8
|
+
attr_accessor :default_id_separator
|
9
|
+
end
|
10
|
+
self.default_id_separator = "-"
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
# @param type_name [String]
|
15
|
+
# @param object_value [Any]
|
16
|
+
# @return [String] a unique, opaque ID generated as a function of the two inputs
|
17
|
+
def encode(type_name, object_value, separator: self.default_id_separator)
|
18
|
+
object_value_str = object_value.to_s
|
19
|
+
|
20
|
+
if type_name.include?(separator)
|
21
|
+
raise "encode(#{type_name}, #{object_value_str}) contains reserved characters `#{separator}` in the type name"
|
22
|
+
end
|
23
|
+
|
24
|
+
Base64.strict_encode64([type_name, object_value_str].join(separator))
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param node_id [String] A unique ID generated by {.encode}
|
28
|
+
# @return [Array<(String, String)>] The type name & value passed to {.encode}
|
29
|
+
def decode(node_id, separator: self.default_id_separator)
|
30
|
+
GraphQL::Schema::Base64Encoder.decode(node_id).split(separator, 2)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|