graphql 1.11.4 → 1.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +5 -5
  3. data/lib/generators/graphql/object_generator.rb +2 -0
  4. data/lib/generators/graphql/relay_generator.rb +63 -0
  5. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  6. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  7. data/lib/generators/graphql/templates/node_type.erb +9 -0
  8. data/lib/generators/graphql/templates/object.erb +1 -1
  9. data/lib/generators/graphql/templates/query_type.erb +1 -3
  10. data/lib/generators/graphql/templates/schema.erb +8 -35
  11. data/lib/generators/graphql/templates/union.erb +1 -1
  12. data/lib/graphql.rb +55 -4
  13. data/lib/graphql/analysis/analyze_query.rb +7 -0
  14. data/lib/graphql/analysis/ast.rb +11 -2
  15. data/lib/graphql/analysis/ast/visitor.rb +9 -1
  16. data/lib/graphql/argument.rb +3 -3
  17. data/lib/graphql/backtrace.rb +28 -19
  18. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  19. data/lib/graphql/backtrace/table.rb +22 -2
  20. data/lib/graphql/backtrace/tracer.rb +40 -8
  21. data/lib/graphql/backwards_compatibility.rb +1 -0
  22. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  23. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  24. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  25. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  26. data/lib/graphql/dataloader.rb +198 -0
  27. data/lib/graphql/dataloader/null_dataloader.rb +21 -0
  28. data/lib/graphql/dataloader/request.rb +24 -0
  29. data/lib/graphql/dataloader/request_all.rb +22 -0
  30. data/lib/graphql/dataloader/source.rb +93 -0
  31. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  32. data/lib/graphql/define/instance_definable.rb +32 -2
  33. data/lib/graphql/define/type_definer.rb +5 -5
  34. data/lib/graphql/deprecated_dsl.rb +5 -0
  35. data/lib/graphql/enum_type.rb +2 -0
  36. data/lib/graphql/execution/errors.rb +4 -0
  37. data/lib/graphql/execution/execute.rb +7 -0
  38. data/lib/graphql/execution/interpreter.rb +20 -6
  39. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  40. data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
  41. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  42. data/lib/graphql/execution/interpreter/runtime.rb +236 -120
  43. data/lib/graphql/execution/multiplex.rb +20 -6
  44. data/lib/graphql/function.rb +4 -0
  45. data/lib/graphql/input_object_type.rb +2 -0
  46. data/lib/graphql/integer_decoding_error.rb +17 -0
  47. data/lib/graphql/interface_type.rb +3 -1
  48. data/lib/graphql/introspection.rb +96 -0
  49. data/lib/graphql/introspection/field_type.rb +7 -3
  50. data/lib/graphql/introspection/input_value_type.rb +6 -0
  51. data/lib/graphql/introspection/introspection_query.rb +6 -92
  52. data/lib/graphql/introspection/type_type.rb +7 -3
  53. data/lib/graphql/invalid_null_error.rb +1 -1
  54. data/lib/graphql/language/block_string.rb +24 -5
  55. data/lib/graphql/language/document_from_schema_definition.rb +50 -23
  56. data/lib/graphql/language/lexer.rb +7 -3
  57. data/lib/graphql/language/lexer.rl +7 -3
  58. data/lib/graphql/language/nodes.rb +1 -1
  59. data/lib/graphql/language/parser.rb +107 -103
  60. data/lib/graphql/language/parser.y +4 -0
  61. data/lib/graphql/language/sanitized_printer.rb +59 -26
  62. data/lib/graphql/name_validator.rb +6 -7
  63. data/lib/graphql/object_type.rb +2 -0
  64. data/lib/graphql/pagination/connection.rb +5 -1
  65. data/lib/graphql/pagination/connections.rb +15 -17
  66. data/lib/graphql/query.rb +8 -3
  67. data/lib/graphql/query/context.rb +18 -3
  68. data/lib/graphql/query/serial_execution.rb +1 -0
  69. data/lib/graphql/query/validation_pipeline.rb +1 -1
  70. data/lib/graphql/relay/array_connection.rb +2 -2
  71. data/lib/graphql/relay/base_connection.rb +7 -0
  72. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  73. data/lib/graphql/relay/connection_type.rb +1 -1
  74. data/lib/graphql/relay/mutation.rb +1 -0
  75. data/lib/graphql/relay/node.rb +3 -0
  76. data/lib/graphql/relay/range_add.rb +14 -5
  77. data/lib/graphql/relay/type_extensions.rb +2 -0
  78. data/lib/graphql/scalar_type.rb +2 -0
  79. data/lib/graphql/schema.rb +104 -39
  80. data/lib/graphql/schema/argument.rb +74 -5
  81. data/lib/graphql/schema/build_from_definition.rb +203 -86
  82. data/lib/graphql/schema/default_type_error.rb +2 -0
  83. data/lib/graphql/schema/directive.rb +76 -0
  84. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  85. data/lib/graphql/schema/directive/flagged.rb +57 -0
  86. data/lib/graphql/schema/enum.rb +3 -0
  87. data/lib/graphql/schema/enum_value.rb +12 -6
  88. data/lib/graphql/schema/field.rb +59 -24
  89. data/lib/graphql/schema/field/connection_extension.rb +10 -8
  90. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  91. data/lib/graphql/schema/input_object.rb +38 -25
  92. data/lib/graphql/schema/interface.rb +2 -1
  93. data/lib/graphql/schema/late_bound_type.rb +2 -2
  94. data/lib/graphql/schema/loader.rb +1 -0
  95. data/lib/graphql/schema/member.rb +4 -0
  96. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
  97. data/lib/graphql/schema/member/build_type.rb +17 -7
  98. data/lib/graphql/schema/member/has_arguments.rb +70 -51
  99. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  100. data/lib/graphql/schema/member/has_directives.rb +98 -0
  101. data/lib/graphql/schema/member/has_fields.rb +2 -2
  102. data/lib/graphql/schema/member/has_validators.rb +31 -0
  103. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  104. data/lib/graphql/schema/object.rb +11 -0
  105. data/lib/graphql/schema/printer.rb +5 -4
  106. data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
  107. data/lib/graphql/schema/resolver.rb +7 -0
  108. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
  109. data/lib/graphql/schema/subscription.rb +19 -1
  110. data/lib/graphql/schema/timeout.rb +29 -15
  111. data/lib/graphql/schema/timeout_middleware.rb +2 -0
  112. data/lib/graphql/schema/unique_within_type.rb +1 -2
  113. data/lib/graphql/schema/validation.rb +10 -0
  114. data/lib/graphql/schema/validator.rb +163 -0
  115. data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
  116. data/lib/graphql/schema/validator/format_validator.rb +49 -0
  117. data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
  118. data/lib/graphql/schema/validator/length_validator.rb +57 -0
  119. data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
  120. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  121. data/lib/graphql/static_validation.rb +1 -0
  122. data/lib/graphql/static_validation/all_rules.rb +1 -0
  123. data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
  124. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  125. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  126. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  127. data/lib/graphql/static_validation/validator.rb +33 -7
  128. data/lib/graphql/subscriptions.rb +18 -23
  129. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
  130. data/lib/graphql/tracing.rb +2 -2
  131. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  132. data/lib/graphql/tracing/platform_tracing.rb +4 -2
  133. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  134. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  135. data/lib/graphql/types/int.rb +9 -2
  136. data/lib/graphql/types/relay.rb +11 -3
  137. data/lib/graphql/types/relay/base_connection.rb +2 -91
  138. data/lib/graphql/types/relay/base_edge.rb +2 -34
  139. data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
  140. data/lib/graphql/types/relay/default_relay.rb +27 -0
  141. data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
  142. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  143. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  144. data/lib/graphql/types/relay/node.rb +2 -4
  145. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  146. data/lib/graphql/types/relay/node_field.rb +1 -19
  147. data/lib/graphql/types/relay/nodes_field.rb +1 -19
  148. data/lib/graphql/types/relay/page_info.rb +2 -14
  149. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  150. data/lib/graphql/types/string.rb +7 -1
  151. data/lib/graphql/unauthorized_error.rb +1 -1
  152. data/lib/graphql/union_type.rb +2 -0
  153. data/lib/graphql/upgrader/member.rb +1 -0
  154. data/lib/graphql/upgrader/schema.rb +1 -0
  155. data/lib/graphql/version.rb +1 -1
  156. data/readme.md +1 -1
  157. metadata +49 -6
  158. data/lib/graphql/types/relay/base_field.rb +0 -22
  159. data/lib/graphql/types/relay/base_interface.rb +0 -29
  160. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -21,40 +21,8 @@ module GraphQL
21
21
  # end
22
22
  #
23
23
  # @see {Relay::BaseConnection} for connection types
24
- class BaseEdge < Types::Relay::BaseObject
25
- description "An edge in a connection."
26
-
27
- class << self
28
- # Get or set the Object type that this edge wraps.
29
- #
30
- # @param node_type [Class] A `Schema::Object` subclass
31
- # @param null [Boolean]
32
- def node_type(node_type = nil, null: true)
33
- if node_type
34
- @node_type = node_type
35
- # Add a default `node` field
36
- field :node, node_type, null: null, description: "The item at the end of the edge."
37
- end
38
- @node_type
39
- end
40
-
41
- def authorized?(obj, ctx)
42
- true
43
- end
44
-
45
- def accessible?(ctx)
46
- node_type.accessible?(ctx)
47
- end
48
-
49
- def visible?(ctx)
50
- node_type.visible?(ctx)
51
- end
52
- end
53
-
54
-
55
- field :cursor, String,
56
- null: false,
57
- description: "A cursor for use in pagination."
24
+ class BaseEdge < GraphQL::Schema::Object
25
+ include Types::Relay::EdgeBehaviors
58
26
  end
59
27
  end
60
28
  end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module ConnectionBehaviors
7
+ extend Forwardable
8
+ def_delegators :@object, :cursor_from_node, :parent
9
+
10
+ def self.included(child_class)
11
+ child_class.extend(ClassMethods)
12
+ child_class.extend(Relay::DefaultRelay)
13
+ child_class.default_relay(true)
14
+ child_class.node_nullable(true)
15
+ add_page_info_field(child_class)
16
+ end
17
+
18
+ module ClassMethods
19
+ # @return [Class]
20
+ attr_reader :node_type
21
+
22
+ # @return [Class]
23
+ attr_reader :edge_class
24
+
25
+ # Configure this connection to return `edges` and `nodes` based on `edge_type_class`.
26
+ #
27
+ # This method will use the inputs to create:
28
+ # - `edges` field
29
+ # - `nodes` field
30
+ # - description
31
+ #
32
+ # It's called when you subclass this base connection, trying to use the
33
+ # class name to set defaults. You can call it again in the class definition
34
+ # to override the default (or provide a value, if the default lookup failed).
35
+ def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: true, node_nullable: self.node_nullable)
36
+ # Set this connection's graphql name
37
+ node_type_name = node_type.graphql_name
38
+
39
+ @node_type = node_type
40
+ @edge_type = edge_type_class
41
+ @edge_class = edge_class
42
+
43
+ field :edges, [edge_type_class, null: true],
44
+ null: true,
45
+ description: "A list of edges.",
46
+ legacy_edge_class: edge_class, # This is used by the old runtime only, for EdgesInstrumentation
47
+ connection: false
48
+
49
+ define_nodes_field(node_nullable) if nodes_field
50
+
51
+ description("The connection type for #{node_type_name}.")
52
+ end
53
+
54
+ # Filter this list according to the way its node type would scope them
55
+ def scope_items(items, context)
56
+ node_type.scope_items(items, context)
57
+ end
58
+
59
+ # Add the shortcut `nodes` field to this connection and its subclasses
60
+ def nodes_field(node_nullable: self.node_nullable)
61
+ define_nodes_field(node_nullable)
62
+ end
63
+
64
+ def authorized?(obj, ctx)
65
+ true # Let nodes be filtered out
66
+ end
67
+
68
+ def accessible?(ctx)
69
+ node_type.accessible?(ctx)
70
+ end
71
+
72
+ def visible?(ctx)
73
+ node_type.visible?(ctx)
74
+ end
75
+
76
+ # Set the default `node_nullable` for this class and its child classes. (Defaults to `true`.)
77
+ # Use `node_nullable(false)` in your base class to make non-null `node` and `nodes` fields.
78
+ def node_nullable(new_value = nil)
79
+ if new_value.nil?
80
+ @node_nullable || superclass.node_nullable
81
+ else
82
+ @node_nullable ||= new_value
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def define_nodes_field(nullable)
89
+ field :nodes, [@node_type, null: nullable],
90
+ null: nullable,
91
+ description: "A list of nodes.",
92
+ connection: false
93
+ end
94
+ end
95
+
96
+ class << self
97
+ def add_page_info_field(obj_type)
98
+ obj_type.field :page_info, GraphQL::Types::Relay::PageInfo, null: false, description: "Information to aid in pagination."
99
+ end
100
+ end
101
+
102
+ # By default this calls through to the ConnectionWrapper's edge nodes method,
103
+ # but sometimes you need to override it to support the `nodes` field
104
+ def nodes
105
+ @object.edge_nodes
106
+ end
107
+
108
+ def edges
109
+ if @object.is_a?(GraphQL::Pagination::Connection)
110
+ @object.edges
111
+ elsif context.interpreter?
112
+ context.schema.after_lazy(object.edge_nodes) do |nodes|
113
+ nodes.map { |n| self.class.edge_class.new(n, object) }
114
+ end
115
+ else
116
+ # This is done by edges_instrumentation
117
+ @object.edge_nodes
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module DefaultRelay
7
+ def self.extended(child_class)
8
+ child_class.default_relay(true)
9
+ end
10
+
11
+ def default_relay(new_value)
12
+ @default_relay = new_value
13
+ end
14
+
15
+ def default_relay?
16
+ !!@default_relay
17
+ end
18
+
19
+ def to_graphql
20
+ type_defn = super
21
+ type_defn.default_relay = default_relay?
22
+ type_defn
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module EdgeBehaviors
7
+ def self.included(child_class)
8
+ child_class.description("An edge in a connection.")
9
+ child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
10
+ child_class.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ # Get or set the Object type that this edge wraps.
15
+ #
16
+ # @param node_type [Class] A `Schema::Object` subclass
17
+ # @param null [Boolean]
18
+ def node_type(node_type = nil, null: true)
19
+ if node_type
20
+ @node_type = node_type
21
+ # Add a default `node` field
22
+ field :node, node_type, null: null, description: "The item at the end of the edge.", connection: false
23
+ end
24
+ @node_type
25
+ end
26
+
27
+ def authorized?(obj, ctx)
28
+ true
29
+ end
30
+
31
+ def accessible?(ctx)
32
+ node_type.accessible?(ctx)
33
+ end
34
+
35
+ def visible?(ctx)
36
+ node_type.visible?(ctx)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module HasNodeField
7
+ def self.included(child_class)
8
+ child_class.field(**field_options, &field_block)
9
+ end
10
+
11
+ class << self
12
+ def field_options
13
+ {
14
+ name: "node",
15
+ owner: nil,
16
+ type: GraphQL::Types::Relay::Node,
17
+ null: true,
18
+ description: "Fetches an object given its ID.",
19
+ relay_node_field: true,
20
+ }
21
+ end
22
+
23
+ def field_block
24
+ Proc.new {
25
+ argument :id, "ID!", required: true,
26
+ description: "ID of the object."
27
+
28
+ def resolve(obj, args, ctx)
29
+ ctx.schema.object_from_id(args[:id], ctx)
30
+ end
31
+
32
+ def resolve_field(obj, args, ctx)
33
+ resolve(obj, args, ctx)
34
+ end
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module HasNodesField
7
+ def self.included(child_class)
8
+ child_class.field(**field_options, &field_block)
9
+ end
10
+
11
+ class << self
12
+ def field_options
13
+ {
14
+ name: "nodes",
15
+ owner: nil,
16
+ type: [GraphQL::Types::Relay::Node, null: true],
17
+ null: false,
18
+ description: "Fetches a list of objects given a list of IDs.",
19
+ relay_nodes_field: true,
20
+ }
21
+ end
22
+
23
+ def field_block
24
+ Proc.new {
25
+ argument :ids, "[ID!]!", required: true,
26
+ description: "IDs of the objects."
27
+
28
+ def resolve(obj, args, ctx)
29
+ args[:ids].map { |id| ctx.schema.object_from_id(id, ctx) }
30
+ end
31
+
32
+ def resolve_field(obj, args, ctx)
33
+ resolve(obj, args, ctx)
34
+ end
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -7,10 +7,8 @@ module GraphQL
7
7
  # or you can take it as inspiration for your own implementation
8
8
  # of the `Node` interface.
9
9
  module Node
10
- include Types::Relay::BaseInterface
11
- default_relay(true)
12
- description "An object with an ID."
13
- field(:id, ID, null: false, description: "ID of the object.")
10
+ include GraphQL::Schema::Interface
11
+ include Types::Relay::NodeBehaviors
14
12
  end
15
13
  end
16
14
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Types
5
+ module Relay
6
+ module NodeBehaviors
7
+ def self.included(child_module)
8
+ child_module.extend(DefaultRelay)
9
+ child_module.description("An object with an ID.")
10
+ child_module.field(:id, ID, null: false, description: "ID of the object.")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -19,25 +19,7 @@ module GraphQL
19
19
  # context.schema.object_from_id(id, context)
20
20
  # end
21
21
  #
22
- NodeField = GraphQL::Schema::Field.new(
23
- name: "node",
24
- owner: nil,
25
- type: GraphQL::Types::Relay::Node,
26
- null: true,
27
- description: "Fetches an object given its ID.",
28
- relay_node_field: true,
29
- ) do
30
- argument :id, "ID!", required: true,
31
- description: "ID of the object."
32
-
33
- def resolve(obj, args, ctx)
34
- ctx.schema.object_from_id(args[:id], ctx)
35
- end
36
-
37
- def resolve_field(obj, args, ctx)
38
- resolve(obj, args, ctx)
39
- end
40
- end
22
+ NodeField = GraphQL::Schema::Field.new(**HasNodeField.field_options, &HasNodeField.field_block)
41
23
  end
42
24
  end
43
25
  end
@@ -21,25 +21,7 @@ module GraphQL
21
21
  # end
22
22
  # end
23
23
  #
24
- NodesField = GraphQL::Schema::Field.new(
25
- name: "nodes",
26
- owner: nil,
27
- type: [GraphQL::Types::Relay::Node, null: true],
28
- null: false,
29
- description: "Fetches a list of objects given a list of IDs.",
30
- relay_nodes_field: true,
31
- ) do
32
- argument :ids, "[ID!]!", required: true,
33
- description: "IDs of the objects."
34
-
35
- def resolve(obj, args, ctx)
36
- args[:ids].map { |id| ctx.schema.object_from_id(id, ctx) }
37
- end
38
-
39
- def resolve_field(obj, args, ctx)
40
- resolve(obj, args, ctx)
41
- end
42
- end
24
+ NodesField = GraphQL::Schema::Field.new(**HasNodesField.field_options, &HasNodesField.field_block)
43
25
  end
44
26
  end
45
27
  end
@@ -3,20 +3,8 @@ module GraphQL
3
3
  module Types
4
4
  module Relay
5
5
  # The return type of a connection's `pageInfo` field
6
- class PageInfo < Types::Relay::BaseObject
7
- default_relay true
8
- description "Information about pagination in a connection."
9
- field :has_next_page, Boolean, null: false,
10
- description: "When paginating forwards, are there more items?"
11
-
12
- field :has_previous_page, Boolean, null: false,
13
- description: "When paginating backwards, are there more items?"
14
-
15
- field :start_cursor, String, null: true,
16
- description: "When paginating backwards, the cursor to continue."
17
-
18
- field :end_cursor, String, null: true,
19
- description: "When paginating forwards, the cursor to continue."
6
+ class PageInfo < GraphQL::Schema::Object
7
+ include PageInfoBehaviors
20
8
  end
21
9
  end
22
10
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Types
4
+ module Relay
5
+ module PageInfoBehaviors
6
+ def self.included(child_class)
7
+ child_class.extend GraphQL::Types::Relay::DefaultRelay
8
+
9
+ child_class.description "Information about pagination in a connection."
10
+ child_class.field :has_next_page, Boolean, null: false,
11
+ description: "When paginating forwards, are there more items?"
12
+
13
+ child_class.field :has_previous_page, Boolean, null: false,
14
+ description: "When paginating backwards, are there more items?"
15
+
16
+ child_class.field :start_cursor, String, null: true,
17
+ description: "When paginating backwards, the cursor to continue."
18
+
19
+ child_class.field :end_cursor, String, null: true,
20
+ description: "When paginating forwards, the cursor to continue."
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end