graphql 1.9.17 → 1.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/object_generator.rb +52 -8
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/analysis/ast.rb +12 -11
- data/lib/graphql/argument.rb +10 -38
- data/lib/graphql/backtrace/table.rb +10 -2
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +3 -3
- data/lib/graphql/define/defined_object_proxy.rb +3 -0
- data/lib/graphql/define/instance_definable.rb +18 -108
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/directive.rb +8 -1
- data/lib/graphql/enum_type.rb +5 -71
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +2 -3
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +227 -254
- data/lib/graphql/execution/interpreter.rb +34 -11
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +14 -5
- data/lib/graphql/field.rb +14 -118
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/function.rb +1 -30
- data/lib/graphql/input_object_type.rb +6 -24
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +7 -23
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +7 -7
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +33 -9
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -9
- data/lib/graphql/introspection/type_type.rb +11 -7
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +89 -64
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +52 -91
- data/lib/graphql/language/parser.rb +719 -717
- data/lib/graphql/language/parser.y +104 -98
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -1
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +45 -56
- data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +208 -0
- data/lib/graphql/pagination/connections.rb +145 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +185 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/query/arguments.rb +4 -2
- data/lib/graphql/query/context.rb +36 -9
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +30 -10
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +16 -7
- data/lib/graphql/query.rb +64 -15
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +23 -13
- data/lib/graphql/relay/connection_type.rb +2 -1
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -86
- data/lib/graphql/relay/node.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/scalar_type.rb +15 -59
- data/lib/graphql/schema/argument.rb +113 -11
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +212 -190
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive.rb +34 -3
- data/lib/graphql/schema/enum.rb +52 -4
- data/lib/graphql/schema/enum_value.rb +6 -1
- data/lib/graphql/schema/field/connection_extension.rb +44 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +200 -129
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +131 -22
- data/lib/graphql/schema/interface.rb +26 -8
- data/lib/graphql/schema/introspection_system.rb +108 -37
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +47 -0
- data/lib/graphql/schema/loader.rb +134 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
- data/lib/graphql/schema/member/build_type.rb +19 -5
- data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +105 -5
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_fields.rb +20 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +5 -1
- data/lib/graphql/schema/non_null.rb +30 -0
- data/lib/graphql/schema/object.rb +65 -12
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +0 -15
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
- data/lib/graphql/schema/resolver.rb +26 -18
- data/lib/graphql/schema/scalar.rb +27 -3
- data/lib/graphql/schema/subscription.rb +8 -18
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +2 -2
- data/lib/graphql/schema/union.rb +37 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -2
- data/lib/graphql/schema/warden.rb +115 -29
- data/lib/graphql/schema.rb +903 -195
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/literal_validator.rb +52 -27
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +30 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +23 -5
- data/lib/graphql/subscriptions/instrumentation.rb +10 -5
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +108 -35
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
- data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/platform_tracing.rb +53 -9
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +8 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +14 -34
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +11 -7
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +13 -28
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +31 -6
- data/readme.md +1 -1
- metadata +34 -9
- data/lib/graphql/literal_validation_error.rb +0 -6
@@ -7,11 +7,11 @@ module GraphQL
|
|
7
7
|
module HasFields
|
8
8
|
# Add a field to this object or interface with the given definition
|
9
9
|
# @see {GraphQL::Schema::Field#initialize} for method signature
|
10
|
-
# @return [
|
10
|
+
# @return [GraphQL::Schema::Field]
|
11
11
|
def field(*args, **kwargs, &block)
|
12
12
|
field_defn = field_class.from_options(*args, owner: self, **kwargs, &block)
|
13
13
|
add_field(field_defn)
|
14
|
-
|
14
|
+
field_defn
|
15
15
|
end
|
16
16
|
|
17
17
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
@@ -47,20 +47,22 @@ module GraphQL
|
|
47
47
|
# A list of GraphQL-Ruby keywords.
|
48
48
|
#
|
49
49
|
# @api private
|
50
|
-
GRAPHQL_RUBY_KEYWORDS = [:context, :object, :
|
50
|
+
GRAPHQL_RUBY_KEYWORDS = [:context, :object, :raw_value]
|
51
51
|
|
52
52
|
# A list of field names that we should advise users to pick a different
|
53
53
|
# resolve method name.
|
54
54
|
#
|
55
55
|
# @api private
|
56
|
-
CONFLICT_FIELD_NAMES = Set.new(GRAPHQL_RUBY_KEYWORDS + RUBY_KEYWORDS)
|
56
|
+
CONFLICT_FIELD_NAMES = Set.new(GRAPHQL_RUBY_KEYWORDS + RUBY_KEYWORDS + Object.instance_methods)
|
57
57
|
|
58
58
|
# Register this field with the class, overriding a previous one if needed.
|
59
59
|
# @param field_defn [GraphQL::Schema::Field]
|
60
60
|
# @return [void]
|
61
|
-
def add_field(field_defn)
|
62
|
-
|
63
|
-
|
61
|
+
def add_field(field_defn, method_conflict_warning: field_defn.method_conflict_warning?)
|
62
|
+
# Check that `field_defn.original_name` equals `resolver_method` and `method_sym` --
|
63
|
+
# that shows that no override value was given manually.
|
64
|
+
if method_conflict_warning && CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) && field_defn.original_name == field_defn.resolver_method && field_defn.original_name == field_defn.method_sym
|
65
|
+
warn(conflict_field_name_warning(field_defn))
|
64
66
|
end
|
65
67
|
own_fields[field_defn.name] = field_defn
|
66
68
|
nil
|
@@ -70,7 +72,7 @@ module GraphQL
|
|
70
72
|
def field_class(new_field_class = nil)
|
71
73
|
if new_field_class
|
72
74
|
@field_class = new_field_class
|
73
|
-
elsif @field_class
|
75
|
+
elsif defined?(@field_class) && @field_class
|
74
76
|
@field_class
|
75
77
|
elsif self.is_a?(Class)
|
76
78
|
superclass.respond_to?(:field_class) ? superclass.field_class : GraphQL::Schema::Field
|
@@ -80,9 +82,9 @@ module GraphQL
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
|
-
def global_id_field(field_name)
|
85
|
+
def global_id_field(field_name, **kwargs)
|
84
86
|
id_resolver = GraphQL::Relay::GlobalIdResolve.new(type: self)
|
85
|
-
field field_name, "ID", null: false
|
87
|
+
field field_name, "ID", **kwargs, null: false
|
86
88
|
define_method(field_name) do
|
87
89
|
id_resolver.call(object, {}, context)
|
88
90
|
end
|
@@ -92,6 +94,14 @@ module GraphQL
|
|
92
94
|
def own_fields
|
93
95
|
@own_fields ||= {}
|
94
96
|
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# @param [GraphQL::Schema::Field]
|
101
|
+
# @return [String] A warning to give when this field definition might conflict with a built-in method
|
102
|
+
def conflict_field_name_warning(field_defn)
|
103
|
+
"#{self.graphql_name}'s `field :#{field_defn.original_name}` conflicts with a built-in method, use `resolver_method:` to pick a different resolver method for this field (for example, `resolver_method: :resolve_#{field_defn.resolver_method}` and `def resolve_#{field_defn.resolver_method}`). Or use `method_conflict_warning: false` to suppress this warning."
|
104
|
+
end
|
95
105
|
end
|
96
106
|
end
|
97
107
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
class Member
|
6
|
+
# Set up a type-specific error to make debugging & bug tracker integration better
|
7
|
+
module HasUnresolvedTypeError
|
8
|
+
private
|
9
|
+
def add_unresolved_type_error(child_class)
|
10
|
+
child_class.const_set(:UnresolvedTypeError, Class.new(GraphQL::UnresolvedTypeError))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -6,12 +6,12 @@ module GraphQL
|
|
6
6
|
module TypeSystemHelpers
|
7
7
|
# @return [Schema::NonNull] Make a non-null-type representation of this type
|
8
8
|
def to_non_null_type
|
9
|
-
GraphQL::Schema::NonNull.new(self)
|
9
|
+
@to_non_null_type ||= GraphQL::Schema::NonNull.new(self)
|
10
10
|
end
|
11
11
|
|
12
12
|
# @return [Schema::List] Make a list-type representation of this type
|
13
13
|
def to_list_type
|
14
|
-
GraphQL::Schema::List.new(self)
|
14
|
+
@to_list_type ||= GraphQL::Schema::List.new(self)
|
15
15
|
end
|
16
16
|
|
17
17
|
# @return [Boolean] true if this is a non-nullable type. A nullable list of non-nullables is considered nullable.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
class Member
|
6
|
+
module ValidatesInput
|
7
|
+
def valid_input?(val, ctx)
|
8
|
+
validate_input(val, ctx).valid?
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_input(val, ctx)
|
12
|
+
if val.nil?
|
13
|
+
GraphQL::Query::InputValidationResult.new
|
14
|
+
else
|
15
|
+
validate_non_null_input(val, ctx)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_isolated_input?(v)
|
20
|
+
valid_input?(v, GraphQL::Query::NullContext)
|
21
|
+
end
|
22
|
+
|
23
|
+
def coerce_isolated_input(v)
|
24
|
+
coerce_input(v, GraphQL::Query::NullContext)
|
25
|
+
end
|
26
|
+
|
27
|
+
def coerce_isolated_result(v)
|
28
|
+
coerce_result(v, GraphQL::Query::NullContext)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -3,10 +3,13 @@ require 'graphql/schema/member/accepts_definition'
|
|
3
3
|
require 'graphql/schema/member/base_dsl_methods'
|
4
4
|
require 'graphql/schema/member/cached_graphql_definition'
|
5
5
|
require 'graphql/schema/member/graphql_type_names'
|
6
|
+
require 'graphql/schema/member/has_ast_node'
|
6
7
|
require 'graphql/schema/member/has_path'
|
8
|
+
require 'graphql/schema/member/has_unresolved_type_error'
|
7
9
|
require 'graphql/schema/member/relay_shortcuts'
|
8
10
|
require 'graphql/schema/member/scoped'
|
9
11
|
require 'graphql/schema/member/type_system_helpers'
|
12
|
+
require 'graphql/schema/member/validates_input'
|
10
13
|
require "graphql/relay/type_extensions"
|
11
14
|
|
12
15
|
module GraphQL
|
@@ -20,10 +23,13 @@ module GraphQL
|
|
20
23
|
extend CachedGraphQLDefinition
|
21
24
|
extend GraphQL::Relay::TypeExtensions
|
22
25
|
extend BaseDSLMethods
|
26
|
+
extend BaseDSLMethods::ConfigurationExtension
|
27
|
+
introspection(false)
|
23
28
|
extend TypeSystemHelpers
|
24
29
|
extend Scoped
|
25
30
|
extend RelayShortcuts
|
26
31
|
extend HasPath
|
32
|
+
extend HasAstNode
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -64,7 +64,7 @@ module GraphQL
|
|
64
64
|
|
65
65
|
class << self
|
66
66
|
# Override this method to handle legacy-style usages of `MyMutation.field`
|
67
|
-
def field(*args, &block)
|
67
|
+
def field(*args, **kwargs, &block)
|
68
68
|
if args.empty?
|
69
69
|
raise ArgumentError, "#{name}.field is used for adding fields to this mutation. Use `mutation: #{name}` to attach this mutation instead."
|
70
70
|
else
|
@@ -78,6 +78,10 @@ module GraphQL
|
|
78
78
|
|
79
79
|
private
|
80
80
|
|
81
|
+
def conflict_field_name_warning(field_defn)
|
82
|
+
"#{self.graphql_name}'s `field :#{field_defn.name}` conflicts with a built-in method, use `hash_key:` or `method:` to pick a different resolve behavior for this field (for example, `hash_key: :#{field_defn.resolver_method}_value`, and modify the return hash). Or use `method_conflict_warning: false` to suppress this warning."
|
83
|
+
end
|
84
|
+
|
81
85
|
# Override this to attach self as `mutation`
|
82
86
|
def generate_payload_type
|
83
87
|
payload_class = super
|
@@ -6,6 +6,8 @@ module GraphQL
|
|
6
6
|
# Wraps a {Schema::Member} when it is required.
|
7
7
|
# @see {Schema::Member::TypeSystemHelpers#to_non_null_type}
|
8
8
|
class NonNull < GraphQL::Schema::Wrapper
|
9
|
+
include Schema::Member::ValidatesInput
|
10
|
+
|
9
11
|
def to_graphql
|
10
12
|
@of_type.graphql_definition.to_non_null_type
|
11
13
|
end
|
@@ -32,6 +34,34 @@ module GraphQL
|
|
32
34
|
def inspect
|
33
35
|
"#<#{self.class.name} @of_type=#{@of_type.inspect}>"
|
34
36
|
end
|
37
|
+
|
38
|
+
def validate_input(value, ctx)
|
39
|
+
if value.nil?
|
40
|
+
result = GraphQL::Query::InputValidationResult.new
|
41
|
+
result.add_problem("Expected value to not be null")
|
42
|
+
result
|
43
|
+
else
|
44
|
+
of_type.validate_input(value, ctx)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# This is for introspection, where it's expected the name will be `null`
|
49
|
+
def graphql_name
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def coerce_input(value, ctx)
|
54
|
+
of_type.coerce_input(value, ctx)
|
55
|
+
end
|
56
|
+
|
57
|
+
def coerce_result(value, ctx)
|
58
|
+
of_type.coerce_result(value, ctx)
|
59
|
+
end
|
60
|
+
|
61
|
+
# This is for implementing introspection
|
62
|
+
def description
|
63
|
+
nil
|
64
|
+
end
|
35
65
|
end
|
36
66
|
end
|
37
67
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "graphql/query/null_context"
|
4
|
+
|
3
5
|
module GraphQL
|
4
6
|
class Schema
|
5
7
|
class Object < GraphQL::Schema::Member
|
@@ -57,13 +59,9 @@ module GraphQL
|
|
57
59
|
else
|
58
60
|
nil
|
59
61
|
end
|
60
|
-
# rescue GraphQL::ExecutionError => err
|
61
|
-
# err
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
|
-
# rescue GraphQL::ExecutionError => err
|
66
|
-
# err
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
@@ -73,34 +71,88 @@ module GraphQL
|
|
73
71
|
end
|
74
72
|
|
75
73
|
class << self
|
76
|
-
|
74
|
+
# Set up a type-specific invalid null error to use when this object's non-null fields wrongly return `nil`.
|
75
|
+
# It should help with debugging and bug tracker integrations.
|
76
|
+
def inherited(child_class)
|
77
|
+
child_class.const_set(:InvalidNullError, GraphQL::InvalidNullError.subclass_for(child_class))
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def implements(*new_interfaces, **options)
|
82
|
+
new_memberships = []
|
77
83
|
new_interfaces.each do |int|
|
78
84
|
if int.is_a?(Module)
|
79
85
|
unless int.include?(GraphQL::Schema::Interface)
|
80
86
|
raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
|
81
87
|
end
|
82
88
|
|
89
|
+
new_memberships << int.type_membership_class.new(int, self, **options)
|
90
|
+
|
83
91
|
# Include the methods here,
|
84
92
|
# `.fields` will use the inheritance chain
|
85
93
|
# to find inherited fields
|
86
94
|
include(int)
|
95
|
+
elsif int.is_a?(GraphQL::InterfaceType)
|
96
|
+
new_memberships << int.type_membership_class.new(int, self, **options)
|
97
|
+
elsif int.is_a?(String) || int.is_a?(GraphQL::Schema::LateBoundType)
|
98
|
+
if options.any?
|
99
|
+
raise ArgumentError, "`implements(...)` doesn't support options with late-loaded types yet. Remove #{options} and open an issue to request this feature."
|
100
|
+
end
|
101
|
+
new_memberships << int
|
102
|
+
else
|
103
|
+
raise ArgumentError, "Unexpected interface definition (expected module): #{int} (#{int.class})"
|
87
104
|
end
|
88
105
|
end
|
89
|
-
|
106
|
+
|
107
|
+
# Remove any interfaces which are being replaced (late-bound types are updated in place this way)
|
108
|
+
own_interface_type_memberships.reject! { |old_i_m|
|
109
|
+
old_int_type = old_i_m.respond_to?(:abstract_type) ? old_i_m.abstract_type : old_i_m
|
110
|
+
old_name = Schema::Member::BuildType.to_type_name(old_int_type)
|
111
|
+
|
112
|
+
new_memberships.any? { |new_i_m|
|
113
|
+
new_int_type = new_i_m.respond_to?(:abstract_type) ? new_i_m.abstract_type : new_i_m
|
114
|
+
new_name = Schema::Member::BuildType.to_type_name(new_int_type)
|
115
|
+
|
116
|
+
new_name == old_name
|
117
|
+
}
|
118
|
+
}
|
119
|
+
own_interface_type_memberships.concat(new_memberships)
|
120
|
+
end
|
121
|
+
|
122
|
+
def own_interface_type_memberships
|
123
|
+
@own_interface_type_memberships ||= []
|
90
124
|
end
|
91
125
|
|
92
|
-
def
|
93
|
-
|
126
|
+
def interface_type_memberships
|
127
|
+
own_interface_type_memberships + (superclass.respond_to?(:interface_type_memberships) ? superclass.interface_type_memberships : [])
|
94
128
|
end
|
95
129
|
|
96
|
-
|
97
|
-
|
130
|
+
# param context [Query::Context] If omitted, skip filtering.
|
131
|
+
def interfaces(context = GraphQL::Query::NullContext)
|
132
|
+
visible_interfaces = []
|
133
|
+
unfiltered = context == GraphQL::Query::NullContext
|
134
|
+
own_interface_type_memberships.each do |type_membership|
|
135
|
+
# During initialization, `type_memberships` can hold late-bound types
|
136
|
+
case type_membership
|
137
|
+
when String, Schema::LateBoundType
|
138
|
+
visible_interfaces << type_membership
|
139
|
+
when Schema::TypeMembership
|
140
|
+
if unfiltered || type_membership.visible?(context)
|
141
|
+
visible_interfaces << type_membership.abstract_type
|
142
|
+
end
|
143
|
+
else
|
144
|
+
raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
visible_interfaces + (superclass <= GraphQL::Schema::Object ? superclass.interfaces(context) : [])
|
98
148
|
end
|
99
149
|
|
100
|
-
#
|
150
|
+
# @return [Hash<String => GraphQL::Schema::Field>] All of this object's fields, indexed by name
|
151
|
+
# @see get_field A faster way to find one field by name ({#fields} merges hashes of inherited fields; {#get_field} just looks up one field.)
|
101
152
|
def fields
|
102
153
|
all_fields = super
|
103
154
|
interfaces.each do |int|
|
155
|
+
# Include legacy-style interfaces, too
|
104
156
|
if int.is_a?(GraphQL::InterfaceType)
|
105
157
|
int_f = {}
|
106
158
|
int.fields.each do |name, legacy_field|
|
@@ -117,9 +169,10 @@ module GraphQL
|
|
117
169
|
obj_type = GraphQL::ObjectType.new
|
118
170
|
obj_type.name = graphql_name
|
119
171
|
obj_type.description = description
|
120
|
-
obj_type.
|
172
|
+
obj_type.structural_interface_type_memberships = interface_type_memberships
|
121
173
|
obj_type.introspection = introspection
|
122
174
|
obj_type.mutation = mutation
|
175
|
+
obj_type.ast_node = ast_node
|
123
176
|
fields.each do |field_name, field_inst|
|
124
177
|
field_defn = field_inst.to_graphql
|
125
178
|
obj_type.fields[field_defn.name] = field_defn
|
@@ -14,9 +14,10 @@ module GraphQL
|
|
14
14
|
class PossibleTypes
|
15
15
|
def initialize(schema)
|
16
16
|
@object_types = schema.types.values.select { |type| type.kind.object? }
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
@interface_implementers = Hash.new do |h1, ctx|
|
18
|
+
h1[ctx] = Hash.new do |h2, int_type|
|
19
|
+
h2[int_type] = @object_types.select { |type| type.interfaces(ctx).include?(int_type) }.sort_by(&:name)
|
20
|
+
end
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
@@ -27,13 +28,17 @@ module GraphQL
|
|
27
28
|
when GraphQL::UnionType
|
28
29
|
type_defn.possible_types(ctx)
|
29
30
|
when GraphQL::InterfaceType
|
30
|
-
|
31
|
+
interface_implementers(ctx, type_defn)
|
31
32
|
when GraphQL::BaseType
|
32
33
|
[type_defn]
|
33
34
|
else
|
34
35
|
raise "Unexpected possible_types object: #{type_defn.inspect}"
|
35
36
|
end
|
36
37
|
end
|
38
|
+
|
39
|
+
def interface_implementers(ctx, type_defn)
|
40
|
+
@interface_implementers[ctx][type_defn]
|
41
|
+
end
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
@@ -54,7 +54,6 @@ module GraphQL
|
|
54
54
|
)
|
55
55
|
|
56
56
|
@document = @document_from_schema.document
|
57
|
-
|
58
57
|
@schema = schema
|
59
58
|
end
|
60
59
|
|
@@ -95,20 +94,6 @@ module GraphQL
|
|
95
94
|
print(node)
|
96
95
|
end
|
97
96
|
|
98
|
-
def print_directive(directive)
|
99
|
-
if directive.name == "deprecated"
|
100
|
-
reason = directive.arguments.find { |arg| arg.name == "reason" }
|
101
|
-
|
102
|
-
if reason.value == GraphQL::Directive::DEFAULT_DEPRECATION_REASON
|
103
|
-
"@deprecated"
|
104
|
-
else
|
105
|
-
"@deprecated(reason: #{reason.value.to_s.inspect})"
|
106
|
-
end
|
107
|
-
else
|
108
|
-
super
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
97
|
class IntrospectionPrinter < GraphQL::Language::Printer
|
113
98
|
def print_schema_definition(schema)
|
114
99
|
"schema {\n query: Root\n}"
|
@@ -61,7 +61,7 @@ module GraphQL
|
|
61
61
|
end
|
62
62
|
|
63
63
|
return_value = if input_kwargs.any?
|
64
|
-
super(input_kwargs)
|
64
|
+
super(**input_kwargs)
|
65
65
|
else
|
66
66
|
super()
|
67
67
|
end
|
@@ -105,7 +105,7 @@ module GraphQL
|
|
105
105
|
sig = super
|
106
106
|
# Arguments were added at the root, but they should be nested
|
107
107
|
sig[:arguments].clear
|
108
|
-
sig[:arguments][:input] = { type: input_type, required: true }
|
108
|
+
sig[:arguments][:input] = { type: input_type, required: true, description: "Parameters for #{graphql_name}" }
|
109
109
|
sig
|
110
110
|
end
|
111
111
|
|
@@ -122,7 +122,9 @@ module GraphQL
|
|
122
122
|
graphql_name("#{mutation_name}Input")
|
123
123
|
description("Autogenerated input type of #{mutation_name}")
|
124
124
|
mutation(mutation_class)
|
125
|
-
|
125
|
+
mutation_args.each do |_name, arg|
|
126
|
+
add_argument(arg)
|
127
|
+
end
|
126
128
|
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
127
129
|
end
|
128
130
|
end
|
@@ -26,8 +26,10 @@ module GraphQL
|
|
26
26
|
def field_class(new_class = nil)
|
27
27
|
if new_class
|
28
28
|
@field_class = new_class
|
29
|
+
elsif defined?(@field_class) && @field_class
|
30
|
+
@field_class
|
29
31
|
else
|
30
|
-
|
32
|
+
find_inherited_value(:field_class, GraphQL::Schema::Field)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -56,7 +58,8 @@ module GraphQL
|
|
56
58
|
resolver_fields.each do |name, f|
|
57
59
|
# Reattach the already-defined field here
|
58
60
|
# (The field's `.owner` will still point to the mutation, not the object type, I think)
|
59
|
-
|
61
|
+
# Don't re-warn about a method conflict. Since this type is generated, it should be fixed in the resolver instead.
|
62
|
+
add_field(f, method_conflict_warning: false)
|
60
63
|
end
|
61
64
|
end
|
62
65
|
end
|
@@ -40,6 +40,7 @@ module GraphQL
|
|
40
40
|
@arguments_by_keyword[arg.keyword] = arg
|
41
41
|
end
|
42
42
|
@arguments_loads_as_type = self.class.arguments_loads_as_type
|
43
|
+
@prepared_arguments = nil
|
43
44
|
end
|
44
45
|
|
45
46
|
# @return [Object] The application object this field is being resolved on
|
@@ -51,6 +52,10 @@ module GraphQL
|
|
51
52
|
# @return [GraphQL::Schema::Field]
|
52
53
|
attr_reader :field
|
53
54
|
|
55
|
+
def arguments
|
56
|
+
@prepared_arguments || raise("Arguments have not been prepared yet, still waiting for #load_arguments to resolve. (Call `.arguments` later in the code.)")
|
57
|
+
end
|
58
|
+
|
54
59
|
# This method is _actually_ called by the runtime,
|
55
60
|
# it does some preparation and then eventually calls
|
56
61
|
# the user-defined `#resolve` method.
|
@@ -74,9 +79,10 @@ module GraphQL
|
|
74
79
|
# for that argument, or may return a lazy object
|
75
80
|
load_arguments_val = load_arguments(args)
|
76
81
|
context.schema.after_lazy(load_arguments_val) do |loaded_args|
|
82
|
+
@prepared_arguments = loaded_args
|
77
83
|
# Then call `authorized?`, which may raise or may return a lazy object
|
78
84
|
authorized_val = if loaded_args.any?
|
79
|
-
authorized?(loaded_args)
|
85
|
+
authorized?(**loaded_args)
|
80
86
|
else
|
81
87
|
authorized?
|
82
88
|
end
|
@@ -135,20 +141,8 @@ module GraphQL
|
|
135
141
|
def authorized?(**inputs)
|
136
142
|
self.class.arguments.each_value do |argument|
|
137
143
|
arg_keyword = argument.keyword
|
138
|
-
if inputs.key?(arg_keyword) && !(
|
139
|
-
|
140
|
-
# If this argument resulted in an object being loaded,
|
141
|
-
# then authorize this loaded object with its own policy.
|
142
|
-
#
|
143
|
-
# But if this argument was "just" a plain argument, like
|
144
|
-
# a boolean, then authorize it based on the mutation.
|
145
|
-
authorization_value = if loads_type
|
146
|
-
value
|
147
|
-
else
|
148
|
-
self
|
149
|
-
end
|
150
|
-
|
151
|
-
arg_auth, err = argument.authorized?(authorization_value, context)
|
144
|
+
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
145
|
+
arg_auth, err = argument.authorized?(self, arg_value, context)
|
152
146
|
if !arg_auth
|
153
147
|
return arg_auth, err
|
154
148
|
else
|
@@ -232,7 +226,7 @@ module GraphQL
|
|
232
226
|
# or use it as a configuration method to assign a return type
|
233
227
|
# instead of generating one.
|
234
228
|
# TODO unify with {#null}
|
235
|
-
# @param new_type [Class, nil] If a type definition class is provided, it will be used as the return type of the field
|
229
|
+
# @param new_type [Class, Array<Class>, nil] If a type definition class is provided, it will be used as the return type of the field
|
236
230
|
# @param null [true, false] Whether or not the field may return `nil`
|
237
231
|
# @return [Class] The type which this field returns.
|
238
232
|
def type(new_type = nil, null: nil)
|
@@ -262,6 +256,19 @@ module GraphQL
|
|
262
256
|
@complexity || (superclass.respond_to?(:complexity) ? superclass.complexity : 1)
|
263
257
|
end
|
264
258
|
|
259
|
+
def broadcastable(new_broadcastable)
|
260
|
+
@broadcastable = new_broadcastable
|
261
|
+
end
|
262
|
+
|
263
|
+
# @return [Boolean, nil]
|
264
|
+
def broadcastable?
|
265
|
+
if defined?(@broadcastable)
|
266
|
+
@broadcastable
|
267
|
+
else
|
268
|
+
(superclass.respond_to?(:broadcastable?) ? superclass.broadcastable? : nil)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
265
272
|
def field_options
|
266
273
|
{
|
267
274
|
type: type_expr,
|
@@ -273,6 +280,7 @@ module GraphQL
|
|
273
280
|
null: null,
|
274
281
|
complexity: complexity,
|
275
282
|
extensions: extensions,
|
283
|
+
broadcastable: broadcastable?,
|
276
284
|
}
|
277
285
|
end
|
278
286
|
|
@@ -297,7 +305,7 @@ module GraphQL
|
|
297
305
|
argument = @arguments_by_keyword[:#{arg_defn.keyword}]
|
298
306
|
lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
|
299
307
|
context.schema.after_lazy(values) do |values2|
|
300
|
-
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, lookup_as_type, value) })
|
308
|
+
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, lookup_as_type, value, context) })
|
301
309
|
end
|
302
310
|
end
|
303
311
|
RUBY
|
@@ -306,7 +314,7 @@ module GraphQL
|
|
306
314
|
def load_#{arg_defn.keyword}(value)
|
307
315
|
argument = @arguments_by_keyword[:#{arg_defn.keyword}]
|
308
316
|
lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
|
309
|
-
load_application_object(argument, lookup_as_type, value)
|
317
|
+
load_application_object(argument, lookup_as_type, value, context)
|
310
318
|
end
|
311
319
|
RUBY
|
312
320
|
else
|
@@ -3,11 +3,9 @@ module GraphQL
|
|
3
3
|
class Schema
|
4
4
|
class Scalar < GraphQL::Schema::Member
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
|
+
extend GraphQL::Schema::Member::ValidatesInput
|
6
7
|
|
7
8
|
class << self
|
8
|
-
extend Forwardable
|
9
|
-
def_delegators :graphql_definition, :coerce_isolated_input, :coerce_isolated_result
|
10
|
-
|
11
9
|
def coerce_input(val, ctx)
|
12
10
|
val
|
13
11
|
end
|
@@ -24,6 +22,7 @@ module GraphQL
|
|
24
22
|
type_defn.coerce_input = method(:coerce_input)
|
25
23
|
type_defn.metadata[:type_class] = self
|
26
24
|
type_defn.default_scalar = default_scalar
|
25
|
+
type_defn.ast_node = ast_node
|
27
26
|
type_defn
|
28
27
|
end
|
29
28
|
|
@@ -37,6 +36,31 @@ module GraphQL
|
|
37
36
|
end
|
38
37
|
@default_scalar
|
39
38
|
end
|
39
|
+
|
40
|
+
def default_scalar?
|
41
|
+
@default_scalar ||= false
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_non_null_input(value, ctx)
|
45
|
+
result = Query::InputValidationResult.new
|
46
|
+
coerced_result = begin
|
47
|
+
coerce_input(value, ctx)
|
48
|
+
rescue GraphQL::CoercionError => err
|
49
|
+
err
|
50
|
+
end
|
51
|
+
|
52
|
+
if coerced_result.nil?
|
53
|
+
str_value = if value == Float::INFINITY
|
54
|
+
""
|
55
|
+
else
|
56
|
+
" #{GraphQL::Language.serialize(value)}"
|
57
|
+
end
|
58
|
+
result.add_problem("Could not coerce value#{str_value} to #{graphql_name}")
|
59
|
+
elsif coerced_result.is_a?(GraphQL::CoercionError)
|
60
|
+
result.add_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
|
61
|
+
end
|
62
|
+
result
|
63
|
+
end
|
40
64
|
end
|
41
65
|
end
|
42
66
|
end
|