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,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/pagination/connection"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Pagination
|
6
|
+
class ArrayConnection < Pagination::Connection
|
7
|
+
def nodes
|
8
|
+
load_nodes
|
9
|
+
@nodes
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_previous_page
|
13
|
+
load_nodes
|
14
|
+
@has_previous_page
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_next_page
|
18
|
+
load_nodes
|
19
|
+
@has_next_page
|
20
|
+
end
|
21
|
+
|
22
|
+
def cursor_for(item)
|
23
|
+
idx = items.find_index(item) + 1
|
24
|
+
encode(idx.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def index_from_cursor(cursor)
|
30
|
+
decode(cursor).to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
# Populate all the pagination info _once_,
|
34
|
+
# It doesn't do anything on subsequent calls.
|
35
|
+
def load_nodes
|
36
|
+
@nodes ||= begin
|
37
|
+
sliced_nodes = if before && after
|
38
|
+
items[index_from_cursor(after)..index_from_cursor(before)-1] || []
|
39
|
+
elsif before
|
40
|
+
items[0..index_from_cursor(before)-2] || []
|
41
|
+
elsif after
|
42
|
+
items[index_from_cursor(after)..-1] || []
|
43
|
+
else
|
44
|
+
items
|
45
|
+
end
|
46
|
+
|
47
|
+
@has_previous_page = if last
|
48
|
+
# There are items preceding the ones in this result
|
49
|
+
sliced_nodes.count > last
|
50
|
+
elsif after
|
51
|
+
# We've paginated into the Array a bit, there are some behind us
|
52
|
+
index_from_cursor(after) > 0
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
@has_next_page = if first
|
58
|
+
# There are more items after these items
|
59
|
+
sliced_nodes.count > first
|
60
|
+
elsif before
|
61
|
+
# The original array is longer than the `before` index
|
62
|
+
index_from_cursor(before) < items.length + 1
|
63
|
+
else
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
limited_nodes = sliced_nodes
|
68
|
+
|
69
|
+
limited_nodes = limited_nodes.first(first) if first
|
70
|
+
limited_nodes = limited_nodes.last(last) if last
|
71
|
+
|
72
|
+
limited_nodes
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Pagination
|
5
|
+
# A Connection wraps a list of items and provides cursor-based pagination over it.
|
6
|
+
#
|
7
|
+
# Connections were introduced by Facebook's `Relay` front-end framework, but
|
8
|
+
# proved to be generally useful for GraphQL APIs. When in doubt, use connections
|
9
|
+
# to serve lists (like Arrays, ActiveRecord::Relations) via GraphQL.
|
10
|
+
#
|
11
|
+
# Unlike the previous connection implementation, these default to bidirectional pagination.
|
12
|
+
#
|
13
|
+
# Pagination arguments and context may be provided at initialization or assigned later (see {Schema::Field::ConnectionExtension}).
|
14
|
+
class Connection
|
15
|
+
class PaginationImplementationMissingError < GraphQL::Error
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Object] A list object, from the application. This is the unpaginated value passed into the connection.
|
19
|
+
attr_reader :items
|
20
|
+
|
21
|
+
# @return [GraphQL::Query::Context]
|
22
|
+
attr_accessor :context
|
23
|
+
|
24
|
+
# @return [Object] the object this collection belongs to
|
25
|
+
attr_accessor :parent
|
26
|
+
|
27
|
+
# Raw access to client-provided values. (`max_page_size` not applied to first or last.)
|
28
|
+
attr_accessor :before_value, :after_value, :first_value, :last_value
|
29
|
+
|
30
|
+
# @return [String, nil] the client-provided cursor. `""` is treated as `nil`.
|
31
|
+
def before
|
32
|
+
if defined?(@before)
|
33
|
+
@before
|
34
|
+
else
|
35
|
+
@before = @before_value == "" ? nil : @before_value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String, nil] the client-provided cursor. `""` is treated as `nil`.
|
40
|
+
def after
|
41
|
+
if defined?(@after)
|
42
|
+
@after
|
43
|
+
else
|
44
|
+
@after = @after_value == "" ? nil : @after_value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Hash<Symbol => Object>] The field arguments from the field that returned this connection
|
49
|
+
attr_accessor :arguments
|
50
|
+
|
51
|
+
# @param items [Object] some unpaginated collection item, like an `Array` or `ActiveRecord::Relation`
|
52
|
+
# @param context [Query::Context]
|
53
|
+
# @param parent [Object] The object this collection belongs to
|
54
|
+
# @param first [Integer, nil] The limit parameter from the client, if it provided one
|
55
|
+
# @param after [String, nil] A cursor for pagination, if the client provided one
|
56
|
+
# @param last [Integer, nil] Limit parameter from the client, if provided
|
57
|
+
# @param before [String, nil] A cursor for pagination, if the client provided one.
|
58
|
+
# @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
|
59
|
+
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
|
60
|
+
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil)
|
61
|
+
@items = items
|
62
|
+
@parent = parent
|
63
|
+
@context = context
|
64
|
+
@field = field
|
65
|
+
@first_value = first
|
66
|
+
@after_value = after
|
67
|
+
@last_value = last
|
68
|
+
@before_value = before
|
69
|
+
@arguments = arguments
|
70
|
+
@edge_class = edge_class || self.class::Edge
|
71
|
+
# This is only true if the object was _initialized_ with an override
|
72
|
+
# or if one is assigned later.
|
73
|
+
@has_max_page_size_override = max_page_size != :not_given
|
74
|
+
@max_page_size = if max_page_size == :not_given
|
75
|
+
nil
|
76
|
+
else
|
77
|
+
max_page_size
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def max_page_size=(new_value)
|
82
|
+
@has_max_page_size_override = true
|
83
|
+
@max_page_size = new_value
|
84
|
+
end
|
85
|
+
|
86
|
+
def max_page_size
|
87
|
+
if @has_max_page_size_override
|
88
|
+
@max_page_size
|
89
|
+
else
|
90
|
+
context.schema.default_max_page_size
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def has_max_page_size_override?
|
95
|
+
@has_max_page_size_override
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_writer :first
|
99
|
+
# @return [Integer, nil]
|
100
|
+
# A clamped `first` value.
|
101
|
+
# (The underlying instance variable doesn't have limits on it.)
|
102
|
+
# If neither `first` nor `last` is given, but `max_page_size` is present, max_page_size is used for first.
|
103
|
+
def first
|
104
|
+
@first ||= begin
|
105
|
+
capped = limit_pagination_argument(@first_value, max_page_size)
|
106
|
+
if capped.nil? && last.nil?
|
107
|
+
capped = max_page_size
|
108
|
+
end
|
109
|
+
capped
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# This is called by `Relay::RangeAdd` -- it can be overridden
|
114
|
+
# when `item` needs some modifications based on this connection's state.
|
115
|
+
#
|
116
|
+
# @param item [Object] An item newly added to `items`
|
117
|
+
# @return [Edge]
|
118
|
+
def range_add_edge(item)
|
119
|
+
edge_class.new(item, self)
|
120
|
+
end
|
121
|
+
|
122
|
+
attr_writer :last
|
123
|
+
# @return [Integer, nil] A clamped `last` value. (The underlying instance variable doesn't have limits on it)
|
124
|
+
def last
|
125
|
+
@last ||= limit_pagination_argument(@last_value, max_page_size)
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [Array<Edge>] {nodes}, but wrapped with Edge instances
|
129
|
+
def edges
|
130
|
+
@edges ||= nodes.map { |n| @edge_class.new(n, self) }
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Class] A wrapper class for edges of this connection
|
134
|
+
attr_accessor :edge_class
|
135
|
+
|
136
|
+
# @return [GraphQL::Schema::Field] The field this connection was returned by
|
137
|
+
attr_accessor :field
|
138
|
+
|
139
|
+
# @return [Array<Object>] A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
|
140
|
+
def nodes
|
141
|
+
raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
|
142
|
+
end
|
143
|
+
|
144
|
+
# A dynamic alias for compatibility with {Relay::BaseConnection}.
|
145
|
+
# @deprecated use {#nodes} instead
|
146
|
+
def edge_nodes
|
147
|
+
nodes
|
148
|
+
end
|
149
|
+
|
150
|
+
# The connection object itself implements `PageInfo` fields
|
151
|
+
def page_info
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
# @return [Boolean] True if there are more items after this page
|
156
|
+
def has_next_page
|
157
|
+
raise PaginationImplementationMissingError, "Implement #{self.class}#has_next_page to return the next-page check"
|
158
|
+
end
|
159
|
+
|
160
|
+
# @return [Boolean] True if there were items before these items
|
161
|
+
def has_previous_page
|
162
|
+
raise PaginationImplementationMissingError, "Implement #{self.class}#has_previous_page to return the previous-page check"
|
163
|
+
end
|
164
|
+
|
165
|
+
# @return [String] The cursor of the first item in {nodes}
|
166
|
+
def start_cursor
|
167
|
+
nodes.first && cursor_for(nodes.first)
|
168
|
+
end
|
169
|
+
|
170
|
+
# @return [String] The cursor of the last item in {nodes}
|
171
|
+
def end_cursor
|
172
|
+
nodes.last && cursor_for(nodes.last)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Return a cursor for this item.
|
176
|
+
# @param item [Object] one of the passed in {items}, taken from {nodes}
|
177
|
+
# @return [String]
|
178
|
+
def cursor_for(item)
|
179
|
+
raise PaginationImplementationMissingError, "Implement #{self.class}#cursor_for(item) to return the cursor for #{item.inspect}"
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# @param argument [nil, Integer] `first` or `last`, as provided by the client
|
185
|
+
# @param max_page_size [nil, Integer]
|
186
|
+
# @return [nil, Integer] `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`
|
187
|
+
def limit_pagination_argument(argument, max_page_size)
|
188
|
+
if argument
|
189
|
+
if argument < 0
|
190
|
+
argument = 0
|
191
|
+
elsif max_page_size && argument > max_page_size
|
192
|
+
argument = max_page_size
|
193
|
+
end
|
194
|
+
end
|
195
|
+
argument
|
196
|
+
end
|
197
|
+
|
198
|
+
def decode(cursor)
|
199
|
+
context.schema.cursor_encoder.decode(cursor, nonce: true)
|
200
|
+
end
|
201
|
+
|
202
|
+
def encode(cursor)
|
203
|
+
context.schema.cursor_encoder.encode(cursor, nonce: true)
|
204
|
+
end
|
205
|
+
|
206
|
+
# A wrapper around paginated items. It includes a {cursor} for pagination
|
207
|
+
# and could be extended with custom relationship-level data.
|
208
|
+
class Edge
|
209
|
+
attr_reader :node
|
210
|
+
|
211
|
+
def initialize(node, connection)
|
212
|
+
@connection = connection
|
213
|
+
@node = node
|
214
|
+
end
|
215
|
+
|
216
|
+
def parent
|
217
|
+
@connection.parent
|
218
|
+
end
|
219
|
+
|
220
|
+
def cursor
|
221
|
+
@cursor ||= @connection.cursor_for(@node)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Pagination
|
5
|
+
# A schema-level connection wrapper manager.
|
6
|
+
#
|
7
|
+
# Attach as a plugin.
|
8
|
+
#
|
9
|
+
# @example Adding a custom wrapper
|
10
|
+
# class MySchema < GraphQL::Schema
|
11
|
+
# connections.add(MyApp::SearchResults, MyApp::SearchResultsConnection)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example Removing default connection support for arrays (they can still be manually wrapped)
|
15
|
+
# class MySchema < GraphQL::Schema
|
16
|
+
# connections.delete(Array)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @see {Schema.connections}
|
20
|
+
class Connections
|
21
|
+
class ImplementationMissingError < GraphQL::Error
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.use(schema_defn)
|
25
|
+
if schema_defn.plugins.any? { |(plugin, args)| plugin == self }
|
26
|
+
GraphQL::Deprecation.warn("#{self} is now the default, remove `use #{self}` from #{caller(2,1).first}")
|
27
|
+
end
|
28
|
+
schema_defn.connections = self.new(schema: schema_defn)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(schema:)
|
32
|
+
@schema = schema
|
33
|
+
@wrappers = {}
|
34
|
+
add_default
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(nodes_class, implementation)
|
38
|
+
@wrappers[nodes_class] = implementation
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(nodes_class)
|
42
|
+
@wrappers.delete(nodes_class)
|
43
|
+
end
|
44
|
+
|
45
|
+
def all_wrappers
|
46
|
+
all_wrappers = {}
|
47
|
+
@schema.ancestors.reverse_each do |schema_class|
|
48
|
+
if schema_class.respond_to?(:connections) && (c = schema_class.connections)
|
49
|
+
all_wrappers.merge!(c.wrappers)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
all_wrappers
|
53
|
+
end
|
54
|
+
|
55
|
+
def wrapper_for(items, wrappers: all_wrappers)
|
56
|
+
impl = nil
|
57
|
+
|
58
|
+
items.class.ancestors.each { |cls|
|
59
|
+
impl = wrappers[cls]
|
60
|
+
break if impl
|
61
|
+
}
|
62
|
+
|
63
|
+
impl
|
64
|
+
end
|
65
|
+
|
66
|
+
# Used by the runtime to wrap values in connection wrappers.
|
67
|
+
# @api Private
|
68
|
+
def wrap(field, parent, items, arguments, context)
|
69
|
+
return items if GraphQL::Execution::Interpreter::RawValue === items
|
70
|
+
wrappers = context ? context.namespace(:connections)[:all_wrappers] : all_wrappers
|
71
|
+
impl = wrapper_for(items, wrappers: wrappers)
|
72
|
+
|
73
|
+
if impl
|
74
|
+
impl.new(
|
75
|
+
items,
|
76
|
+
context: context,
|
77
|
+
parent: parent,
|
78
|
+
field: field,
|
79
|
+
max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
|
80
|
+
first: arguments[:first],
|
81
|
+
after: arguments[:after],
|
82
|
+
last: arguments[:last],
|
83
|
+
before: arguments[:before],
|
84
|
+
arguments: arguments,
|
85
|
+
edge_class: edge_class_for_field(field),
|
86
|
+
)
|
87
|
+
else
|
88
|
+
begin
|
89
|
+
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(items)
|
90
|
+
if parent.is_a?(GraphQL::Schema::Object)
|
91
|
+
parent = parent.object
|
92
|
+
end
|
93
|
+
connection_class.new(
|
94
|
+
items,
|
95
|
+
arguments,
|
96
|
+
field: field,
|
97
|
+
max_page_size: field.max_page_size,
|
98
|
+
parent: parent,
|
99
|
+
context: context,
|
100
|
+
)
|
101
|
+
rescue RuntimeError => err
|
102
|
+
if err.message.include?("No connection implementation to wrap")
|
103
|
+
raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
|
104
|
+
else
|
105
|
+
raise err
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# use an override if there is one
|
112
|
+
# @api private
|
113
|
+
def edge_class_for_field(field)
|
114
|
+
conn_type = field.type.unwrap
|
115
|
+
conn_type_edge_type = conn_type.respond_to?(:edge_class) && conn_type.edge_class
|
116
|
+
if conn_type_edge_type && conn_type_edge_type != Relay::Edge
|
117
|
+
conn_type_edge_type
|
118
|
+
else
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
protected
|
123
|
+
|
124
|
+
attr_reader :wrappers
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def add_default
|
129
|
+
add(Array, Pagination::ArrayConnection)
|
130
|
+
|
131
|
+
if defined?(ActiveRecord::Relation)
|
132
|
+
add(ActiveRecord::Relation, Pagination::ActiveRecordRelationConnection)
|
133
|
+
end
|
134
|
+
|
135
|
+
if defined?(Sequel::Dataset)
|
136
|
+
add(Sequel::Dataset, Pagination::SequelDatasetConnection)
|
137
|
+
end
|
138
|
+
|
139
|
+
if defined?(Mongoid::Criteria)
|
140
|
+
add(Mongoid::Criteria, Pagination::MongoidRelationConnection)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Mongoid 5 and 6
|
144
|
+
if defined?(Mongoid::Relations::Targets::Enumerable)
|
145
|
+
add(Mongoid::Relations::Targets::Enumerable, Pagination::MongoidRelationConnection)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Mongoid 7
|
149
|
+
if defined?(Mongoid::Association::Referenced::HasMany::Targets::Enumerable)
|
150
|
+
add(Mongoid::Association::Referenced::HasMany::Targets::Enumerable, Pagination::MongoidRelationConnection)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Mongoid 7.3+
|
154
|
+
if defined?(Mongoid::Association::Referenced::HasMany::Enumerable)
|
155
|
+
add(Mongoid::Association::Referenced::HasMany::Enumerable, Pagination::MongoidRelationConnection)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/pagination/relation_connection"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Pagination
|
6
|
+
class MongoidRelationConnection < Pagination::RelationConnection
|
7
|
+
def relation_offset(relation)
|
8
|
+
relation.options.skip
|
9
|
+
end
|
10
|
+
|
11
|
+
def relation_limit(relation)
|
12
|
+
relation.options.limit
|
13
|
+
end
|
14
|
+
|
15
|
+
def relation_count(relation)
|
16
|
+
# Mongo's `.count` doesn't apply limit or skip, which we need. So we have to load _everything_!
|
17
|
+
relation.to_a.count
|
18
|
+
end
|
19
|
+
|
20
|
+
def null_relation(relation)
|
21
|
+
relation.without_options.none
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/pagination/connection"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Pagination
|
6
|
+
# A generic class for working with database query objects.
|
7
|
+
class RelationConnection < Pagination::Connection
|
8
|
+
def nodes
|
9
|
+
load_nodes
|
10
|
+
@nodes
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_previous_page
|
14
|
+
if @has_previous_page.nil?
|
15
|
+
@has_previous_page = if after_offset && after_offset > 0
|
16
|
+
true
|
17
|
+
elsif last
|
18
|
+
# See whether there are any nodes _before_ the current offset.
|
19
|
+
# If there _is no_ current offset, then there can't be any nodes before it.
|
20
|
+
# Assume that if the offset is positive, there are nodes before the offset.
|
21
|
+
limited_nodes
|
22
|
+
!(@paged_nodes_offset.nil? || @paged_nodes_offset == 0)
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@has_previous_page
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_next_page
|
31
|
+
if @has_next_page.nil?
|
32
|
+
@has_next_page = if before_offset && before_offset > 0
|
33
|
+
true
|
34
|
+
elsif first
|
35
|
+
if @nodes && @nodes.count < first
|
36
|
+
false
|
37
|
+
else
|
38
|
+
relation_larger_than(sliced_nodes, first)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@has_next_page
|
45
|
+
end
|
46
|
+
|
47
|
+
def cursor_for(item)
|
48
|
+
load_nodes
|
49
|
+
# index in nodes + existing offset + 1 (because it's offset, not index)
|
50
|
+
offset = nodes.index(item) + 1 + (@paged_nodes_offset || 0) + (relation_offset(items) || 0)
|
51
|
+
encode(offset.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# @param relation [Object] A database query object
|
57
|
+
# @param size [Integer] The value against which we check the relation size
|
58
|
+
# @return [Boolean] True if the number of items in this relation is larger than `size`
|
59
|
+
def relation_larger_than(relation, size)
|
60
|
+
relation_count(set_limit(relation, size + 1)) == size + 1
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param relation [Object] A database query object
|
64
|
+
# @return [Integer, nil] The offset value, or nil if there isn't one
|
65
|
+
def relation_offset(relation)
|
66
|
+
raise "#{self.class}#relation_offset(relation) must return the offset value for a #{relation.class} (#{relation.inspect})"
|
67
|
+
end
|
68
|
+
|
69
|
+
# @param relation [Object] A database query object
|
70
|
+
# @return [Integer, nil] The limit value, or nil if there isn't one
|
71
|
+
def relation_limit(relation)
|
72
|
+
raise "#{self.class}#relation_limit(relation) must return the limit value for a #{relation.class} (#{relation.inspect})"
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param relation [Object] A database query object
|
76
|
+
# @return [Integer, nil] The number of items in this relation (hopefully determined without loading all records into memory!)
|
77
|
+
def relation_count(relation)
|
78
|
+
raise "#{self.class}#relation_count(relation) must return the count of records for a #{relation.class} (#{relation.inspect})"
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param relation [Object] A database query object
|
82
|
+
# @return [Object] A modified query object which will return no records
|
83
|
+
def null_relation(relation)
|
84
|
+
raise "#{self.class}#null_relation(relation) must return an empty relation for a #{relation.class} (#{relation.inspect})"
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Integer]
|
88
|
+
def offset_from_cursor(cursor)
|
89
|
+
decode(cursor).to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
# Abstract this operation so we can always ignore inputs less than zero.
|
93
|
+
# (Sequel doesn't like it, understandably.)
|
94
|
+
def set_offset(relation, offset_value)
|
95
|
+
if offset_value >= 0
|
96
|
+
relation.offset(offset_value)
|
97
|
+
else
|
98
|
+
relation.offset(0)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Abstract this operation so we can always ignore inputs less than zero.
|
103
|
+
# (Sequel doesn't like it, understandably.)
|
104
|
+
def set_limit(relation, limit_value)
|
105
|
+
if limit_value > 0
|
106
|
+
relation.limit(limit_value)
|
107
|
+
elsif limit_value == 0
|
108
|
+
null_relation(relation)
|
109
|
+
else
|
110
|
+
relation
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Apply `before` and `after` to the underlying `items`,
|
115
|
+
# returning a new relation.
|
116
|
+
def sliced_nodes
|
117
|
+
@sliced_nodes ||= begin
|
118
|
+
paginated_nodes = items
|
119
|
+
|
120
|
+
if after_offset
|
121
|
+
previous_offset = relation_offset(items) || 0
|
122
|
+
paginated_nodes = set_offset(paginated_nodes, previous_offset + after_offset)
|
123
|
+
end
|
124
|
+
|
125
|
+
if before_offset && after_offset
|
126
|
+
if after_offset < before_offset
|
127
|
+
# Get the number of items between the two cursors
|
128
|
+
space_between = before_offset - after_offset - 1
|
129
|
+
paginated_nodes = set_limit(paginated_nodes, space_between)
|
130
|
+
else
|
131
|
+
# TODO I think this is untested
|
132
|
+
# The cursors overextend one another to an empty set
|
133
|
+
paginated_nodes = null_relation(paginated_nodes)
|
134
|
+
end
|
135
|
+
elsif before_offset
|
136
|
+
# Use limit to cut off the tail of the relation
|
137
|
+
paginated_nodes = set_limit(paginated_nodes, before_offset - 1)
|
138
|
+
end
|
139
|
+
|
140
|
+
paginated_nodes
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# @return [Integer, nil]
|
145
|
+
def before_offset
|
146
|
+
@before_offset ||= before && offset_from_cursor(before)
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [Integer, nil]
|
150
|
+
def after_offset
|
151
|
+
@after_offset ||= after && offset_from_cursor(after)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Apply `first` and `last` to `sliced_nodes`,
|
155
|
+
# returning a new relation
|
156
|
+
def limited_nodes
|
157
|
+
@limited_nodes ||= begin
|
158
|
+
paginated_nodes = sliced_nodes
|
159
|
+
previous_limit = relation_limit(paginated_nodes)
|
160
|
+
|
161
|
+
if first && (previous_limit.nil? || previous_limit > first)
|
162
|
+
# `first` would create a stricter limit that the one already applied, so add it
|
163
|
+
paginated_nodes = set_limit(paginated_nodes, first)
|
164
|
+
end
|
165
|
+
|
166
|
+
if last
|
167
|
+
if (lv = relation_limit(paginated_nodes))
|
168
|
+
if last <= lv
|
169
|
+
# `last` is a smaller slice than the current limit, so apply it
|
170
|
+
offset = (relation_offset(paginated_nodes) || 0) + (lv - last)
|
171
|
+
paginated_nodes = set_offset(paginated_nodes, offset)
|
172
|
+
paginated_nodes = set_limit(paginated_nodes, last)
|
173
|
+
end
|
174
|
+
else
|
175
|
+
# No limit, so get the last items
|
176
|
+
sliced_nodes_count = relation_count(@sliced_nodes)
|
177
|
+
offset = (relation_offset(paginated_nodes) || 0) + sliced_nodes_count - [last, sliced_nodes_count].min
|
178
|
+
paginated_nodes = set_offset(paginated_nodes, offset)
|
179
|
+
paginated_nodes = set_limit(paginated_nodes, last)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
@paged_nodes_offset = relation_offset(paginated_nodes)
|
184
|
+
paginated_nodes
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Load nodes after applying first/last/before/after,
|
189
|
+
# returns an array of nodes
|
190
|
+
def load_nodes
|
191
|
+
# Return an array so we can consistently use `.index(node)` on it
|
192
|
+
@nodes ||= limited_nodes.to_a
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|