graphql 2.6.11 → 2.6.13

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 (382) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +4 -0
  3. data/lib/generators/graphql/core.rb +1 -0
  4. data/lib/generators/graphql/detailed_trace_generator.rb +1 -0
  5. data/lib/generators/graphql/enum_generator.rb +1 -0
  6. data/lib/generators/graphql/field_extractor.rb +1 -0
  7. data/lib/generators/graphql/input_generator.rb +1 -0
  8. data/lib/generators/graphql/install/mutation_root_generator.rb +1 -0
  9. data/lib/generators/graphql/install_generator.rb +1 -0
  10. data/lib/generators/graphql/interface_generator.rb +1 -0
  11. data/lib/generators/graphql/loader_generator.rb +8 -2
  12. data/lib/generators/graphql/mutation_create_generator.rb +8 -2
  13. data/lib/generators/graphql/mutation_delete_generator.rb +8 -2
  14. data/lib/generators/graphql/mutation_generator.rb +8 -2
  15. data/lib/generators/graphql/mutation_update_generator.rb +8 -2
  16. data/lib/generators/graphql/object_generator.rb +1 -0
  17. data/lib/generators/graphql/orm_mutations_base.rb +8 -2
  18. data/lib/generators/graphql/relay.rb +1 -0
  19. data/lib/generators/graphql/relay_generator.rb +1 -0
  20. data/lib/generators/graphql/scalar_generator.rb +1 -0
  21. data/lib/generators/graphql/type_generator.rb +38 -8
  22. data/lib/generators/graphql/union_generator.rb +1 -0
  23. data/lib/graphql/analysis/analyzer.rb +35 -9
  24. data/lib/graphql/analysis/field_usage.rb +1 -0
  25. data/lib/graphql/analysis/max_query_complexity.rb +2 -1
  26. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  27. data/lib/graphql/analysis/query_complexity.rb +57 -20
  28. data/lib/graphql/analysis/query_depth.rb +17 -12
  29. data/lib/graphql/analysis/visitor.rb +79 -16
  30. data/lib/graphql/analysis.rb +23 -6
  31. data/lib/graphql/analysis_error.rb +1 -0
  32. data/lib/graphql/autoload.rb +30 -7
  33. data/lib/graphql/backtrace/table.rb +21 -5
  34. data/lib/graphql/backtrace/traced_error.rb +8 -3
  35. data/lib/graphql/backtrace.rb +14 -9
  36. data/lib/graphql/coercion_error.rb +1 -0
  37. data/lib/graphql/current.rb +44 -19
  38. data/lib/graphql/dashboard/application_controller.rb +1 -0
  39. data/lib/graphql/dashboard/detailed_traces.rb +1 -0
  40. data/lib/graphql/dashboard/installable.rb +1 -0
  41. data/lib/graphql/dashboard/landings_controller.rb +1 -0
  42. data/lib/graphql/dashboard/limiters.rb +1 -0
  43. data/lib/graphql/dashboard/operation_store.rb +1 -0
  44. data/lib/graphql/dashboard/statics_controller.rb +1 -0
  45. data/lib/graphql/dashboard/subscriptions.rb +1 -0
  46. data/lib/graphql/dashboard.rb +36 -22
  47. data/lib/graphql/dataloader/active_record_association_source.rb +1 -0
  48. data/lib/graphql/dataloader/active_record_source.rb +1 -0
  49. data/lib/graphql/dataloader/async_dataloader.rb +10 -7
  50. data/lib/graphql/dataloader/null_dataloader.rb +4 -3
  51. data/lib/graphql/dataloader/request.rb +8 -2
  52. data/lib/graphql/dataloader/request_all.rb +8 -2
  53. data/lib/graphql/dataloader/source.rb +127 -35
  54. data/lib/graphql/dataloader.rb +93 -42
  55. data/lib/graphql/date_encoding_error.rb +2 -1
  56. data/lib/graphql/dig.rb +12 -3
  57. data/lib/graphql/duration_encoding_error.rb +2 -1
  58. data/lib/graphql/execution/directive_checks.rb +8 -3
  59. data/lib/graphql/execution/errors.rb +20 -6
  60. data/lib/graphql/execution/field_resolve_step.rb +40 -13
  61. data/lib/graphql/execution/finalize.rb +12 -6
  62. data/lib/graphql/execution/input_values.rb +2 -1
  63. data/lib/graphql/execution/interpreter/argument_value.rb +17 -5
  64. data/lib/graphql/execution/interpreter/arguments.rb +24 -9
  65. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -1
  66. data/lib/graphql/execution/interpreter/execution_errors.rb +1 -0
  67. data/lib/graphql/execution/interpreter/handles_raw_value.rb +1 -0
  68. data/lib/graphql/execution/interpreter/resolve.rb +18 -8
  69. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +4 -1
  70. data/lib/graphql/execution/interpreter/runtime.rb +72 -25
  71. data/lib/graphql/execution/interpreter.rb +15 -6
  72. data/lib/graphql/execution/lazy/lazy_method_map.rb +21 -8
  73. data/lib/graphql/execution/lazy.rb +34 -10
  74. data/lib/graphql/execution/load_argument_step.rb +1 -0
  75. data/lib/graphql/execution/lookahead.rb +137 -54
  76. data/lib/graphql/execution/multiplex.rb +4 -4
  77. data/lib/graphql/execution/next.rb +7 -0
  78. data/lib/graphql/execution/prepare_object_step.rb +1 -0
  79. data/lib/graphql/execution/resolve_type_step.rb +2 -1
  80. data/lib/graphql/execution/runner.rb +9 -3
  81. data/lib/graphql/execution/selections_step.rb +3 -2
  82. data/lib/graphql/execution.rb +2 -2
  83. data/lib/graphql/execution_error.rb +19 -10
  84. data/lib/graphql/float_decoding_error.rb +1 -0
  85. data/lib/graphql/float_encoding_error.rb +7 -2
  86. data/lib/graphql/integer_decoding_error.rb +2 -1
  87. data/lib/graphql/integer_encoding_error.rb +8 -3
  88. data/lib/graphql/introspection/base_object.rb +3 -1
  89. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  90. data/lib/graphql/introspection/directive_type.rb +1 -0
  91. data/lib/graphql/introspection/dynamic_fields.rb +1 -0
  92. data/lib/graphql/introspection/entry_points.rb +1 -0
  93. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  94. data/lib/graphql/introspection/field_type.rb +1 -0
  95. data/lib/graphql/introspection/input_value_type.rb +1 -0
  96. data/lib/graphql/introspection/introspection_query.rb +1 -0
  97. data/lib/graphql/introspection/schema_type.rb +1 -0
  98. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  99. data/lib/graphql/introspection/type_type.rb +1 -0
  100. data/lib/graphql/introspection.rb +1 -0
  101. data/lib/graphql/invalid_name_error.rb +1 -0
  102. data/lib/graphql/invalid_null_error.rb +19 -6
  103. data/lib/graphql/language/block_string.rb +2 -1
  104. data/lib/graphql/language/cache.rb +10 -4
  105. data/lib/graphql/language/comment.rb +1 -0
  106. data/lib/graphql/language/definition_slice.rb +1 -0
  107. data/lib/graphql/language/document_from_schema_definition.rb +9 -10
  108. data/lib/graphql/language/generation.rb +23 -9
  109. data/lib/graphql/language/lexer.rb +5 -0
  110. data/lib/graphql/language/nodes.rb +2094 -419
  111. data/lib/graphql/language/parser.rb +24 -17
  112. data/lib/graphql/language/printer.rb +31 -16
  113. data/lib/graphql/language/sanitized_printer.rb +16 -5
  114. data/lib/graphql/language/static_visitor.rb +19 -4
  115. data/lib/graphql/language/visitor.rb +51 -29
  116. data/lib/graphql/language.rb +13 -7
  117. data/lib/graphql/load_application_object_failed_error.rb +14 -5
  118. data/lib/graphql/name_validator.rb +1 -0
  119. data/lib/graphql/pagination/active_record_relation_connection.rb +1 -0
  120. data/lib/graphql/pagination/array_connection.rb +20 -6
  121. data/lib/graphql/pagination/connection.rb +178 -48
  122. data/lib/graphql/pagination/connections.rb +21 -14
  123. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -0
  124. data/lib/graphql/pagination/relation_connection.rb +123 -22
  125. data/lib/graphql/pagination/sequel_dataset_connection.rb +1 -0
  126. data/lib/graphql/pagination.rb +1 -0
  127. data/lib/graphql/parse_error.rb +1 -0
  128. data/lib/graphql/query/context/scoped_context.rb +2 -1
  129. data/lib/graphql/query/context.rb +106 -35
  130. data/lib/graphql/query/fingerprint.rb +15 -7
  131. data/lib/graphql/query/input_validation_result.rb +1 -0
  132. data/lib/graphql/query/null_context.rb +1 -0
  133. data/lib/graphql/query/partial.rb +28 -15
  134. data/lib/graphql/query/result.rb +15 -5
  135. data/lib/graphql/query/validation_pipeline.rb +16 -6
  136. data/lib/graphql/query/variable_validation_error.rb +1 -0
  137. data/lib/graphql/query/variables.rb +9 -2
  138. data/lib/graphql/query.rb +193 -49
  139. data/lib/graphql/railtie.rb +7 -3
  140. data/lib/graphql/rake_task/validate.rb +72 -17
  141. data/lib/graphql/rake_task.rb +55 -23
  142. data/lib/graphql/relay/range_add.rb +32 -21
  143. data/lib/graphql/relay.rb +1 -0
  144. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -0
  145. data/lib/graphql/rubocop/graphql/default_null_true.rb +9 -6
  146. data/lib/graphql/rubocop/graphql/default_required_true.rb +9 -6
  147. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +12 -8
  148. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +9 -5
  149. data/lib/graphql/rubocop.rb +1 -0
  150. data/lib/graphql/runtime_error.rb +1 -0
  151. data/lib/graphql/runtime_type_error.rb +1 -0
  152. data/lib/graphql/schema/addition.rb +18 -6
  153. data/lib/graphql/schema/always_visible.rb +1 -0
  154. data/lib/graphql/schema/argument.rb +265 -42
  155. data/lib/graphql/schema/base_64_encoder.rb +2 -2
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  158. data/lib/graphql/schema/build_from_definition.rb +94 -27
  159. data/lib/graphql/schema/built_in_types.rb +1 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +1 -0
  161. data/lib/graphql/schema/directive/feature.rb +39 -22
  162. data/lib/graphql/schema/directive/flagged.rb +6 -1
  163. data/lib/graphql/schema/directive/include.rb +1 -0
  164. data/lib/graphql/schema/directive/one_of.rb +1 -0
  165. data/lib/graphql/schema/directive/skip.rb +1 -0
  166. data/lib/graphql/schema/directive/specified_by.rb +1 -0
  167. data/lib/graphql/schema/directive/transform.rb +17 -8
  168. data/lib/graphql/schema/directive.rb +12 -7
  169. data/lib/graphql/schema/enum.rb +99 -38
  170. data/lib/graphql/schema/enum_value.rb +21 -13
  171. data/lib/graphql/schema/field/connection_extension.rb +10 -2
  172. data/lib/graphql/schema/field/scope_extension.rb +1 -0
  173. data/lib/graphql/schema/field.rb +621 -109
  174. data/lib/graphql/schema/field_extension.rb +89 -34
  175. data/lib/graphql/schema/find_inherited_value.rb +5 -3
  176. data/lib/graphql/schema/finder.rb +22 -8
  177. data/lib/graphql/schema/has_single_input_argument.rb +39 -6
  178. data/lib/graphql/schema/input_object.rb +40 -13
  179. data/lib/graphql/schema/interface.rb +33 -17
  180. data/lib/graphql/schema/introspection_system.rb +7 -3
  181. data/lib/graphql/schema/late_bound_type.rb +2 -2
  182. data/lib/graphql/schema/list.rb +15 -4
  183. data/lib/graphql/schema/loader.rb +23 -12
  184. data/lib/graphql/schema/member/base_dsl_methods.rb +58 -12
  185. data/lib/graphql/schema/member/build_type.rb +16 -5
  186. data/lib/graphql/schema/member/graphql_type_names.rb +10 -6
  187. data/lib/graphql/schema/member/has_arguments.rb +115 -48
  188. data/lib/graphql/schema/member/has_ast_node.rb +1 -0
  189. data/lib/graphql/schema/member/has_authorization.rb +5 -0
  190. data/lib/graphql/schema/member/has_dataloader.rb +91 -34
  191. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -2
  192. data/lib/graphql/schema/member/has_directives.rb +38 -10
  193. data/lib/graphql/schema/member/has_fields.rb +151 -70
  194. data/lib/graphql/schema/member/has_interfaces.rb +10 -2
  195. data/lib/graphql/schema/member/has_path.rb +14 -5
  196. data/lib/graphql/schema/member/has_unresolved_type_error.rb +1 -0
  197. data/lib/graphql/schema/member/has_validators.rb +19 -4
  198. data/lib/graphql/schema/member/relay_shortcuts.rb +10 -2
  199. data/lib/graphql/schema/member/scoped.rb +14 -3
  200. data/lib/graphql/schema/member/type_system_helpers.rb +36 -6
  201. data/lib/graphql/schema/member/validates_input.rb +1 -0
  202. data/lib/graphql/schema/member.rb +9 -2
  203. data/lib/graphql/schema/mutation.rb +50 -46
  204. data/lib/graphql/schema/non_null.rb +21 -5
  205. data/lib/graphql/schema/object.rb +33 -12
  206. data/lib/graphql/schema/printer.rb +52 -31
  207. data/lib/graphql/schema/ractor_shareable.rb +6 -2
  208. data/lib/graphql/schema/relay_classic_mutation.rb +3 -3
  209. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -7
  210. data/lib/graphql/schema/resolver.rb +156 -45
  211. data/lib/graphql/schema/scalar.rb +1 -0
  212. data/lib/graphql/schema/subscription.rb +67 -28
  213. data/lib/graphql/schema/timeout.rb +65 -25
  214. data/lib/graphql/schema/type_expression.rb +14 -5
  215. data/lib/graphql/schema/type_membership.rb +29 -10
  216. data/lib/graphql/schema/union.rb +4 -2
  217. data/lib/graphql/schema/unique_within_type.rb +24 -5
  218. data/lib/graphql/schema/validator/all_validator.rb +17 -9
  219. data/lib/graphql/schema/validator/allow_blank_validator.rb +8 -2
  220. data/lib/graphql/schema/validator/allow_null_validator.rb +8 -2
  221. data/lib/graphql/schema/validator/exclusion_validator.rb +14 -5
  222. data/lib/graphql/schema/validator/format_validator.rb +21 -10
  223. data/lib/graphql/schema/validator/inclusion_validator.rb +15 -6
  224. data/lib/graphql/schema/validator/length_validator.rb +23 -12
  225. data/lib/graphql/schema/validator/numericality_validator.rb +29 -16
  226. data/lib/graphql/schema/validator/required_validator.rb +45 -31
  227. data/lib/graphql/schema/validator.rb +89 -25
  228. data/lib/graphql/schema/visibility/migration.rb +14 -7
  229. data/lib/graphql/schema/visibility/profile.rb +65 -20
  230. data/lib/graphql/schema/visibility/visit.rb +12 -10
  231. data/lib/graphql/schema/visibility.rb +24 -20
  232. data/lib/graphql/schema/warden.rb +117 -31
  233. data/lib/graphql/schema/wrapper.rb +4 -1
  234. data/lib/graphql/schema.rb +1046 -300
  235. data/lib/graphql/static_validation/all_rules.rb +2 -1
  236. data/lib/graphql/static_validation/base_visitor.rb +59 -9
  237. data/lib/graphql/static_validation/definition_dependencies.rb +27 -7
  238. data/lib/graphql/static_validation/error.rb +3 -0
  239. data/lib/graphql/static_validation/interpreter_visitor.rb +1 -0
  240. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  241. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -0
  242. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +1 -0
  243. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +3 -0
  244. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +1 -0
  245. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -0
  246. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +1 -0
  247. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -0
  248. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +1 -0
  249. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +3 -0
  250. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +1 -0
  251. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -0
  252. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +1 -0
  253. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +9 -1
  254. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +1 -0
  255. data/lib/graphql/static_validation/rules/fields_will_merge.rb +295 -134
  256. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +14 -2
  257. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +3 -0
  258. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +1 -0
  259. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -0
  260. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +1 -0
  261. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +3 -0
  262. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +1 -0
  263. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +3 -0
  264. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +1 -0
  265. data/lib/graphql/static_validation/rules/fragments_are_named.rb +3 -0
  266. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +1 -0
  267. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +3 -0
  268. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +1 -0
  269. data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -0
  270. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +1 -0
  271. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +3 -0
  272. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +1 -0
  273. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +3 -0
  274. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +1 -0
  275. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +3 -0
  276. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +1 -0
  277. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +1 -0
  278. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +4 -0
  279. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +1 -0
  280. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +3 -0
  281. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +1 -0
  282. data/lib/graphql/static_validation/rules/query_root_exists.rb +3 -0
  283. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +1 -0
  284. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -1
  285. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +1 -0
  286. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -0
  287. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +1 -0
  288. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +43 -5
  289. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +1 -0
  290. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +3 -0
  291. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +1 -0
  292. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -0
  293. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +1 -0
  294. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +3 -0
  295. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +1 -0
  296. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +207 -51
  297. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +1 -0
  298. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +3 -0
  299. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +1 -0
  300. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -3
  301. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +1 -0
  302. data/lib/graphql/static_validation/validation_context.rb +3 -2
  303. data/lib/graphql/static_validation/validation_timeout_error.rb +1 -0
  304. data/lib/graphql/static_validation/validator.rb +41 -16
  305. data/lib/graphql/static_validation.rb +1 -0
  306. data/lib/graphql/string_encoding_error.rb +1 -0
  307. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +85 -65
  308. data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
  309. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +1 -0
  310. data/lib/graphql/subscriptions/event.rb +25 -6
  311. data/lib/graphql/subscriptions/serialize.rb +58 -19
  312. data/lib/graphql/subscriptions.rb +172 -46
  313. data/lib/graphql/testing/helpers.rb +17 -4
  314. data/lib/graphql/testing/mock_action_cable.rb +55 -33
  315. data/lib/graphql/testing.rb +1 -0
  316. data/lib/graphql/tracing/active_support_notifications_trace.rb +17 -9
  317. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  318. data/lib/graphql/tracing/appoptics_trace.rb +2 -1
  319. data/lib/graphql/tracing/appoptics_tracing.rb +2 -1
  320. data/lib/graphql/tracing/appsignal_trace.rb +16 -7
  321. data/lib/graphql/tracing/appsignal_tracing.rb +7 -3
  322. data/lib/graphql/tracing/call_legacy_tracers.rb +1 -0
  323. data/lib/graphql/tracing/data_dog_trace.rb +17 -6
  324. data/lib/graphql/tracing/data_dog_tracing.rb +10 -3
  325. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +1 -0
  326. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +1 -0
  327. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +1 -0
  328. data/lib/graphql/tracing/detailed_trace.rb +105 -42
  329. data/lib/graphql/tracing/legacy_hooks_trace.rb +5 -0
  330. data/lib/graphql/tracing/legacy_trace.rb +1 -0
  331. data/lib/graphql/tracing/monitor_trace.rb +17 -11
  332. data/lib/graphql/tracing/new_relic_trace.rb +17 -8
  333. data/lib/graphql/tracing/new_relic_tracing.rb +7 -3
  334. data/lib/graphql/tracing/notifications_trace.rb +11 -8
  335. data/lib/graphql/tracing/notifications_tracing.rb +23 -7
  336. data/lib/graphql/tracing/null_trace.rb +1 -0
  337. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +1 -0
  338. data/lib/graphql/tracing/perfetto_trace.rb +41 -19
  339. data/lib/graphql/tracing/platform_trace.rb +3 -1
  340. data/lib/graphql/tracing/platform_tracing.rb +16 -7
  341. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +1 -0
  342. data/lib/graphql/tracing/prometheus_trace.rb +22 -13
  343. data/lib/graphql/tracing/prometheus_tracing.rb +1 -0
  344. data/lib/graphql/tracing/scout_trace.rb +10 -4
  345. data/lib/graphql/tracing/scout_tracing.rb +7 -3
  346. data/lib/graphql/tracing/sentry_trace.rb +12 -5
  347. data/lib/graphql/tracing/statsd_trace.rb +12 -6
  348. data/lib/graphql/tracing/statsd_tracing.rb +7 -1
  349. data/lib/graphql/tracing/trace.rb +231 -58
  350. data/lib/graphql/tracing.rb +25 -9
  351. data/lib/graphql/type_kinds.rb +2 -1
  352. data/lib/graphql/types/big_int.rb +1 -0
  353. data/lib/graphql/types/boolean.rb +1 -0
  354. data/lib/graphql/types/float.rb +1 -0
  355. data/lib/graphql/types/id.rb +1 -0
  356. data/lib/graphql/types/int.rb +2 -1
  357. data/lib/graphql/types/iso_8601_date.rb +21 -4
  358. data/lib/graphql/types/iso_8601_date_time.rb +33 -6
  359. data/lib/graphql/types/iso_8601_duration.rb +42 -9
  360. data/lib/graphql/types/json.rb +1 -0
  361. data/lib/graphql/types/relay/base_connection.rb +38 -32
  362. data/lib/graphql/types/relay/base_edge.rb +15 -9
  363. data/lib/graphql/types/relay/connection_behaviors.rb +19 -3
  364. data/lib/graphql/types/relay/edge_behaviors.rb +17 -4
  365. data/lib/graphql/types/relay/has_node_field.rb +6 -1
  366. data/lib/graphql/types/relay/has_nodes_field.rb +6 -1
  367. data/lib/graphql/types/relay/node.rb +1 -0
  368. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  369. data/lib/graphql/types/relay/page_info.rb +1 -0
  370. data/lib/graphql/types/relay/page_info_behaviors.rb +1 -0
  371. data/lib/graphql/types/relay.rb +4 -3
  372. data/lib/graphql/types/string.rb +1 -0
  373. data/lib/graphql/types.rb +1 -0
  374. data/lib/graphql/unauthorized_enum_value_error.rb +4 -1
  375. data/lib/graphql/unauthorized_error.rb +11 -4
  376. data/lib/graphql/unauthorized_field_error.rb +4 -1
  377. data/lib/graphql/unresolved_type_error.rb +16 -5
  378. data/lib/graphql/version.rb +2 -1
  379. data/lib/graphql.rb +37 -9
  380. data/readme.md +1 -1
  381. metadata +89 -5
  382. data/.yardopts +0 -5
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  require "strscan"
4
5
  require "graphql/language/nodes"
@@ -65,24 +66,30 @@ module GraphQL
65
66
  end
66
67
 
67
68
  def column_at(pos)
68
- next_line_idx = lines_at.bsearch_index { |l| l >= pos } || 0
69
- if next_line_idx > 0
70
- line_pos = @lines_at[next_line_idx - 1]
71
- pos - line_pos
69
+ next_line_idx = lines_at.bsearch_index { |l| l >= pos } || @lines_at.size
70
+ line_start = next_line_idx == 0 ? 0 : @lines_at[next_line_idx - 1] + 1
71
+ if @graphql_str.ascii_only?
72
+ pos - line_start + 1
72
73
  else
73
- pos + 1
74
+ @graphql_str.byteslice(line_start, pos - line_start).force_encoding(Encoding::UTF_8).length + 1
74
75
  end
75
76
  end
76
77
 
77
78
  private
78
79
 
79
- # @return [Array<Integer>] Positions of each line break in the original string
80
+ # **Returns**
81
+ #
82
+ # - `Array<Integer>` — Byte offsets of each line break in the original string
83
+ #
84
+ # :call-seq:
85
+ # lines_at() -> Array[Integer]
80
86
  def lines_at
81
87
  @lines_at ||= begin
88
+ graphql_str = @graphql_str.b
82
89
  la = []
83
- idx = 0
90
+ idx = 0 #: Integer?
84
91
  while idx
85
- idx = @graphql_str.index("\n", idx)
92
+ idx = graphql_str.index("\n", idx)
86
93
  if idx
87
94
  la << idx
88
95
  idx += 1
@@ -158,7 +165,7 @@ module GraphQL
158
165
  expect_token(:LPAREN)
159
166
  defs = []
160
167
  while !at?(:RPAREN)
161
- loc = pos
168
+ loc = pos #: untyped
162
169
  expect_token(:VAR_SIGN)
163
170
  var_name = parse_name
164
171
  expect_token(:COLON)
@@ -168,7 +175,7 @@ module GraphQL
168
175
  value
169
176
  end
170
177
 
171
- directives = parse_directives
178
+ directives = parse_directives #: untyped
172
179
 
173
180
  defs << Nodes::VariableDefinition.new(
174
181
  pos: loc,
@@ -250,15 +257,15 @@ module GraphQL
250
257
  if at?(:QUERY)
251
258
  advance_token
252
259
  expect_token(:COLON)
253
- query = parse_name
260
+ query = parse_name #: untyped
254
261
  elsif at?(:MUTATION)
255
262
  advance_token
256
263
  expect_token(:COLON)
257
- mutation = parse_name
264
+ mutation = parse_name #: untyped
258
265
  elsif at?(:SUBSCRIPTION)
259
266
  advance_token
260
267
  expect_token(:COLON)
261
- subscription = parse_name
268
+ subscription = parse_name #: untyped
262
269
  else
263
270
  expect_one_of([:QUERY, :MUTATION, :SUBSCRIPTION])
264
271
  end
@@ -291,15 +298,15 @@ module GraphQL
291
298
  if at?(:QUERY)
292
299
  advance_token
293
300
  expect_token(:COLON)
294
- query = parse_name
301
+ query = parse_name #: untyped
295
302
  elsif at?(:MUTATION)
296
303
  advance_token
297
304
  expect_token(:COLON)
298
- mutation = parse_name
305
+ mutation = parse_name #: untyped
299
306
  elsif at?(:SUBSCRIPTION)
300
307
  advance_token
301
308
  expect_token(:COLON)
302
- subscription = parse_name
309
+ subscription = parse_name #: untyped
303
310
  else
304
311
  expect_one_of([:QUERY, :MUTATION, :SUBSCRIPTION])
305
312
  end
@@ -736,7 +743,7 @@ module GraphQL
736
743
  advance_token
737
744
  args = []
738
745
  while !at?(:RCURLY)
739
- loc = pos
746
+ loc = pos #: untyped
740
747
  n = parse_name
741
748
  expect_token(:COLON)
742
749
  args << Argument.new(pos: loc, name: n, value: value, filename: @filename, source: self)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Language
4
5
  class Printer
@@ -30,27 +31,41 @@ module GraphQL
30
31
 
31
32
  # Turn an arbitrary AST node back into a string.
32
33
  #
33
- # @example Turning a document into a query string
34
- # document = GraphQL.parse(query_string)
35
- # GraphQL::Language::Printer.new.print(document)
36
- # # => "{ ... }"
34
+ # **Examples**
37
35
  #
36
+ # **Example: Turning a document into a query string**
38
37
  #
39
- # @example Building a custom printer
38
+ # ```ruby
39
+ # document = GraphQL.parse(query_string)
40
+ # GraphQL::Language::Printer.new.print(document)
41
+ # # => "{ ... }"
42
+ # ```
40
43
  #
41
- # class MyPrinter < GraphQL::Language::Printer
42
- # def print_argument(arg)
43
- # print_string("#{arg.name}: <HIDDEN>")
44
- # end
45
- # end
44
+ # **Example: Building a custom printer**
46
45
  #
47
- # MyPrinter.new.print(document)
48
- # # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
46
+ # ```ruby
47
+ # class MyPrinter < GraphQL::Language::Printer
48
+ # def print_argument(arg)
49
+ # print_string("#{arg.name}: <HIDDEN>")
50
+ # end
51
+ # end
49
52
  #
50
- # @param node [Nodes::AbstractNode]
51
- # @param indent [String] Whitespace to add to the printed node
52
- # @param truncate_size [Integer, nil] The size to truncate to.
53
- # @return [String] Valid GraphQL for `node`
53
+ # MyPrinter.new.print(document)
54
+ # # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
55
+ # ```
56
+ #
57
+ # **Parameters**
58
+ #
59
+ # - `node` (`Nodes::AbstractNode`)
60
+ # - `indent` (`String`) — Whitespace to add to the printed node
61
+ # - `truncate_size` (`Integer, nil`) — The size to truncate to.
62
+ #
63
+ # **Returns**
64
+ #
65
+ # - `String` — Valid GraphQL for `node`
66
+ #
67
+ # :call-seq:
68
+ # print(Nodes::AbstractNode node, String indent:, Integer | nil truncate_size:) -> String
54
69
  def print(node, indent: "", truncate_size: nil)
55
70
  truncate_size = truncate_size ? [truncate_size - OMISSION.size, 0].max : nil
56
71
  @out = TruncatableBuffer.new(truncate_size: truncate_size)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Language
4
5
  # A custom printer used to print sanitized queries. It inlines provided variables
@@ -10,11 +11,16 @@ module GraphQL
10
11
  # on the type of fields or arguments, we have to track the current object, field
11
12
  # and input type while printing the query.
12
13
  #
13
- # @example Printing a scrubbed string
14
- # printer = QueryPrinter.new(query)
15
- # puts printer.sanitized_query_string
14
+ # See [Query#sanitized_query_string](rdoc-ref:Query#sanitized_query_string)
16
15
  #
17
- # @see {Query#sanitized_query_string}
16
+ # **Examples**
17
+ #
18
+ # **Example: Printing a scrubbed string**
19
+ #
20
+ # ```ruby
21
+ # printer = QueryPrinter.new(query)
22
+ # puts printer.sanitized_query_string
23
+ # ```
18
24
  class SanitizedPrinter < GraphQL::Language::Printer
19
25
 
20
26
  REDACTED = "\"<REDACTED>\""
@@ -27,7 +33,12 @@ module GraphQL
27
33
  @inline_variables = inline_variables
28
34
  end
29
35
 
30
- # @return [String, nil] A scrubbed query string, if the query was valid.
36
+ # **Returns**
37
+ #
38
+ # - `String, nil` — A scrubbed query string, if the query was valid.
39
+ #
40
+ # :call-seq:
41
+ # sanitized_query_string() -> String | nil
31
42
  def sanitized_query_string
32
43
  if query.valid?
33
44
  print(query.document)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Language
4
5
  # Like `GraphQL::Language::Visitor` except it doesn't support
@@ -9,7 +10,13 @@ module GraphQL
9
10
  end
10
11
 
11
12
  # Visit `document` and all children
12
- # @return [void]
13
+ #
14
+ # **Returns**
15
+ #
16
+ # - `void`
17
+ #
18
+ # :call-seq:
19
+ # visit() -> void
13
20
  def visit
14
21
  # `@document` may be any kind of node:
15
22
  visit_method = @document.visit_method
@@ -104,9 +111,17 @@ module GraphQL
104
111
  # To customize this hook, override one of its make_visit_methods (or the base method?)
105
112
  # in your subclasses.
106
113
  #
107
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
108
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
109
- # @return [void]
114
+ # **Parameters**
115
+ #
116
+ # - `node` (`GraphQL::Language::Nodes::AbstractNode`) — the node being visited
117
+ # - `parent` (`GraphQL::Language::Nodes::AbstractNode, nil`) — the previously-visited node, or `nil` if this is the root node.
118
+ #
119
+ # **Returns**
120
+ #
121
+ # - `void`
122
+ #
123
+ # :call-seq:
124
+ # #{node_method}(GraphQL::Language::Nodes::AbstractNode node, GraphQL::Language::Nodes::AbstractNode | nil parent) -> void
110
125
  def #{node_method}(node, parent)
111
126
  #{
112
127
  if method_defined?(child_visit_method)
@@ -1,37 +1,43 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Language
4
5
  # Depth-first traversal through the tree, calling hooks at each stop.
5
6
  #
6
- # @example Create a visitor counting certain field names
7
- # class NameCounter < GraphQL::Language::Visitor
8
- # def initialize(document, field_name)
9
- # super(document)
10
- # @field_name = field_name
11
- # @count = 0
12
- # end
7
+ # See [GraphQL::Language::StaticVisitor](rdoc-ref:GraphQL::Language::StaticVisitor) for a faster visitor that doesn't support modifying the document
13
8
  #
14
- # attr_reader :count
9
+ # **Examples**
15
10
  #
16
- # def on_field(node, parent)
17
- # # if this field matches our search, increment the counter
18
- # if node.name == @field_name
19
- # @count += 1
20
- # end
21
- # # Continue visiting subfields:
22
- # super
23
- # end
11
+ # **Example: Create a visitor counting certain field names**
12
+ #
13
+ # ```ruby
14
+ # class NameCounter < GraphQL::Language::Visitor
15
+ # def initialize(document, field_name)
16
+ # super(document)
17
+ # @field_name = field_name
18
+ # @count = 0
24
19
  # end
25
20
  #
26
- # # Initialize a visitor
27
- # visitor = NameCounter.new(document, "name")
28
- # # Run it
29
- # visitor.visit
30
- # # Check the result
31
- # visitor.count
32
- # # => 3
21
+ # attr_reader :count
22
+ #
23
+ # def on_field(node, parent)
24
+ # # if this field matches our search, increment the counter
25
+ # if node.name == @field_name
26
+ # @count += 1
27
+ # end
28
+ # # Continue visiting subfields:
29
+ # super
30
+ # end
31
+ # end
33
32
  #
34
- # @see GraphQL::Language::StaticVisitor for a faster visitor that doesn't support modifying the document
33
+ # # Initialize a visitor
34
+ # visitor = NameCounter.new(document, "name")
35
+ # # Run it
36
+ # visitor.visit
37
+ # # Check the result
38
+ # visitor.count
39
+ # # => 3
40
+ # ```
35
41
  class Visitor
36
42
  class DeleteNode; end
37
43
 
@@ -44,11 +50,19 @@ module GraphQL
44
50
  @result = nil
45
51
  end
46
52
 
47
- # @return [GraphQL::Language::Nodes::Document] The document with any modifications applied
53
+ # **Returns**
54
+ #
55
+ # - `GraphQL::Language::Nodes::Document` — The document with any modifications applied
48
56
  attr_reader :result
49
57
 
50
58
  # Visit `document` and all children
51
- # @return [void]
59
+ #
60
+ # **Returns**
61
+ #
62
+ # - `void`
63
+ #
64
+ # :call-seq:
65
+ # visit() -> void
52
66
  def visit
53
67
  # `@document` may be any kind of node:
54
68
  visit_method = :"#{@document.visit_method}_with_modifications"
@@ -175,9 +189,17 @@ module GraphQL
175
189
  # To customize this hook, override one of its make_visit_methods (or the base method?)
176
190
  # in your subclasses.
177
191
  #
178
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
179
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
180
- # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
192
+ # **Parameters**
193
+ #
194
+ # - `node` (`GraphQL::Language::Nodes::AbstractNode`) — the node being visited
195
+ # - `parent` (`GraphQL::Language::Nodes::AbstractNode, nil`) — the previously-visited node, or `nil` if this is the root node.
196
+ #
197
+ # **Returns**
198
+ #
199
+ # - `Array, nil` — If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
200
+ #
201
+ # :call-seq:
202
+ # #{node_method}(GraphQL::Language::Nodes::AbstractNode node, GraphQL::Language::Nodes::AbstractNode | nil parent) -> Array | nil
181
203
  def #{node_method}(node, parent)
182
204
  if node.equal?(DELETE_NODE)
183
205
  # This might be passed to `super(DELETE_NODE, ...)`
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  require "graphql/language/block_string"
3
4
  require "graphql/language/comment"
4
5
  require "graphql/language/printer"
@@ -16,8 +17,7 @@ require "strscan"
16
17
 
17
18
  module GraphQL
18
19
  module Language
19
- # @api private
20
- def self.serialize(value)
20
+ def self.serialize(value) # :nodoc:
21
21
  if value.is_a?(Hash)
22
22
  serialized_hash = value.map do |k, v|
23
23
  "#{k}:#{serialize v}"
@@ -43,12 +43,18 @@ module GraphQL
43
43
 
44
44
  # Returns a new string if any single-quoted newlines were escaped.
45
45
  # Otherwise, returns `query_str` unchanged.
46
- # @return [String]
46
+ #
47
+ # **Returns**
48
+ #
49
+ # - `String`
50
+ #
51
+ # :call-seq:
52
+ # escape_single_quoted_newlines(query_str) -> String
47
53
  def self.escape_single_quoted_newlines(query_str)
48
54
  scanner = StringScanner.new(query_str)
49
- inside_single_quoted_string = false
50
- inside_triple_quoted_string = false
51
- new_query_str = nil
55
+ inside_single_quoted_string = false #: bool
56
+ inside_triple_quoted_string = false #: bool
57
+ new_query_str = nil #: String?
52
58
  while !scanner.eos?
53
59
  if scanner.skip('"""')
54
60
  inside_triple_quoted_string = !inside_triple_quoted_string
@@ -83,7 +89,7 @@ module GraphQL
83
89
  new_query_str || query_str
84
90
  end
85
91
 
86
- LEADING_REGEX = Regexp.union(" ", *Lexer::Punctuation.constants.map { |const| Lexer::Punctuation.const_get(const) })
92
+ LEADING_REGEX = Regexp.union([" ", *Lexer::Punctuation.constants.map { |const| Lexer::Punctuation.const_get(const) }])
87
93
 
88
94
  # Optimized pattern using:
89
95
  # - Possessive quantifiers (*+, ++) to prevent backtracking in number patterns
@@ -1,18 +1,27 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  module GraphQL
4
5
  # Raised when a argument is configured with `loads:` and the client provides an `ID`,
5
6
  # but no object is loaded for that ID.
6
7
  #
7
- # @see GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader#load_application_object_failed, A hook which you can override in resolvers, mutations and input objects.
8
+ # See [GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader#load_application_object_failed](rdoc-ref:GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader#load_application_object_failed) A hook which you can override in resolvers, mutations and input objects.
8
9
  class LoadApplicationObjectFailedError < GraphQL::ExecutionError
9
- # @return [GraphQL::Schema::Argument] the argument definition for the argument that was looked up
10
+ # **Returns**
11
+ #
12
+ # - `GraphQL::Schema::Argument` — the argument definition for the argument that was looked up
10
13
  attr_reader :argument
11
- # @return [String] The ID provided by the client
14
+ # **Returns**
15
+ #
16
+ # - `String` — The ID provided by the client
12
17
  attr_reader :id
13
- # @return [Object] The value found with this ID
18
+ # **Returns**
19
+ #
20
+ # - `Object` — The value found with this ID
14
21
  attr_reader :object
15
- # @return [GraphQL::Query::Context]
22
+ # **Returns**
23
+ #
24
+ # - `GraphQL::Query::Context`
16
25
  attr_reader :context
17
26
 
18
27
  def initialize(argument:, id:, object:, context:)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  class NameValidator
4
5
  VALID_NAME_REGEX = /^[_a-zA-Z][_a-zA-Z0-9]*$/
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  require "graphql/pagination/relation_connection"
3
4
 
4
5
  module GraphQL
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  require "graphql/pagination/connection"
3
4
 
4
5
  module GraphQL
@@ -20,14 +21,22 @@ module GraphQL
20
21
  end
21
22
 
22
23
  def cursor_for(item)
23
- idx = items.find_index(item) + 1
24
- encode(idx.to_s)
24
+ index = cursor_index_for(item, items)
25
+ encode((index + 1).to_s)
26
+ end
27
+
28
+ def cursor_for_position(item, position) # :nodoc:
29
+ if self.class.custom_cursor_for?(ArrayConnection)
30
+ super
31
+ else
32
+ encode((@paged_nodes_offset + position + 1).to_s)
33
+ end
25
34
  end
26
35
 
27
36
  private
28
37
 
29
38
  def index_from_cursor(cursor)
30
- index = Integer(decode(cursor), 10, exception: false)
39
+ index = Integer(decode(cursor), 10, exception: false) #: Integer?
31
40
  if index.nil? || index <= 0
32
41
  raise GraphQL::ExecutionError, "Invalid cursor: #{cursor.inspect}"
33
42
  end
@@ -38,14 +47,15 @@ module GraphQL
38
47
  # It doesn't do anything on subsequent calls.
39
48
  def load_nodes
40
49
  @nodes ||= begin
50
+ sliced_nodes_offset = after ? index_from_cursor(after) : 0
41
51
  sliced_nodes = if before && after
42
52
  end_idx = index_from_cursor(before) - 2
43
- end_idx < 0 ? [] : items[index_from_cursor(after)..end_idx] || []
53
+ end_idx < 0 ? [] : items[sliced_nodes_offset..end_idx] || []
44
54
  elsif before
45
55
  end_idx = index_from_cursor(before) - 2
46
56
  end_idx < 0 ? [] : items[0..end_idx] || []
47
57
  elsif after
48
- items[index_from_cursor(after)..-1] || []
58
+ items[sliced_nodes_offset..-1] || []
49
59
  else
50
60
  items
51
61
  end
@@ -71,9 +81,13 @@ module GraphQL
71
81
  end
72
82
 
73
83
  limited_nodes = sliced_nodes
84
+ @paged_nodes_offset = sliced_nodes_offset
74
85
 
75
86
  limited_nodes = limited_nodes.first(first) if first
76
- limited_nodes = limited_nodes.last(last) if last
87
+ if last
88
+ @paged_nodes_offset += [limited_nodes.length - last, 0].max
89
+ limited_nodes = limited_nodes.last(last)
90
+ end
77
91
 
78
92
  limited_nodes
79
93
  end