graphql 1.8.0.pre7 → 1.8.0.pre8

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/argument.rb +24 -19
  3. data/lib/graphql/backtrace/tracer.rb +16 -22
  4. data/lib/graphql/base_type.rb +6 -1
  5. data/lib/graphql/execution/execute.rb +15 -13
  6. data/lib/graphql/execution/lazy/resolve.rb +1 -3
  7. data/lib/graphql/interface_type.rb +5 -3
  8. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  9. data/lib/graphql/language/lexer.rb +65 -51
  10. data/lib/graphql/language/lexer.rl +2 -0
  11. data/lib/graphql/language/nodes.rb +118 -71
  12. data/lib/graphql/language/parser.rb +699 -652
  13. data/lib/graphql/language/parser.y +11 -5
  14. data/lib/graphql/language/printer.rb +2 -2
  15. data/lib/graphql/object_type.rb +0 -5
  16. data/lib/graphql/relay/relation_connection.rb +1 -1
  17. data/lib/graphql/schema.rb +15 -3
  18. data/lib/graphql/schema/argument.rb +18 -1
  19. data/lib/graphql/schema/enum.rb +5 -2
  20. data/lib/graphql/schema/enum_value.rb +8 -1
  21. data/lib/graphql/schema/field.rb +10 -3
  22. data/lib/graphql/schema/input_object.rb +4 -2
  23. data/lib/graphql/schema/interface.rb +15 -0
  24. data/lib/graphql/schema/member.rb +2 -1
  25. data/lib/graphql/schema/member/accepts_definition.rb +118 -0
  26. data/lib/graphql/schema/member/build_type.rb +2 -2
  27. data/lib/graphql/schema/member/has_fields.rb +3 -2
  28. data/lib/graphql/schema/object.rb +4 -2
  29. data/lib/graphql/schema/scalar.rb +2 -0
  30. data/lib/graphql/schema/traversal.rb +3 -0
  31. data/lib/graphql/schema/union.rb +6 -11
  32. data/lib/graphql/version.rb +1 -1
  33. data/spec/graphql/argument_spec.rb +21 -0
  34. data/spec/graphql/base_type_spec.rb +22 -0
  35. data/spec/graphql/enum_type_spec.rb +18 -5
  36. data/spec/graphql/execution/execute_spec.rb +3 -3
  37. data/spec/graphql/input_object_type_spec.rb +13 -0
  38. data/spec/graphql/interface_type_spec.rb +12 -0
  39. data/spec/graphql/language/nodes_spec.rb +0 -12
  40. data/spec/graphql/language/parser_spec.rb +74 -0
  41. data/spec/graphql/language/printer_spec.rb +1 -1
  42. data/spec/graphql/object_type_spec.rb +21 -0
  43. data/spec/graphql/relay/range_add_spec.rb +5 -1
  44. data/spec/graphql/relay/relation_connection_spec.rb +7 -1
  45. data/spec/graphql/schema/argument_spec.rb +31 -0
  46. data/spec/graphql/schema/enum_spec.rb +5 -0
  47. data/spec/graphql/schema/field_spec.rb +11 -1
  48. data/spec/graphql/schema/input_object_spec.rb +5 -0
  49. data/spec/graphql/schema/interface_spec.rb +29 -0
  50. data/spec/graphql/schema/member/accepts_definition_spec.rb +62 -0
  51. data/spec/graphql/schema/printer_spec.rb +34 -0
  52. data/spec/graphql/schema/traversal_spec.rb +31 -0
  53. data/spec/graphql/schema/union_spec.rb +30 -0
  54. data/spec/graphql/schema_spec.rb +6 -0
  55. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  56. data/spec/graphql/tracing/active_support_notifications_tracing_spec.rb +1 -1
  57. data/spec/graphql/union_type_spec.rb +1 -1
  58. data/spec/spec_helper.rb +1 -0
  59. data/spec/support/dummy/schema.rb +1 -4
  60. metadata +7 -2
@@ -152,10 +152,6 @@ rule
152
152
  | operation_type
153
153
  | schema_keyword
154
154
 
155
- name_list:
156
- name { return [make_node(:TypeName, name: val[0])] }
157
- | name_list name { val[0] << make_node(:TypeName, name: val[1]) }
158
-
159
155
  enum_value_definition:
160
156
  enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0])) }
161
157
 
@@ -306,7 +302,17 @@ rule
306
302
 
307
303
  implements_opt:
308
304
  /* none */ { return [] }
309
- | IMPLEMENTS name_list { return val[1] }
305
+ | IMPLEMENTS AMP interfaces_list { return val[2] }
306
+ | IMPLEMENTS interfaces_list { return val[1] }
307
+ | IMPLEMENTS legacy_interfaces_list { return val[1] }
308
+
309
+ interfaces_list:
310
+ name { return [make_node(:TypeName, name: val[0])] }
311
+ | interfaces_list AMP name { val[0] << make_node(:TypeName, name: val[2]) }
312
+
313
+ legacy_interfaces_list:
314
+ name { return [make_node(:TypeName, name: val[0])] }
315
+ | legacy_interfaces_list name { val[0] << make_node(:TypeName, name: val[1]) }
310
316
 
311
317
  input_value_definition:
312
318
  name COLON type default_value_opt directives_list_opt {
@@ -154,7 +154,7 @@ module GraphQL
154
154
  def print_object_type_definition(object_type)
155
155
  out = print_description(object_type)
156
156
  out << "type #{object_type.name}"
157
- out << " implements " << object_type.interfaces.map(&:name).join(", ") unless object_type.interfaces.empty?
157
+ out << " implements " << object_type.interfaces.map(&:name).join(" & ") unless object_type.interfaces.empty?
158
158
  out << print_directives(object_type.directives)
159
159
  out << print_field_definitions(object_type.fields)
160
160
  end
@@ -339,7 +339,7 @@ module GraphQL
339
339
  when Hash
340
340
  "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
341
341
  else
342
- raise TypeError
342
+ GraphQL::Language.serialize(node.to_s)
343
343
  end
344
344
  end
345
345
 
@@ -102,11 +102,6 @@ module GraphQL
102
102
  dirty_ifaces.concat(interfaces)
103
103
  end
104
104
 
105
- def name=(name)
106
- GraphQL::NameValidator.validate!(name)
107
- @name = name
108
- end
109
-
110
105
  protected
111
106
 
112
107
  attr_reader :dirty_interfaces, :dirty_inherited_interfaces
@@ -27,7 +27,7 @@ module GraphQL
27
27
  if first
28
28
  paged_nodes.length >= first && sliced_nodes_count > first
29
29
  elsif GraphQL::Relay::ConnectionType.bidirectional_pagination && last
30
- sliced_nodes_count > last
30
+ sliced_nodes_count >= last
31
31
  else
32
32
  false
33
33
  end
@@ -64,6 +64,7 @@ module GraphQL
64
64
  # end
65
65
  #
66
66
  class Schema
67
+ extend GraphQL::Schema::Member::AcceptsDefinition
67
68
  include GraphQL::Define::InstanceDefinable
68
69
  accepts_definitions \
69
70
  :query, :mutation, :subscription,
@@ -197,6 +198,9 @@ module GraphQL
197
198
  rescue_middleware.remove_handler(*args, &block)
198
199
  end
199
200
 
201
+ # For forwards-compatibility with Schema classes
202
+ alias :graphql_definition :itself
203
+
200
204
  # Validate a query string according to this schema.
201
205
  # @param string_or_document [String, GraphQL::Language::Nodes::Document]
202
206
  # @return [Array<GraphQL::StaticValidation::Message>]
@@ -681,6 +685,7 @@ module GraphQL
681
685
  schema_defn.id_from_object = method(:id_from_object)
682
686
  schema_defn.type_error = method(:type_error)
683
687
  schema_defn.context_class = context_class
688
+ schema_defn.cursor_encoder = cursor_encoder
684
689
  schema_defn.tracers.concat(defined_tracers)
685
690
  schema_defn.query_analyzers.concat(defined_query_analyzers)
686
691
  schema_defn.multiplex_analyzers.concat(defined_multiplex_analyzers)
@@ -749,6 +754,13 @@ module GraphQL
749
754
  end
750
755
  end
751
756
 
757
+ def cursor_encoder(new_encoder = nil)
758
+ if new_encoder
759
+ @cursor_encoder = new_encoder
760
+ end
761
+ @cursor_encoder || Base64Encoder
762
+ end
763
+
752
764
  def default_max_page_size(new_default_max_page_size = nil)
753
765
  if new_default_max_page_size
754
766
  @default_max_page_size = new_default_max_page_size
@@ -773,9 +785,9 @@ module GraphQL
773
785
  end
774
786
  end
775
787
 
776
- def orphan_types(new_orphan_types = nil)
777
- if new_orphan_types
778
- @orphan_types = new_orphan_types
788
+ def orphan_types(*new_orphan_types)
789
+ if new_orphan_types.any?
790
+ @orphan_types = new_orphan_types.flatten
779
791
  else
780
792
  @orphan_types || []
781
793
  end
@@ -3,11 +3,15 @@ module GraphQL
3
3
  class Schema
4
4
  class Argument
5
5
  include GraphQL::Schema::Member::CachedGraphQLDefinition
6
+ include GraphQL::Schema::Member::AcceptsDefinition
6
7
 
7
8
  NO_DEFAULT = :__no_default__
8
9
 
9
10
  attr_reader :name
10
11
 
12
+ # @return [GraphQL::Schema::Field, Class] The field or input object this argument belongs to
13
+ attr_reader :owner
14
+
11
15
  # @param arg_name [Symbol]
12
16
  # @param type_expr
13
17
  # @param desc [String]
@@ -15,13 +19,26 @@ module GraphQL
15
19
  # @param description [String]
16
20
  # @param default_value [Object]
17
21
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
18
- def initialize(arg_name, type_expr, desc = nil, required:, description: nil, default_value: NO_DEFAULT, camelize: true)
22
+ def initialize(arg_name, type_expr, desc = nil, required:, description: nil, default_value: NO_DEFAULT, camelize: true, owner:, &definition_block)
19
23
  @name = arg_name.to_s
20
24
  @type_expr = type_expr
21
25
  @description = desc || description
22
26
  @null = !required
23
27
  @default_value = default_value
24
28
  @camelize = camelize
29
+ @owner = owner
30
+
31
+ if definition_block
32
+ instance_eval(&definition_block)
33
+ end
34
+ end
35
+
36
+ def description(text = nil)
37
+ if text
38
+ @description = text
39
+ else
40
+ @description
41
+ end
25
42
  end
26
43
 
27
44
  def to_graphql
@@ -20,6 +20,8 @@ module GraphQL
20
20
  # end
21
21
  class Schema
22
22
  class Enum < GraphQL::Schema::Member
23
+ extend GraphQL::Schema::Member::AcceptsDefinition
24
+
23
25
  class << self
24
26
  # Define a value for this enum
25
27
  # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
@@ -28,8 +30,9 @@ module GraphQL
28
30
  # @param deprecation_reason [String] if this object is deprecated, include a message here
29
31
  # @return [void]
30
32
  # @see {Schema::EnumValue} which handles these inputs by default
31
- def value(*args, &block)
32
- value = enum_value_class.new(*args, &block)
33
+ def value(*args, **kwargs, &block)
34
+ kwargs[:owner] = self
35
+ value = enum_value_class.new(*args, **kwargs, &block)
33
36
  own_values[value.graphql_name] = value
34
37
  nil
35
38
  end
@@ -26,13 +26,20 @@ module GraphQL
26
26
  # enum_value_class CustomEnumValue
27
27
  # end
28
28
  class EnumValue < GraphQL::Schema::Member
29
+ include GraphQL::Schema::Member::AcceptsDefinition
30
+
29
31
  attr_reader :graphql_name
30
32
 
31
- def initialize(graphql_name, desc = nil, description: nil, value: nil, deprecation_reason: nil, &block)
33
+ # @return [Class] The enum type that owns this value
34
+ attr_reader :owner
35
+
36
+ def initialize(graphql_name, desc = nil, owner:, description: nil, value: nil, deprecation_reason: nil, &block)
32
37
  @graphql_name = graphql_name.to_s
33
38
  @description = desc || description
34
39
  @value = value || @graphql_name
35
40
  @deprecation_reason = deprecation_reason
41
+ @owner = owner
42
+
36
43
  if block_given?
37
44
  instance_eval(&block)
38
45
  end
@@ -6,6 +6,7 @@ module GraphQL
6
6
  class Schema
7
7
  class Field
8
8
  include GraphQL::Schema::Member::CachedGraphQLDefinition
9
+ include GraphQL::Schema::Member::AcceptsDefinition
9
10
 
10
11
  # @return [String]
11
12
  attr_reader :name
@@ -19,9 +20,13 @@ module GraphQL
19
20
  # @return [Symbol]
20
21
  attr_reader :method
21
22
 
23
+ # @return [Class] The type that this field belongs to
24
+ attr_reader :owner
25
+
22
26
  # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
23
27
  # @param return_type_expr [Class, GraphQL::BaseType, Array] The return type of this field
24
28
  # @param desc [String] Field description
29
+ # @param owner [Class] The type that this field belongs to
25
30
  # @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
26
31
  # @param description [String] Field description
27
32
  # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
@@ -35,7 +40,7 @@ module GraphQL
35
40
  # @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
36
41
  # @param camelize [Boolean] If true, the field name will be camelized when building the schema
37
42
  # @param complexity [Numeric] When provided, set the complexity for this field
38
- def initialize(name, return_type_expr = nil, desc = nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, connection: nil, max_page_size: nil, resolve: nil, introspection: false, hash_key: nil, camelize: true, complexity: 1, extras: [], &definition_block)
43
+ def initialize(name, return_type_expr = nil, desc = nil, owner:, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, connection: nil, max_page_size: nil, resolve: nil, introspection: false, hash_key: nil, camelize: true, complexity: 1, extras: [], &definition_block)
39
44
  if (field || function) && desc.nil? && return_type_expr.is_a?(String)
40
45
  # The return type should be copied from `field` or `function`, and the second positional argument is the description
41
46
  desc = return_type_expr
@@ -75,6 +80,7 @@ module GraphQL
75
80
  @extras = extras
76
81
  @arguments = {}
77
82
  @camelize = camelize
83
+ @owner = owner
78
84
 
79
85
  if definition_block
80
86
  instance_eval(&definition_block)
@@ -82,8 +88,9 @@ module GraphQL
82
88
  end
83
89
 
84
90
  # This is the `argument(...)` DSL for class-based field definitons
85
- def argument(*args)
86
- arg_defn = self.class.argument_class.new(*args)
91
+ def argument(*args, **kwargs, &block)
92
+ kwargs[:owner] = self
93
+ arg_defn = self.class.argument_class.new(*args, **kwargs, &block)
87
94
  arguments[arg_defn.name] = arg_defn
88
95
  end
89
96
 
@@ -2,6 +2,7 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  class InputObject < GraphQL::Schema::Member
5
+ extend GraphQL::Schema::Member::AcceptsDefinition
5
6
  extend GraphQL::Delegate
6
7
 
7
8
  def initialize(values, context:, defaults_used:)
@@ -23,8 +24,9 @@ module GraphQL
23
24
  # @return [Class<GraphQL::Arguments>]
24
25
  attr_accessor :arguments_class
25
26
 
26
- def argument(*args)
27
- argument = GraphQL::Schema::Argument.new(*args)
27
+ def argument(*args, **kwargs)
28
+ kwargs[:owner] = self
29
+ argument = GraphQL::Schema::Argument.new(*args, **kwargs)
28
30
  arg_name = argument.graphql_definition.name
29
31
  own_arguments[arg_name] = argument
30
32
  # Add a method access
@@ -3,6 +3,7 @@ module GraphQL
3
3
  class Schema
4
4
  class Interface < GraphQL::Schema::Member
5
5
  extend GraphQL::Schema::Member::HasFields
6
+ extend GraphQL::Schema::Member::AcceptsDefinition
6
7
  field_class GraphQL::Schema::Field
7
8
 
8
9
  class << self
@@ -15,14 +16,28 @@ module GraphQL
15
16
  end
16
17
  end
17
18
 
19
+ def orphan_types(*types)
20
+ if types.any?
21
+ @orphan_types = types
22
+ else
23
+ all_orphan_types = @orphan_types || []
24
+ all_orphan_types += super if defined?(super)
25
+ all_orphan_types.uniq
26
+ end
27
+ end
28
+
18
29
  def to_graphql
19
30
  type_defn = GraphQL::InterfaceType.new
20
31
  type_defn.name = graphql_name
21
32
  type_defn.description = description
33
+ type_defn.orphan_types = orphan_types
22
34
  fields.each do |field_name, field_inst|
23
35
  field_defn = field_inst.graphql_definition
24
36
  type_defn.fields[field_defn.name] = field_defn
25
37
  end
38
+ if respond_to?(:resolve_type)
39
+ type_defn.resolve_type = method(:resolve_type)
40
+ end
26
41
  type_defn
27
42
  end
28
43
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'graphql/schema/member/accepts_definition'
2
3
  require "graphql/relay/type_extensions"
3
4
 
4
5
  module GraphQL
@@ -27,7 +28,7 @@ module GraphQL
27
28
  # These constants are interpreted as GraphQL types
28
29
  #
29
30
  # @example
30
- # field :isDraft, Boolean, null: false
31
+ # field :is_draft, Boolean, null: false
31
32
  # field :id, ID, null: false
32
33
  # field :score, Int, null: false
33
34
  module GraphQLTypeNames
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ # Support for legacy `accepts_definitions` functions.
7
+ #
8
+ # Keep the legacy handler hooked up. Class-based types and fields
9
+ # will call those legacy handlers during their `.to_graphql`
10
+ # methods.
11
+ #
12
+ # This can help out while transitioning from one to the other.
13
+ # Eventually, `GraphQL::{X}Type` objects will be removed entirely,
14
+ # But this can help during the transition.
15
+ #
16
+ # @example Applying a function to base object class
17
+ # # Here's the legacy-style config, which we're calling back to:
18
+ # GraphQL::ObjectType.accepts_definition({
19
+ # permission_level: ->(defn, value) { defn.metadata[:permission_level] = value }
20
+ # })
21
+ #
22
+ # class BaseObject < GraphQL::Schema::Object
23
+ # # Setup a named pass-through to the legacy config functions
24
+ # accepts_definition :permission_level
25
+ # end
26
+ #
27
+ # class Account < BaseObject
28
+ # # This value will be passed to the legacy handler:
29
+ # permission_level 1
30
+ # end
31
+ #
32
+ # # The class gets a reader method which returns the args,
33
+ # # only marginally useful.
34
+ # Account.permission_level # => [1]
35
+ #
36
+ # # The legacy handler is called, as before:
37
+ # Account.graphql_definition.metadata[:permission_level] # => 1
38
+ module AcceptsDefinition
39
+ def self.included(child)
40
+ child.extend(ClassMethods)
41
+ child.prepend(ToGraphQLExtension)
42
+ child.prepend(InitializeExtension)
43
+ end
44
+
45
+ def self.extended(child)
46
+ child.extend(ClassMethods)
47
+ # I tried to use `super`, but super isn't quite right
48
+ # since the method is defined in the same class itself,
49
+ # not the superclass
50
+ child.class_eval do
51
+ class << self
52
+ prepend(ToGraphQLExtension)
53
+ end
54
+ end
55
+ end
56
+
57
+ module ClassMethods
58
+ def accepts_definition(name)
59
+ @accepts_definition_methods ||= []
60
+ @accepts_definition_methods << name
61
+ ivar_name = "@#{name}_args"
62
+ define_singleton_method(name) do |*args|
63
+ if args.any?
64
+ instance_variable_set(ivar_name, args)
65
+ end
66
+ instance_variable_get(ivar_name)
67
+ end
68
+
69
+ define_method(name) do |*args|
70
+ if args.any?
71
+ instance_variable_set(ivar_name, args)
72
+ end
73
+ instance_variable_get(ivar_name)
74
+ end
75
+ end
76
+
77
+ def accepts_definition_methods
78
+ @accepts_definition_methods ||= []
79
+ sc = self.is_a?(Class) ? superclass : self.class.superclass
80
+ @accepts_definition_methods + (sc.respond_to?(:accepts_definition_methods) ? sc.accepts_definition_methods : [])
81
+ end
82
+ end
83
+
84
+ module ToGraphQLExtension
85
+ def to_graphql
86
+ defn = super
87
+ accepts_definition_methods.each do |method_name|
88
+ value = instance_variable_get("@#{method_name}_args")
89
+ if !value.nil?
90
+ defn = defn.redefine { public_send(method_name, *value) }
91
+ end
92
+ end
93
+ defn
94
+ end
95
+ end
96
+
97
+ module InitializeExtension
98
+ def initialize(*args, **kwargs, &block)
99
+ self.class.accepts_definition_methods.each do |method_name|
100
+ if kwargs.key?(method_name)
101
+ value = kwargs.delete(method_name)
102
+ if !value.is_a?(Array)
103
+ value = [value]
104
+ end
105
+ instance_variable_set("@#{method_name}_args", value)
106
+ end
107
+ end
108
+ super(*args, **kwargs, &block)
109
+ end
110
+
111
+ def accepts_definition_methods
112
+ self.class.accepts_definition_methods
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end