graphql 1.13.3 → 1.13.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 +0 -7
- 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/{templates → install/templates}/base_mutation.erb +0 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
- data/lib/generators/graphql/install_generator.rb +1 -1
- 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 -9
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/visitor.rb +2 -1
- data/lib/graphql/dataloader/source.rb +2 -2
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +4 -2
- data/lib/graphql/execution/interpreter/runtime.rb +33 -17
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +2 -0
- data/lib/graphql/introspection/schema_type.rb +5 -0
- data/lib/graphql/introspection/type_type.rb +9 -3
- data/lib/graphql/introspection.rb +3 -0
- data/lib/graphql/language/document_from_schema_definition.rb +1 -0
- data/lib/graphql/language/lexer.rb +50 -25
- data/lib/graphql/language/lexer.rl +2 -0
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +829 -816
- data/lib/graphql/language/parser.y +8 -2
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/pagination/relation_connection.rb +8 -5
- data/lib/graphql/rubocop/graphql/default_required_true.rb +4 -4
- data/lib/graphql/schema/argument.rb +18 -1
- data/lib/graphql/schema/build_from_definition.rb +1 -0
- data/lib/graphql/schema/directive.rb +15 -0
- data/lib/graphql/schema/field.rb +13 -7
- data/lib/graphql/schema/loader.rb +3 -0
- data/lib/graphql/schema/scalar.rb +12 -0
- data/lib/graphql/schema.rb +12 -5
- data/lib/graphql/static_validation/base_visitor.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/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +4 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/data_dog_tracing.rb +6 -1
- data/lib/graphql/tracing/platform_tracing.rb +11 -6
- 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 +2 -1
- data/lib/graphql/types/relay/node_field.rb +0 -12
- data/lib/graphql/types/relay/nodes_field.rb +6 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +12 -0
- metadata +20 -8
@@ -8,13 +8,28 @@ require_relative 'core'
|
|
8
8
|
|
9
9
|
module Graphql
|
10
10
|
module Generators
|
11
|
-
class TypeGeneratorBase < Rails::Generators::
|
11
|
+
class TypeGeneratorBase < Rails::Generators::NamedBase
|
12
12
|
include Core
|
13
13
|
|
14
|
-
|
15
|
-
type: :
|
16
|
-
|
17
|
-
|
14
|
+
class_option 'namespaced_types',
|
15
|
+
type: :boolean,
|
16
|
+
required: false,
|
17
|
+
default: false,
|
18
|
+
banner: "Namespaced",
|
19
|
+
desc: "If the generated types will be namespaced"
|
20
|
+
|
21
|
+
argument :custom_fields,
|
22
|
+
type: :array,
|
23
|
+
default: [],
|
24
|
+
banner: "name:type name:type ...",
|
25
|
+
desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
|
26
|
+
|
27
|
+
|
28
|
+
attr_accessor :graphql_type
|
29
|
+
|
30
|
+
def create_type_file
|
31
|
+
template "#{graphql_type}.erb", "#{options[:directory]}/types#{subdirectory}/#{type_file_name}.rb"
|
32
|
+
end
|
18
33
|
|
19
34
|
# Take a type expression in any combination of GraphQL or Ruby styles
|
20
35
|
# and return it in a specified output style
|
@@ -60,12 +75,12 @@ module Graphql
|
|
60
75
|
|
61
76
|
# @return [String] The user-provided type name, normalized to Ruby code
|
62
77
|
def type_ruby_name
|
63
|
-
@type_ruby_name ||= self.class.normalize_type_expression(
|
78
|
+
@type_ruby_name ||= self.class.normalize_type_expression(name, mode: :ruby)[0]
|
64
79
|
end
|
65
80
|
|
66
81
|
# @return [String] The user-provided type name, as a GraphQL name
|
67
82
|
def type_graphql_name
|
68
|
-
@type_graphql_name ||= self.class.normalize_type_expression(
|
83
|
+
@type_graphql_name ||= self.class.normalize_type_expression(name, mode: :graphql)[0]
|
69
84
|
end
|
70
85
|
|
71
86
|
# @return [String] The user-provided type name, as a file name (without extension)
|
@@ -82,6 +97,24 @@ module Graphql
|
|
82
97
|
}
|
83
98
|
end
|
84
99
|
|
100
|
+
def ruby_class_name
|
101
|
+
class_prefix =
|
102
|
+
if options[:namespaced_types]
|
103
|
+
"#{graphql_type.pluralize.camelize}::"
|
104
|
+
else
|
105
|
+
""
|
106
|
+
end
|
107
|
+
@ruby_class_name || class_prefix + type_ruby_name.sub(/^Types::/, "")
|
108
|
+
end
|
109
|
+
|
110
|
+
def subdirectory
|
111
|
+
if options[:namespaced_types]
|
112
|
+
"/#{graphql_type.pluralize}"
|
113
|
+
else
|
114
|
+
""
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
85
118
|
class NormalizedField
|
86
119
|
def initialize(name, type_expr, null)
|
87
120
|
@name = name
|
@@ -89,8 +122,12 @@ module Graphql
|
|
89
122
|
@null = null
|
90
123
|
end
|
91
124
|
|
92
|
-
def
|
93
|
-
"field :#{@name}, #{@type_expr}, null:
|
125
|
+
def to_object_field
|
126
|
+
"field :#{@name}, #{@type_expr}#{@null ? '' : ', null: false'}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_input_argument
|
130
|
+
"argument :#{@name}, #{@type_expr}, required: false"
|
94
131
|
end
|
95
132
|
end
|
96
133
|
end
|
@@ -19,14 +19,14 @@ module Graphql
|
|
19
19
|
banner: "type type ...",
|
20
20
|
desc: "Possible types for this union (expressed as Ruby or GraphQL)"
|
21
21
|
|
22
|
-
def create_type_file
|
23
|
-
template "union.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
|
24
|
-
end
|
25
|
-
|
26
22
|
private
|
27
23
|
|
24
|
+
def graphql_type
|
25
|
+
"union"
|
26
|
+
end
|
27
|
+
|
28
28
|
def normalized_possible_types
|
29
|
-
|
29
|
+
custom_fields.map { |t| self.class.normalize_type_expression(t, mode: :ruby)[0] }
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -100,7 +100,8 @@ module GraphQL
|
|
100
100
|
def on_field(node, parent)
|
101
101
|
@response_path.push(node.alias || node.name)
|
102
102
|
parent_type = @object_types.last
|
103
|
-
|
103
|
+
# This could be nil if the previous field wasn't found:
|
104
|
+
field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context)
|
104
105
|
@field_definitions.push(field_definition)
|
105
106
|
if !field_definition.nil?
|
106
107
|
next_object_type = field_definition.type.unwrap
|
@@ -138,8 +138,8 @@ module GraphQL
|
|
138
138
|
# @api private
|
139
139
|
def result_for(key)
|
140
140
|
if !@results.key?(key)
|
141
|
-
raise <<-ERR
|
142
|
-
|
141
|
+
raise GraphQL::InvariantError, <<-ERR
|
142
|
+
Fetching result for a key on #{self.class} that hasn't been loaded yet (#{key.inspect}, loaded: #{@results.keys})
|
143
143
|
|
144
144
|
This key should have been loaded already. This is a bug in GraphQL::Dataloader, please report it on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/new.
|
145
145
|
ERR
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
# This error is raised when `Types::ISO8601Date` is asked to return a value
|
4
|
+
# that cannot be parsed to a Ruby Date.
|
5
|
+
#
|
6
|
+
# @see GraphQL::Types::ISO8601Date which raises this error
|
7
|
+
class DateEncodingError < GraphQL::RuntimeTypeError
|
8
|
+
# The value which couldn't be encoded
|
9
|
+
attr_reader :date_value
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@date_value = value
|
13
|
+
super("Date cannot be parsed: #{value}. \nDate must be be able to be parsed as a Ruby Date object.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -31,8 +31,10 @@ module GraphQL
|
|
31
31
|
# If any jobs were enqueued, run them now,
|
32
32
|
# since this might have been called outside of execution.
|
33
33
|
# (The jobs are responsible for updating `result` in-place.)
|
34
|
-
|
35
|
-
@
|
34
|
+
if !@storage.key?(ast_node) || !@storage[ast_node].key?(argument_owner)
|
35
|
+
@dataloader.run_isolated do
|
36
|
+
@storage[ast_node][argument_owner][parent_object]
|
37
|
+
end
|
36
38
|
end
|
37
39
|
# Ack, the _hash_ is updated, but the key is eventually
|
38
40
|
# overridden with an immutable arguments instance.
|
@@ -159,7 +159,8 @@ module GraphQL
|
|
159
159
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
160
160
|
@runtime_directive_names = []
|
161
161
|
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
|
162
|
-
schema.directives
|
162
|
+
@schema_directives = schema.directives
|
163
|
+
@schema_directives.each do |name, dir_defn|
|
163
164
|
if dir_defn.method(:resolve).owner != noop_resolve_owner
|
164
165
|
@runtime_directive_names << name
|
165
166
|
end
|
@@ -206,7 +207,7 @@ module GraphQL
|
|
206
207
|
# Root .authorized? returned false.
|
207
208
|
@response = nil
|
208
209
|
else
|
209
|
-
|
210
|
+
call_method_on_directives(:resolve, object_proxy, root_operation.directives) do # execute query level directives
|
210
211
|
gathered_selections = gather_selections(object_proxy, root_type, root_operation.selections)
|
211
212
|
# This is kind of a hack -- `gathered_selections` is an Array if any of the selections
|
212
213
|
# require isolation during execution (because of runtime directives). In that case,
|
@@ -226,7 +227,7 @@ module GraphQL
|
|
226
227
|
|
227
228
|
@dataloader.append_job {
|
228
229
|
set_all_interpreter_context(query.root_value, nil, nil, path)
|
229
|
-
|
230
|
+
call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
|
230
231
|
evaluate_selections(
|
231
232
|
path,
|
232
233
|
context.scoped_context,
|
@@ -502,7 +503,7 @@ module GraphQL
|
|
502
503
|
}
|
503
504
|
end
|
504
505
|
|
505
|
-
field_result =
|
506
|
+
field_result = call_method_on_directives(:resolve, object, directives) do
|
506
507
|
# Actually call the field resolver and capture the result
|
507
508
|
app_result = begin
|
508
509
|
query.with_error_handling do
|
@@ -734,7 +735,7 @@ module GraphQL
|
|
734
735
|
final_result = nil
|
735
736
|
end
|
736
737
|
set_all_interpreter_context(continue_value, nil, nil, path) # reset this mutable state
|
737
|
-
|
738
|
+
call_method_on_directives(:resolve, continue_value, selections.graphql_directives) do
|
738
739
|
evaluate_selections(
|
739
740
|
path,
|
740
741
|
context.scoped_context,
|
@@ -753,6 +754,8 @@ module GraphQL
|
|
753
754
|
end
|
754
755
|
when "LIST"
|
755
756
|
inner_type = current_type.of_type
|
757
|
+
# This is true for objects, unions, and interfaces
|
758
|
+
use_dataloader_job = !inner_type.unwrap.kind.input?
|
756
759
|
response_list = GraphQLResultArray.new(result_name, selection_result)
|
757
760
|
response_list.graphql_non_null_list_items = inner_type.non_null?
|
758
761
|
set_result(selection_result, result_name, response_list)
|
@@ -767,12 +770,12 @@ module GraphQL
|
|
767
770
|
this_idx = idx
|
768
771
|
next_path.freeze
|
769
772
|
idx += 1
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
if HALT != continue_value
|
774
|
-
continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
|
773
|
+
if use_dataloader_job
|
774
|
+
@dataloader.append_job do
|
775
|
+
resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
775
776
|
end
|
777
|
+
else
|
778
|
+
resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
776
779
|
end
|
777
780
|
end
|
778
781
|
rescue NoMethodError => err
|
@@ -792,17 +795,30 @@ module GraphQL
|
|
792
795
|
end
|
793
796
|
end
|
794
797
|
|
795
|
-
def
|
798
|
+
def resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
|
799
|
+
set_all_interpreter_context(nil, nil, nil, next_path)
|
800
|
+
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
801
|
+
# This will update `response_list` with the lazy
|
802
|
+
after_lazy(inner_value, owner: inner_type, path: next_path, ast_node: ast_node, scoped_context: scoped_context, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
|
803
|
+
continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
|
804
|
+
if HALT != continue_value
|
805
|
+
continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
811
|
+
def call_method_on_directives(method_name, object, directives, &block)
|
796
812
|
return yield if directives.nil? || directives.empty?
|
797
|
-
run_directive(object, directives, 0, &block)
|
813
|
+
run_directive(method_name, object, directives, 0, &block)
|
798
814
|
end
|
799
815
|
|
800
|
-
def run_directive(object, directives, idx, &block)
|
816
|
+
def run_directive(method_name, object, directives, idx, &block)
|
801
817
|
dir_node = directives[idx]
|
802
818
|
if !dir_node
|
803
819
|
yield
|
804
820
|
else
|
805
|
-
dir_defn =
|
821
|
+
dir_defn = @schema_directives.fetch(dir_node.name)
|
806
822
|
if !dir_defn.is_a?(Class)
|
807
823
|
dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
|
808
824
|
end
|
@@ -821,8 +837,8 @@ module GraphQL
|
|
821
837
|
if dir_args == HALT
|
822
838
|
nil
|
823
839
|
else
|
824
|
-
dir_defn.
|
825
|
-
run_directive(object, directives, idx + 1, &block)
|
840
|
+
dir_defn.public_send(method_name, object, dir_args, context) do
|
841
|
+
run_directive(method_name, object, directives, idx + 1, &block)
|
826
842
|
end
|
827
843
|
end
|
828
844
|
end
|
@@ -831,7 +847,7 @@ module GraphQL
|
|
831
847
|
# Check {Schema::Directive.include?} for each directive that's present
|
832
848
|
def directives_include?(node, graphql_object, parent_type)
|
833
849
|
node.directives.each do |dir_node|
|
834
|
-
dir_defn =
|
850
|
+
dir_defn = @schema_directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
|
835
851
|
args = arguments(graphql_object, dir_defn, dir_node)
|
836
852
|
if !dir_defn.include?(graphql_object, args, context)
|
837
853
|
return false
|
@@ -6,8 +6,8 @@ module GraphQL
|
|
6
6
|
description "A Directive can be adjacent to many parts of the GraphQL language, "\
|
7
7
|
"a __DirectiveLocation describes one such possible adjacencies."
|
8
8
|
|
9
|
-
GraphQL::Directive::LOCATIONS.each do |location|
|
10
|
-
value(location.to_s, GraphQL::Directive::LOCATION_DESCRIPTIONS[location], value: location)
|
9
|
+
GraphQL::Schema::Directive::LOCATIONS.each do |location|
|
10
|
+
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
|
11
11
|
end
|
12
12
|
introspection true
|
13
13
|
end
|
@@ -19,6 +19,8 @@ module GraphQL
|
|
19
19
|
field :on_fragment, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_fragment?
|
20
20
|
field :on_field, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_field?
|
21
21
|
|
22
|
+
field :is_repeatable, Boolean, method: :repeatable?
|
23
|
+
|
22
24
|
def args(include_deprecated:)
|
23
25
|
args = @context.warden.arguments(@object)
|
24
26
|
args = args.reject(&:deprecation_reason) unless include_deprecated
|
@@ -13,6 +13,11 @@ module GraphQL
|
|
13
13
|
field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
|
14
14
|
field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
|
15
15
|
field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
|
16
|
+
field :description, String, resolver_method: :schema_description
|
17
|
+
|
18
|
+
def schema_description
|
19
|
+
context.schema.description
|
20
|
+
end
|
16
21
|
|
17
22
|
def types
|
18
23
|
@context.warden.reachable_types.sort_by(&:graphql_name)
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
"possible at runtime. List and NonNull types compose other types."
|
13
13
|
|
14
14
|
field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
|
15
|
-
field :name, String
|
15
|
+
field :name, String, method: :graphql_name
|
16
16
|
field :description, String
|
17
17
|
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
|
18
18
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
@@ -27,8 +27,14 @@ module GraphQL
|
|
27
27
|
end
|
28
28
|
field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
field :specified_by_url, String
|
31
|
+
|
32
|
+
def specified_by_url
|
33
|
+
if object.kind.scalar?
|
34
|
+
object.specified_by_url
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
32
38
|
end
|
33
39
|
|
34
40
|
def kind
|
@@ -7,6 +7,7 @@ module GraphQL
|
|
7
7
|
<<-QUERY
|
8
8
|
query IntrospectionQuery {
|
9
9
|
__schema {
|
10
|
+
description
|
10
11
|
queryType { name }
|
11
12
|
mutationType { name }
|
12
13
|
subscriptionType { name }
|
@@ -17,6 +18,7 @@ query IntrospectionQuery {
|
|
17
18
|
name
|
18
19
|
description
|
19
20
|
locations
|
21
|
+
isRepeatable
|
20
22
|
args#{include_deprecated_args ? '(includeDeprecated: true)' : ''} {
|
21
23
|
...InputValue
|
22
24
|
}
|
@@ -27,6 +29,7 @@ fragment FullType on __Type {
|
|
27
29
|
kind
|
28
30
|
name
|
29
31
|
description
|
32
|
+
specifiedByUrl
|
30
33
|
fields(includeDeprecated: true) {
|
31
34
|
name
|
32
35
|
description
|
@@ -152,6 +152,7 @@ module GraphQL
|
|
152
152
|
def build_directive_node(directive)
|
153
153
|
GraphQL::Language::Nodes::DirectiveDefinition.new(
|
154
154
|
name: directive.graphql_name,
|
155
|
+
repeatable: directive.repeatable?,
|
155
156
|
arguments: build_argument_nodes(warden.arguments(directive)),
|
156
157
|
locations: build_directive_location_nodes(directive.locations),
|
157
158
|
description: directive.description,
|