graphql 1.12.24 → 1.13.19
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 +3 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/install_generator.rb +10 -3
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +8 -37
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/mutation.erb +1 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/field_usage.rb +2 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +5 -4
- data/lib/graphql/argument.rb +1 -1
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/base_type.rb +5 -3
- data/lib/graphql/boolean_type.rb +1 -1
- data/lib/graphql/dataloader/source.rb +2 -2
- data/lib/graphql/dataloader.rb +55 -22
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/define/instance_definable.rb +15 -0
- data/lib/graphql/directive/deprecated_directive.rb +1 -1
- data/lib/graphql/directive/include_directive.rb +1 -1
- data/lib/graphql/directive/skip_directive.rb +1 -1
- data/lib/graphql/directive.rb +1 -5
- data/lib/graphql/enum_type.rb +7 -3
- data/lib/graphql/execution/errors.rb +1 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +6 -4
- data/lib/graphql/execution/interpreter/runtime.rb +66 -38
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +4 -1
- data/lib/graphql/field.rb +1 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/interface_type.rb +1 -1
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +5 -3
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +3 -3
- data/lib/graphql/introspection/input_value_type.rb +4 -4
- data/lib/graphql/introspection/schema_type.rb +9 -4
- data/lib/graphql/introspection/type_type.rb +18 -12
- data/lib/graphql/introspection.rb +4 -1
- data/lib/graphql/language/block_string.rb +2 -6
- data/lib/graphql/language/document_from_schema_definition.rb +11 -4
- data/lib/graphql/language/lexer.rb +50 -28
- data/lib/graphql/language/lexer.rl +2 -4
- data/lib/graphql/language/nodes.rb +4 -3
- data/lib/graphql/language/parser.rb +841 -820
- data/lib/graphql/language/parser.y +13 -6
- data/lib/graphql/language/printer.rb +10 -1
- data/lib/graphql/language/sanitized_printer.rb +5 -5
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/object_type.rb +2 -2
- data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
- data/lib/graphql/pagination/relation_connection.rb +59 -29
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +15 -2
- data/lib/graphql/query/input_validation_result.rb +9 -0
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +12 -7
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +2 -3
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -4
- data/lib/graphql/query.rb +0 -1
- data/lib/graphql/relay/connection_type.rb +15 -2
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/global_id_resolve.rb +1 -2
- data/lib/graphql/relay/mutation.rb +1 -1
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/relay/range_add.rb +4 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/scalar_type.rb +1 -1
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +30 -15
- data/lib/graphql/schema/build_from_definition.rb +6 -5
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +23 -4
- data/lib/graphql/schema/enum.rb +61 -12
- data/lib/graphql/schema/enum_value.rb +6 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +261 -83
- data/lib/graphql/schema/field_extension.rb +89 -2
- data/lib/graphql/schema/find_inherited_value.rb +1 -0
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +24 -7
- data/lib/graphql/schema/interface.rb +11 -20
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/list.rb +21 -4
- data/lib/graphql/schema/loader.rb +3 -0
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/build_type.rb +0 -4
- data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
- data/lib/graphql/schema/member/has_arguments.rb +56 -14
- data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +76 -18
- data/lib/graphql/schema/member/has_interfaces.rb +100 -0
- data/lib/graphql/schema/member/validates_input.rb +2 -2
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/non_null.rb +9 -3
- data/lib/graphql/schema/object.rb +10 -75
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +37 -17
- data/lib/graphql/schema/scalar.rb +15 -1
- data/lib/graphql/schema/subscription.rb +11 -1
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +8 -1
- data/lib/graphql/schema/validator/format_validator.rb +0 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +4 -7
- data/lib/graphql/schema/warden.rb +126 -53
- data/lib/graphql/schema.rb +120 -24
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +6 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/static_validation/validation_context.rb +4 -0
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions/serialize.rb +22 -2
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +20 -10
- data/lib/graphql/types/iso_8601_date.rb +13 -5
- data/lib/graphql/types/iso_8601_date_time.rb +8 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +28 -10
- data/lib/graphql/types/relay/default_relay.rb +5 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/types/relay/node_field.rb +2 -3
- data/lib/graphql/types/relay/nodes_field.rb +19 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/union_type.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +22 -32
- metadata +31 -11
- /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
- /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
data/lib/graphql/schema.rb
CHANGED
@@ -92,6 +92,8 @@ module GraphQL
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
+
class DuplicateNamesError < GraphQL::Error; end
|
96
|
+
|
95
97
|
class UnresolvedLateBoundTypeError < GraphQL::Error
|
96
98
|
attr_reader :type
|
97
99
|
def initialize(type:)
|
@@ -159,7 +161,7 @@ module GraphQL
|
|
159
161
|
include LazyHandlingMethods
|
160
162
|
extend LazyHandlingMethods
|
161
163
|
|
162
|
-
|
164
|
+
deprecated_accepts_definitions \
|
163
165
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
164
166
|
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
165
167
|
:orphan_types, :resolve_type, :type_error, :parse_error,
|
@@ -843,7 +845,7 @@ module GraphQL
|
|
843
845
|
# - Cause the Schema instance to be created, if it hasn't been created yet
|
844
846
|
# - Delegate to that instance
|
845
847
|
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
846
|
-
def_delegators :
|
848
|
+
def_delegators :deprecated_graphql_definition,
|
847
849
|
# Execution
|
848
850
|
:execution_strategy_for_operation,
|
849
851
|
# Configuration
|
@@ -852,6 +854,10 @@ module GraphQL
|
|
852
854
|
:id_from_object=, :object_from_id=,
|
853
855
|
:remove_handler
|
854
856
|
|
857
|
+
def deprecated_graphql_definition
|
858
|
+
graphql_definition(silence_deprecation_warning: true)
|
859
|
+
end
|
860
|
+
|
855
861
|
# @return [GraphQL::Subscriptions]
|
856
862
|
attr_accessor :subscriptions
|
857
863
|
|
@@ -886,6 +892,17 @@ module GraphQL
|
|
886
892
|
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
887
893
|
end
|
888
894
|
|
895
|
+
# @return [String, nil]
|
896
|
+
def description(new_description = nil)
|
897
|
+
if new_description
|
898
|
+
@description = new_description
|
899
|
+
elsif defined?(@description)
|
900
|
+
@description
|
901
|
+
else
|
902
|
+
find_inherited_value(:description, nil)
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
889
906
|
def find(path)
|
890
907
|
if !@finder
|
891
908
|
@find_cache = {}
|
@@ -894,8 +911,15 @@ module GraphQL
|
|
894
911
|
@find_cache[path] ||= @finder.find(path)
|
895
912
|
end
|
896
913
|
|
897
|
-
def graphql_definition
|
898
|
-
@graphql_definition ||=
|
914
|
+
def graphql_definition(silence_deprecation_warning: false)
|
915
|
+
@graphql_definition ||= begin
|
916
|
+
unless silence_deprecation_warning
|
917
|
+
message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Use a class-based definition instead."
|
918
|
+
caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
|
919
|
+
GraphQL::Deprecation.warn(message + caller_message)
|
920
|
+
end
|
921
|
+
to_graphql(silence_deprecation_warning: silence_deprecation_warning)
|
922
|
+
end
|
899
923
|
end
|
900
924
|
|
901
925
|
def default_filter
|
@@ -927,19 +951,20 @@ module GraphQL
|
|
927
951
|
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
928
952
|
end
|
929
953
|
|
954
|
+
prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
930
955
|
def to_graphql
|
931
956
|
schema_defn = self.new
|
932
957
|
schema_defn.raise_definition_error = true
|
933
|
-
schema_defn.query = query && query.graphql_definition
|
934
|
-
schema_defn.mutation = mutation && mutation.graphql_definition
|
935
|
-
schema_defn.subscription = subscription && subscription.graphql_definition
|
958
|
+
schema_defn.query = query && query.graphql_definition(silence_deprecation_warning: true)
|
959
|
+
schema_defn.mutation = mutation && mutation.graphql_definition(silence_deprecation_warning: true)
|
960
|
+
schema_defn.subscription = subscription && subscription.graphql_definition(silence_deprecation_warning: true)
|
936
961
|
schema_defn.validate_timeout = validate_timeout
|
937
962
|
schema_defn.validate_max_errors = validate_max_errors
|
938
963
|
schema_defn.max_complexity = max_complexity
|
939
964
|
schema_defn.error_bubbling = error_bubbling
|
940
965
|
schema_defn.max_depth = max_depth
|
941
966
|
schema_defn.default_max_page_size = default_max_page_size
|
942
|
-
schema_defn.orphan_types = orphan_types.map(
|
967
|
+
schema_defn.orphan_types = orphan_types.map { |t| t.graphql_definition(silence_deprecation_warning: true) }
|
943
968
|
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
944
969
|
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
945
970
|
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
@@ -996,16 +1021,58 @@ module GraphQL
|
|
996
1021
|
# Build a map of `{ name => type }` and return it
|
997
1022
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
998
1023
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
999
|
-
def types
|
1000
|
-
non_introspection_types.merge(introspection_system.types)
|
1024
|
+
def types(context = GraphQL::Query::NullContext)
|
1025
|
+
all_types = non_introspection_types.merge(introspection_system.types)
|
1026
|
+
visible_types = {}
|
1027
|
+
all_types.each do |k, v|
|
1028
|
+
visible_types[k] =if v.is_a?(Array)
|
1029
|
+
visible_t = nil
|
1030
|
+
v.each do |t|
|
1031
|
+
if t.visible?(context)
|
1032
|
+
if visible_t.nil?
|
1033
|
+
visible_t = t
|
1034
|
+
else
|
1035
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
visible_t
|
1040
|
+
else
|
1041
|
+
v
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
visible_types
|
1001
1045
|
end
|
1002
1046
|
|
1003
1047
|
# @param type_name [String]
|
1004
1048
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1005
|
-
def get_type(type_name)
|
1006
|
-
own_types[type_name]
|
1007
|
-
|
1008
|
-
|
1049
|
+
def get_type(type_name, context = GraphQL::Query::NullContext)
|
1050
|
+
local_entry = own_types[type_name]
|
1051
|
+
type_defn = case local_entry
|
1052
|
+
when nil
|
1053
|
+
nil
|
1054
|
+
when Array
|
1055
|
+
visible_t = nil
|
1056
|
+
warden = Warden.from_context(context)
|
1057
|
+
local_entry.each do |t|
|
1058
|
+
if warden.visible_type?(t, context)
|
1059
|
+
if visible_t.nil?
|
1060
|
+
visible_t = t
|
1061
|
+
else
|
1062
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
visible_t
|
1067
|
+
when Module
|
1068
|
+
local_entry
|
1069
|
+
else
|
1070
|
+
raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
type_defn ||
|
1074
|
+
introspection_system.types[type_name] || # todo context-specific introspection?
|
1075
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
1009
1076
|
end
|
1010
1077
|
|
1011
1078
|
# @api private
|
@@ -1182,19 +1249,19 @@ module GraphQL
|
|
1182
1249
|
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
1183
1250
|
end
|
1184
1251
|
|
1185
|
-
def get_field(type_or_name, field_name)
|
1252
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
1186
1253
|
parent_type = case type_or_name
|
1187
1254
|
when LateBoundType
|
1188
|
-
get_type(type_or_name.name)
|
1255
|
+
get_type(type_or_name.name, context)
|
1189
1256
|
when String
|
1190
|
-
get_type(type_or_name)
|
1257
|
+
get_type(type_or_name, context)
|
1191
1258
|
when Module
|
1192
1259
|
type_or_name
|
1193
1260
|
else
|
1194
|
-
raise
|
1261
|
+
raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1195
1262
|
end
|
1196
1263
|
|
1197
|
-
if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
|
1264
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
1198
1265
|
field
|
1199
1266
|
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1200
1267
|
entry_point_field
|
@@ -1205,8 +1272,8 @@ module GraphQL
|
|
1205
1272
|
end
|
1206
1273
|
end
|
1207
1274
|
|
1208
|
-
def get_fields(type)
|
1209
|
-
type.fields
|
1275
|
+
def get_fields(type, context = GraphQL::Query::NullContext)
|
1276
|
+
type.fields(context)
|
1210
1277
|
end
|
1211
1278
|
|
1212
1279
|
def introspection(new_introspection_namespace = nil)
|
@@ -1405,7 +1472,6 @@ module GraphQL
|
|
1405
1472
|
if new_orphan_types.any?
|
1406
1473
|
new_orphan_types = new_orphan_types.flatten
|
1407
1474
|
add_type_and_traverse(new_orphan_types, root: false)
|
1408
|
-
@orphan_types = new_orphan_types
|
1409
1475
|
own_orphan_types.concat(new_orphan_types.flatten)
|
1410
1476
|
end
|
1411
1477
|
|
@@ -1664,6 +1730,7 @@ module GraphQL
|
|
1664
1730
|
{
|
1665
1731
|
backtrace: ctx[:backtrace],
|
1666
1732
|
tracers: ctx[:tracers],
|
1733
|
+
dataloader: ctx[:dataloader],
|
1667
1734
|
}
|
1668
1735
|
else
|
1669
1736
|
{}
|
@@ -1715,7 +1782,7 @@ module GraphQL
|
|
1715
1782
|
if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
|
1716
1783
|
GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
|
1717
1784
|
else
|
1718
|
-
subscription.
|
1785
|
+
subscription.all_field_definitions.each do |field|
|
1719
1786
|
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1720
1787
|
end
|
1721
1788
|
end
|
@@ -1737,7 +1804,36 @@ module GraphQL
|
|
1737
1804
|
end
|
1738
1805
|
new_types = Array(t)
|
1739
1806
|
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1740
|
-
|
1807
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1808
|
+
if (prev_entry = own_types[name])
|
1809
|
+
prev_entries = case prev_entry
|
1810
|
+
when Array
|
1811
|
+
prev_entry
|
1812
|
+
when Module
|
1813
|
+
own_types[name] = [prev_entry]
|
1814
|
+
else
|
1815
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
case types_entry
|
1819
|
+
when Array
|
1820
|
+
prev_entries.concat(types_entry)
|
1821
|
+
prev_entries.uniq! # in case any are being re-visited
|
1822
|
+
when Module
|
1823
|
+
if !prev_entries.include?(types_entry)
|
1824
|
+
prev_entries << types_entry
|
1825
|
+
end
|
1826
|
+
else
|
1827
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1828
|
+
end
|
1829
|
+
else
|
1830
|
+
if types_entry.is_a?(Array)
|
1831
|
+
types_entry.uniq!
|
1832
|
+
end
|
1833
|
+
own_types[name] = types_entry
|
1834
|
+
end
|
1835
|
+
end
|
1836
|
+
|
1741
1837
|
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1742
1838
|
own_union_memberships.merge!(addition.union_memberships)
|
1743
1839
|
|
@@ -33,6 +33,7 @@ module GraphQL
|
|
33
33
|
GraphQL::StaticValidation::VariablesAreUsedAndDefined,
|
34
34
|
GraphQL::StaticValidation::VariableUsagesAreAllowed,
|
35
35
|
GraphQL::StaticValidation::MutationRootExists,
|
36
|
+
GraphQL::StaticValidation::QueryRootExists,
|
36
37
|
GraphQL::StaticValidation::SubscriptionRootExists,
|
37
38
|
GraphQL::StaticValidation::InputObjectNamesAreUnique,
|
38
39
|
]
|
@@ -94,7 +94,7 @@ module GraphQL
|
|
94
94
|
|
95
95
|
def on_field(node, parent)
|
96
96
|
parent_type = @object_types.last
|
97
|
-
field_definition = @schema.get_field(parent_type, node.name)
|
97
|
+
field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
|
98
98
|
@field_definitions.push(field_definition)
|
99
99
|
if !field_definition.nil?
|
100
100
|
next_object_type = field_definition.type.unwrap
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def on_directive(node, parent)
|
113
|
-
directive_defn = @
|
113
|
+
directive_defn = @context.schema_directives[node.name]
|
114
114
|
@directive_definitions.push(directive_defn)
|
115
115
|
super
|
116
116
|
@directive_definitions.pop
|
@@ -120,14 +120,14 @@ module GraphQL
|
|
120
120
|
argument_defn = if (arg = @argument_definitions.last)
|
121
121
|
arg_type = arg.type.unwrap
|
122
122
|
if arg_type.kind.input_object?
|
123
|
-
arg_type
|
123
|
+
@context.warden.get_argument(arg_type, node.name)
|
124
124
|
else
|
125
125
|
nil
|
126
126
|
end
|
127
127
|
elsif (directive_defn = @directive_definitions.last)
|
128
|
-
directive_defn
|
128
|
+
@context.warden.get_argument(directive_defn, node.name)
|
129
129
|
elsif (field_defn = @field_definitions.last)
|
130
|
-
field_defn
|
130
|
+
@context.warden.get_argument(field_defn, node.name)
|
131
131
|
else
|
132
132
|
nil
|
133
133
|
end
|
@@ -187,7 +187,7 @@ module GraphQL
|
|
187
187
|
|
188
188
|
def on_fragment_with_type(node)
|
189
189
|
object_type = if node.type
|
190
|
-
@
|
190
|
+
@context.warden.get_type(node.type.name)
|
191
191
|
else
|
192
192
|
@object_types.last
|
193
193
|
end
|
@@ -95,7 +95,7 @@ module GraphQL
|
|
95
95
|
def required_input_fields_are_present(type, ast_node)
|
96
96
|
# TODO - would be nice to use these to create an error message so the caller knows
|
97
97
|
# that required fields are missing
|
98
|
-
required_field_names =
|
98
|
+
required_field_names = @warden.arguments(type)
|
99
99
|
.select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
|
100
100
|
.map(&:name)
|
101
101
|
|
@@ -15,7 +15,7 @@ module GraphQL
|
|
15
15
|
if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
|
16
16
|
parent_defn = parent_definition(parent)
|
17
17
|
|
18
|
-
if parent_defn && (arg_defn = parent_defn
|
18
|
+
if parent_defn && (arg_defn = context.warden.get_argument(parent_defn, node.name))
|
19
19
|
validation_result = context.validate_literal(node.value, arg_defn.type)
|
20
20
|
if !validation_result.valid?
|
21
21
|
kind_of_node = node_type(parent)
|
@@ -340,7 +340,7 @@ module GraphQL
|
|
340
340
|
selections.each do |node|
|
341
341
|
case node
|
342
342
|
when GraphQL::Language::Nodes::Field
|
343
|
-
definition = context.
|
343
|
+
definition = context.query.get_field(owner_type, node.name)
|
344
344
|
fields << Field.new(node, definition, owner_type, parents)
|
345
345
|
when GraphQL::Language::Nodes::InlineFragment
|
346
346
|
fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
module QueryRootExists
|
5
|
+
def on_operation_definition(node, _parent)
|
6
|
+
if (node.operation_type == 'query' || node.operation_type.nil?) && context.warden.root_type_for_operation("query").nil?
|
7
|
+
add_error(GraphQL::StaticValidation::QueryRootExistsError.new(
|
8
|
+
'Schema is not configured for queries',
|
9
|
+
nodes: node
|
10
|
+
))
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class QueryRootExistsError < StaticValidation::Error
|
5
|
+
|
6
|
+
def initialize(message, path: nil, nodes: [])
|
7
|
+
super(message, path: path, nodes: nodes)
|
8
|
+
end
|
9
|
+
|
10
|
+
# A hash representation of this Message
|
11
|
+
def to_h
|
12
|
+
extensions = {
|
13
|
+
"code" => code,
|
14
|
+
}
|
15
|
+
|
16
|
+
super.merge({
|
17
|
+
"extensions" => extensions
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
def code
|
22
|
+
"missingQueryConfiguration"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -8,7 +8,7 @@ module GraphQL
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def on_directive(node, _parent)
|
11
|
-
directive_defn = context.
|
11
|
+
directive_defn = context.schema_directives[node.name]
|
12
12
|
assert_required_args(node, directive_defn)
|
13
13
|
super
|
14
14
|
end
|
@@ -16,10 +16,10 @@ module GraphQL
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
19
|
-
args = defn.arguments
|
19
|
+
args = defn.arguments(context.query.context)
|
20
20
|
return if args.empty?
|
21
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
22
|
-
required_argument_names =
|
22
|
+
required_argument_names = context.warden.arguments(defn)
|
23
23
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
24
24
|
.map(&:name)
|
25
25
|
|
@@ -34,16 +34,16 @@ module GraphQL
|
|
34
34
|
parent_type = get_parent_type(context, parent)
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
36
36
|
|
37
|
-
required_fields =
|
38
|
-
.select{|
|
39
|
-
.
|
37
|
+
required_fields = context.warden.arguments(parent_type)
|
38
|
+
.select{|arg| arg.type.kind.non_null?}
|
39
|
+
.map(&:graphql_name)
|
40
40
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
42
42
|
missing_fields = required_fields - present_fields
|
43
43
|
|
44
44
|
missing_fields.each do |missing_field|
|
45
45
|
path = [*context.path, missing_field]
|
46
|
-
missing_field_type = parent_type
|
46
|
+
missing_field_type = context.warden.get_argument(parent_type, missing_field).type
|
47
47
|
add_error(RequiredInputObjectAttributesArePresentError.new(
|
48
48
|
"Argument '#{missing_field}' on InputObject '#{parent_type.to_type_signature}' is required. Expected type #{missing_field_type.to_type_signature}",
|
49
49
|
argument_name: missing_field,
|
@@ -40,7 +40,7 @@ module GraphQL
|
|
40
40
|
nodes: [used_directives[directive_name], ast_directive],
|
41
41
|
directive: directive_name,
|
42
42
|
))
|
43
|
-
|
43
|
+
elsif !((dir_defn = context.schema_directives[directive_name]) && dir_defn.repeatable?)
|
44
44
|
used_directives[directive_name] = ast_directive
|
45
45
|
end
|
46
46
|
end
|
@@ -22,15 +22,15 @@ module GraphQL
|
|
22
22
|
node_values = node_values.select { |value| value.is_a? GraphQL::Language::Nodes::VariableIdentifier }
|
23
23
|
|
24
24
|
if node_values.any?
|
25
|
-
|
25
|
+
argument_owner = case parent
|
26
26
|
when GraphQL::Language::Nodes::Field
|
27
|
-
context.field_definition
|
27
|
+
context.field_definition
|
28
28
|
when GraphQL::Language::Nodes::Directive
|
29
|
-
context.directive_definition
|
29
|
+
context.directive_definition
|
30
30
|
when GraphQL::Language::Nodes::InputObject
|
31
31
|
arg_type = context.argument_definition.type.unwrap
|
32
32
|
if arg_type.kind.input_object?
|
33
|
-
|
33
|
+
arg_type
|
34
34
|
else
|
35
35
|
# This is some kind of error
|
36
36
|
nil
|
@@ -43,7 +43,7 @@ module GraphQL
|
|
43
43
|
var_defn_ast = @declared_variables[node_value.name]
|
44
44
|
# Might be undefined :(
|
45
45
|
# VariablesAreUsedAndDefined can't finalize its search until the end of the document.
|
46
|
-
var_defn_ast &&
|
46
|
+
var_defn_ast && argument_owner && validate_usage(argument_owner, node, var_defn_ast)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
super
|
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
def validate_usage(
|
54
|
+
def validate_usage(argument_owner, arg_node, ast_var)
|
55
55
|
var_type = context.schema.type_from_ast(ast_var.type, context: context)
|
56
56
|
if var_type.nil?
|
57
57
|
return
|
@@ -65,9 +65,15 @@ module GraphQL
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
arg_defn =
|
68
|
+
arg_defn = context.warden.get_argument(argument_owner, arg_node.name)
|
69
69
|
arg_defn_type = arg_defn.type
|
70
70
|
|
71
|
+
# If the argument is non-null, but it was given a default value,
|
72
|
+
# then treat it as nullable in practice, see https://github.com/rmosolgo/graphql-ruby/issues/3793
|
73
|
+
if arg_defn_type.non_null? && arg_defn.default_value?
|
74
|
+
arg_defn_type = arg_defn_type.of_type
|
75
|
+
end
|
76
|
+
|
71
77
|
var_inner_type = var_type.unwrap
|
72
78
|
arg_inner_type = arg_defn_type.unwrap
|
73
79
|
|
data/lib/graphql/string_type.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
GraphQL::STRING_TYPE = GraphQL::Types::String.graphql_definition
|
2
|
+
GraphQL::STRING_TYPE = GraphQL::Types::String.graphql_definition(silence_deprecation_warning: true)
|
@@ -170,10 +170,12 @@ module GraphQL
|
|
170
170
|
first_subscription_id = first_event.context.fetch(:subscription_id)
|
171
171
|
object ||= load_action_cable_message(message, first_event.context)
|
172
172
|
result = execute_update(first_subscription_id, first_event, object)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
173
|
+
if !result.nil?
|
174
|
+
# Having calculated the result _once_, send the same payload to all subscribers
|
175
|
+
events.each do |event|
|
176
|
+
subscription_id = event.context.fetch(:subscription_id)
|
177
|
+
deliver(subscription_id, result)
|
178
|
+
end
|
177
179
|
end
|
178
180
|
end
|
179
181
|
end
|
@@ -214,6 +216,8 @@ module GraphQL
|
|
214
216
|
# The channel was closed, forget about it.
|
215
217
|
def delete_subscription(subscription_id)
|
216
218
|
query = @subscriptions.delete(subscription_id)
|
219
|
+
# In case this came from the server, tell the client to unsubscribe:
|
220
|
+
@action_cable.server.broadcast(stream_subscription_name(subscription_id), { more: false })
|
217
221
|
# This can be `nil` when `.trigger` happens inside an unsubscribed ActionCable channel,
|
218
222
|
# see https://github.com/rmosolgo/graphql-ruby/issues/2478
|
219
223
|
if query
|
@@ -23,15 +23,23 @@ module GraphQL
|
|
23
23
|
@arguments = arguments
|
24
24
|
@context = context
|
25
25
|
field ||= context.field
|
26
|
-
|
26
|
+
scope_key = field.subscription_scope
|
27
|
+
scope_val = scope || (context && scope_key && context[scope_key])
|
28
|
+
if scope_key &&
|
29
|
+
(subscription = field.resolver) &&
|
30
|
+
(subscription.respond_to?(:subscription_scope_optional?)) &&
|
31
|
+
!subscription.subscription_scope_optional? &&
|
32
|
+
scope_val.nil?
|
33
|
+
raise Subscriptions::SubscriptionScopeMissingError, "#{field.path} (#{subscription}) requires a `scope:` value to trigger updates (Set `subscription_scope ..., optional: true` to disable this requirement)"
|
34
|
+
end
|
27
35
|
|
28
|
-
@topic = self.class.serialize(name, arguments, field, scope: scope_val)
|
36
|
+
@topic = self.class.serialize(name, arguments, field, scope: scope_val, context: context)
|
29
37
|
end
|
30
38
|
|
31
39
|
# @return [String] an identifier for this unit of subscription
|
32
|
-
def self.serialize(_name, arguments, field, scope:)
|
40
|
+
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
|
33
41
|
subscription = field.resolver || GraphQL::Schema::Subscription
|
34
|
-
normalized_args = stringify_args(field, arguments.to_h)
|
42
|
+
normalized_args = stringify_args(field, arguments.to_h, context)
|
35
43
|
subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
|
36
44
|
end
|
37
45
|
|
@@ -83,7 +91,7 @@ module GraphQL
|
|
83
91
|
end
|
84
92
|
end
|
85
93
|
|
86
|
-
def stringify_args(arg_owner, args)
|
94
|
+
def stringify_args(arg_owner, args, context)
|
87
95
|
arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers
|
88
96
|
case args
|
89
97
|
when Hash
|
@@ -91,13 +99,13 @@ module GraphQL
|
|
91
99
|
args.each do |k, v|
|
92
100
|
arg_name = k.to_s
|
93
101
|
camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name)
|
94
|
-
arg_defn = get_arg_definition(arg_owner, camelized_arg_name)
|
102
|
+
arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context)
|
95
103
|
|
96
104
|
if arg_defn
|
97
105
|
normalized_arg_name = camelized_arg_name
|
98
106
|
else
|
99
107
|
normalized_arg_name = arg_name
|
100
|
-
arg_defn = get_arg_definition(arg_owner, normalized_arg_name)
|
108
|
+
arg_defn = get_arg_definition(arg_owner, normalized_arg_name, context)
|
101
109
|
end
|
102
110
|
arg_base_type = arg_defn.type.unwrap
|
103
111
|
# In the case where the value being emitted is seen as a "JSON"
|
@@ -113,22 +121,22 @@ module GraphQL
|
|
113
121
|
end
|
114
122
|
next_args[normalized_arg_name] = sorted_value.respond_to?(:to_json) ? sorted_value.to_json : sorted_value
|
115
123
|
else
|
116
|
-
next_args[normalized_arg_name] = stringify_args(arg_base_type, v)
|
124
|
+
next_args[normalized_arg_name] = stringify_args(arg_base_type, v, context)
|
117
125
|
end
|
118
126
|
end
|
119
127
|
# Make sure they're deeply sorted
|
120
128
|
next_args.sort.to_h
|
121
129
|
when Array
|
122
|
-
args.map { |a| stringify_args(arg_owner, a) }
|
130
|
+
args.map { |a| stringify_args(arg_owner, a, context) }
|
123
131
|
when GraphQL::Schema::InputObject
|
124
|
-
stringify_args(arg_owner, args.to_h)
|
132
|
+
stringify_args(arg_owner, args.to_h, context)
|
125
133
|
else
|
126
134
|
args
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
130
|
-
def get_arg_definition(arg_owner, arg_name)
|
131
|
-
arg_owner.
|
138
|
+
def get_arg_definition(arg_owner, arg_name, context)
|
139
|
+
arg_owner.get_argument(arg_name, context) || arg_owner.arguments(context).each_value.find { |v| v.keyword.to_s == arg_name }
|
132
140
|
end
|
133
141
|
end
|
134
142
|
end
|