graphql 1.11.6 → 1.13.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (293) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/install_generator.rb +17 -7
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/loader_generator.rb +1 -0
  10. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_generator.rb +6 -30
  13. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  14. data/lib/generators/graphql/object_generator.rb +12 -38
  15. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  16. data/lib/generators/graphql/relay.rb +63 -0
  17. data/lib/generators/graphql/relay_generator.rb +21 -0
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  20. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  21. data/lib/generators/graphql/templates/enum.erb +5 -1
  22. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  23. data/lib/generators/graphql/templates/input.erb +9 -0
  24. data/lib/generators/graphql/templates/interface.erb +4 -2
  25. data/lib/generators/graphql/templates/mutation.erb +1 -1
  26. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  27. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  28. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  29. data/lib/generators/graphql/templates/node_type.erb +9 -0
  30. data/lib/generators/graphql/templates/object.erb +5 -3
  31. data/lib/generators/graphql/templates/query_type.erb +1 -3
  32. data/lib/generators/graphql/templates/scalar.erb +3 -1
  33. data/lib/generators/graphql/templates/schema.erb +19 -34
  34. data/lib/generators/graphql/templates/union.erb +4 -2
  35. data/lib/generators/graphql/type_generator.rb +47 -10
  36. data/lib/generators/graphql/union_generator.rb +5 -5
  37. data/lib/graphql/analysis/analyze_query.rb +7 -0
  38. data/lib/graphql/analysis/ast/field_usage.rb +28 -1
  39. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  40. data/lib/graphql/analysis/ast/visitor.rb +14 -5
  41. data/lib/graphql/analysis/ast.rb +11 -2
  42. data/lib/graphql/argument.rb +1 -1
  43. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  44. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  45. data/lib/graphql/backtrace/table.rb +34 -3
  46. data/lib/graphql/backtrace/traced_error.rb +0 -1
  47. data/lib/graphql/backtrace/tracer.rb +40 -10
  48. data/lib/graphql/backtrace.rb +28 -19
  49. data/lib/graphql/backwards_compatibility.rb +2 -1
  50. data/lib/graphql/base_type.rb +6 -4
  51. data/lib/graphql/boolean_type.rb +1 -1
  52. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  53. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  54. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  55. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  56. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  57. data/lib/graphql/dataloader/request.rb +19 -0
  58. data/lib/graphql/dataloader/request_all.rb +19 -0
  59. data/lib/graphql/dataloader/source.rb +155 -0
  60. data/lib/graphql/dataloader.rb +308 -0
  61. data/lib/graphql/date_encoding_error.rb +16 -0
  62. data/lib/graphql/define/assign_global_id_field.rb +1 -1
  63. data/lib/graphql/define/instance_definable.rb +48 -3
  64. data/lib/graphql/define/type_definer.rb +5 -5
  65. data/lib/graphql/deprecated_dsl.rb +18 -5
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  68. data/lib/graphql/directive/include_directive.rb +1 -1
  69. data/lib/graphql/directive/skip_directive.rb +1 -1
  70. data/lib/graphql/directive.rb +1 -5
  71. data/lib/graphql/enum_type.rb +9 -3
  72. data/lib/graphql/execution/errors.rb +110 -7
  73. data/lib/graphql/execution/execute.rb +8 -1
  74. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  75. data/lib/graphql/execution/interpreter/arguments_cache.rb +49 -15
  76. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  77. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  78. data/lib/graphql/execution/interpreter/runtime.rb +670 -294
  79. data/lib/graphql/execution/interpreter.rb +16 -16
  80. data/lib/graphql/execution/lazy.rb +5 -1
  81. data/lib/graphql/execution/lookahead.rb +2 -2
  82. data/lib/graphql/execution/multiplex.rb +39 -23
  83. data/lib/graphql/field.rb +1 -1
  84. data/lib/graphql/float_type.rb +1 -1
  85. data/lib/graphql/function.rb +4 -0
  86. data/lib/graphql/id_type.rb +1 -1
  87. data/lib/graphql/input_object_type.rb +3 -1
  88. data/lib/graphql/int_type.rb +1 -1
  89. data/lib/graphql/integer_decoding_error.rb +17 -0
  90. data/lib/graphql/integer_encoding_error.rb +18 -2
  91. data/lib/graphql/interface_type.rb +4 -2
  92. data/lib/graphql/internal_representation/document.rb +2 -2
  93. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  94. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  95. data/lib/graphql/introspection/directive_type.rb +11 -5
  96. data/lib/graphql/introspection/entry_points.rb +2 -2
  97. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  98. data/lib/graphql/introspection/field_type.rb +3 -3
  99. data/lib/graphql/introspection/input_value_type.rb +10 -4
  100. data/lib/graphql/introspection/schema_type.rb +10 -5
  101. data/lib/graphql/introspection/type_type.rb +18 -12
  102. data/lib/graphql/introspection.rb +5 -2
  103. data/lib/graphql/invalid_null_error.rb +1 -1
  104. data/lib/graphql/language/block_string.rb +2 -6
  105. data/lib/graphql/language/cache.rb +37 -0
  106. data/lib/graphql/language/document_from_schema_definition.rb +60 -26
  107. data/lib/graphql/language/lexer.rb +50 -28
  108. data/lib/graphql/language/lexer.rl +2 -4
  109. data/lib/graphql/language/nodes.rb +14 -4
  110. data/lib/graphql/language/parser.rb +856 -825
  111. data/lib/graphql/language/parser.y +28 -11
  112. data/lib/graphql/language/printer.rb +10 -1
  113. data/lib/graphql/language/sanitized_printer.rb +5 -5
  114. data/lib/graphql/language/token.rb +0 -4
  115. data/lib/graphql/language.rb +1 -0
  116. data/lib/graphql/name_validator.rb +0 -4
  117. data/lib/graphql/object_type.rb +4 -4
  118. data/lib/graphql/pagination/active_record_relation_connection.rb +47 -3
  119. data/lib/graphql/pagination/connection.rb +19 -1
  120. data/lib/graphql/pagination/connections.rb +45 -30
  121. data/lib/graphql/pagination/relation_connection.rb +69 -28
  122. data/lib/graphql/parse_error.rb +0 -1
  123. data/lib/graphql/query/arguments.rb +2 -2
  124. data/lib/graphql/query/arguments_cache.rb +1 -2
  125. data/lib/graphql/query/context.rb +22 -4
  126. data/lib/graphql/query/executor.rb +0 -1
  127. data/lib/graphql/query/input_validation_result.rb +9 -0
  128. data/lib/graphql/query/literal_input.rb +1 -1
  129. data/lib/graphql/query/null_context.rb +21 -9
  130. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  131. data/lib/graphql/query/serial_execution.rb +1 -0
  132. data/lib/graphql/query/validation_pipeline.rb +3 -4
  133. data/lib/graphql/query/variable_validation_error.rb +3 -3
  134. data/lib/graphql/query/variables.rb +35 -4
  135. data/lib/graphql/query.rb +20 -8
  136. data/lib/graphql/railtie.rb +9 -1
  137. data/lib/graphql/rake_task.rb +3 -0
  138. data/lib/graphql/relay/array_connection.rb +2 -2
  139. data/lib/graphql/relay/base_connection.rb +7 -0
  140. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  141. data/lib/graphql/relay/connection_type.rb +16 -3
  142. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  143. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  144. data/lib/graphql/relay/mutation.rb +2 -1
  145. data/lib/graphql/relay/node.rb +3 -0
  146. data/lib/graphql/relay/page_info.rb +1 -1
  147. data/lib/graphql/relay/range_add.rb +14 -5
  148. data/lib/graphql/relay/type_extensions.rb +2 -0
  149. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  150. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  151. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  152. data/lib/graphql/rubocop.rb +4 -0
  153. data/lib/graphql/scalar_type.rb +3 -1
  154. data/lib/graphql/schema/addition.rb +247 -0
  155. data/lib/graphql/schema/argument.rb +177 -21
  156. data/lib/graphql/schema/build_from_definition.rb +150 -55
  157. data/lib/graphql/schema/default_type_error.rb +2 -0
  158. data/lib/graphql/schema/directive/feature.rb +1 -1
  159. data/lib/graphql/schema/directive/flagged.rb +57 -0
  160. data/lib/graphql/schema/directive/include.rb +1 -1
  161. data/lib/graphql/schema/directive/skip.rb +1 -1
  162. data/lib/graphql/schema/directive/transform.rb +14 -2
  163. data/lib/graphql/schema/directive.rb +103 -4
  164. data/lib/graphql/schema/enum.rb +72 -11
  165. data/lib/graphql/schema/enum_value.rb +18 -6
  166. data/lib/graphql/schema/field/connection_extension.rb +4 -2
  167. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  168. data/lib/graphql/schema/field.rb +332 -111
  169. data/lib/graphql/schema/field_extension.rb +89 -2
  170. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  171. data/lib/graphql/schema/finder.rb +5 -5
  172. data/lib/graphql/schema/input_object.rb +79 -55
  173. data/lib/graphql/schema/interface.rb +12 -20
  174. data/lib/graphql/schema/introspection_system.rb +1 -1
  175. data/lib/graphql/schema/list.rb +21 -4
  176. data/lib/graphql/schema/loader.rb +11 -0
  177. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  178. data/lib/graphql/schema/member/base_dsl_methods.rb +5 -16
  179. data/lib/graphql/schema/member/build_type.rb +4 -7
  180. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  181. data/lib/graphql/schema/member/has_arguments.rb +166 -74
  182. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  183. data/lib/graphql/schema/member/has_directives.rb +98 -0
  184. data/lib/graphql/schema/member/has_fields.rb +77 -22
  185. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  186. data/lib/graphql/schema/member/has_validators.rb +31 -0
  187. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  188. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  189. data/lib/graphql/schema/member/validates_input.rb +2 -2
  190. data/lib/graphql/schema/member.rb +5 -0
  191. data/lib/graphql/schema/middleware_chain.rb +1 -1
  192. data/lib/graphql/schema/non_null.rb +9 -3
  193. data/lib/graphql/schema/object.rb +40 -80
  194. data/lib/graphql/schema/printer.rb +16 -20
  195. data/lib/graphql/schema/relay_classic_mutation.rb +38 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -2
  197. data/lib/graphql/schema/resolver.rb +110 -64
  198. data/lib/graphql/schema/scalar.rb +18 -2
  199. data/lib/graphql/schema/subscription.rb +55 -9
  200. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  201. data/lib/graphql/schema/traversal.rb +1 -1
  202. data/lib/graphql/schema/type_expression.rb +1 -1
  203. data/lib/graphql/schema/type_membership.rb +18 -4
  204. data/lib/graphql/schema/union.rb +8 -1
  205. data/lib/graphql/schema/validation.rb +4 -2
  206. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  207. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  208. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  209. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  210. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  211. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  212. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  213. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  214. data/lib/graphql/schema/validator.rb +171 -0
  215. data/lib/graphql/schema/warden.rb +126 -53
  216. data/lib/graphql/schema.rb +262 -281
  217. data/lib/graphql/static_validation/all_rules.rb +2 -0
  218. data/lib/graphql/static_validation/base_visitor.rb +9 -6
  219. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  220. data/lib/graphql/static_validation/error.rb +3 -1
  221. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  222. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -2
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +6 -2
  224. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  225. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  226. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  227. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -47
  229. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  230. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  231. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  232. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  233. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  234. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  235. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  236. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  237. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  238. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  239. data/lib/graphql/static_validation/validation_context.rb +12 -2
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +41 -10
  242. data/lib/graphql/static_validation.rb +1 -0
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/string_type.rb +1 -1
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +39 -8
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +0 -3
  247. data/lib/graphql/subscriptions/event.rb +68 -32
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  249. data/lib/graphql/subscriptions/serialize.rb +34 -5
  250. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  251. data/lib/graphql/subscriptions.rb +34 -39
  252. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
  253. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  254. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  255. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +24 -12
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  260. data/lib/graphql/tracing.rb +2 -2
  261. data/lib/graphql/types/big_int.rb +5 -1
  262. data/lib/graphql/types/int.rb +10 -3
  263. data/lib/graphql/types/iso_8601_date.rb +13 -5
  264. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  265. data/lib/graphql/types/relay/base_connection.rb +6 -91
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  268. data/lib/graphql/types/relay/default_relay.rb +31 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  270. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  271. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  272. data/lib/graphql/types/relay/node.rb +2 -4
  273. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  274. data/lib/graphql/types/relay/node_field.rb +3 -22
  275. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -3
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +1 -1
  281. data/lib/graphql/union_type.rb +3 -1
  282. data/lib/graphql/upgrader/member.rb +1 -0
  283. data/lib/graphql/upgrader/schema.rb +1 -0
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +68 -37
  286. data/readme.md +3 -6
  287. metadata +83 -113
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/types/relay/base_field.rb +0 -22
  290. data/lib/graphql/types/relay/base_interface.rb +0 -29
  291. data/lib/graphql/types/relay/base_object.rb +0 -26
  292. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  293. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b6e1d6fb5063c843becb61784cb776964a380af5a2fc5a98054d2554ddf4caa
4
- data.tar.gz: c41027cdf69f8c07bed157075c70e95936f3d26922f0b1d38f7759352a35ab43
3
+ metadata.gz: c21327429549138738debab2d522197133548eb4b275a5f67086154e08469149
4
+ data.tar.gz: ec61107f4f45aaf1de25c6674d7fcf3b8e19b1245fdbf2a1bd1b0f7f1dd9b0aa
5
5
  SHA512:
6
- metadata.gz: 3dc4e13b30d51c32775785b9ed4a11940bc2cb541866877e6eef48bc621956700ddf057c597d2bc5a9fa09ca863e01ba84295e414e488e22ee03b94c28bc4003
7
- data.tar.gz: 70f5ba8c04e13b83af431db1e8edea297a3c43acc6f6356668094349b577fe7de4e8cdb029aaf8ce70cc243664915ac7dac38612badd0acb720ce57464769cec
6
+ metadata.gz: 5b56c3aaa86b6d758b53d49a7906de483375c54f40db9126b96d791f41c7bba6407d9b59205a4d47215cef1391cd5ebbc03d5eb76825747cbfc1d0f6baf1f0ef
7
+ data.tar.gz: 7f7cb3b2e4fa8c26b355ea4adf01803ab32e2d97036475469071e2cf67d06431ab0486f0daf8ab28433deb95bb8642ea0a2b52739abe6d0ad06bb22b4fdcb2cc
@@ -19,17 +19,12 @@ module Graphql
19
19
  sentinel = /< GraphQL::Schema\s*\n/m
20
20
 
21
21
  in_root do
22
- inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
22
+ if File.exist?(schema_file_path)
23
+ inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
24
+ end
23
25
  end
24
26
  end
25
27
 
26
- def create_mutation_root_type
27
- create_dir("#{options[:directory]}/mutations")
28
- template("base_mutation.erb", "#{options[:directory]}/mutations/base_mutation.rb", { skip: true })
29
- template("mutation_type.erb", "#{options[:directory]}/types/mutation_type.rb", { skip: true })
30
- insert_root_type('mutation', 'MutationType')
31
- end
32
-
33
28
  def schema_file_path
34
29
  "#{options[:directory]}/#{schema_name.underscore}.rb"
35
30
  end
@@ -13,20 +13,14 @@ module Graphql
13
13
  desc "Create a GraphQL::EnumType with the given name and values"
14
14
  source_root File.expand_path('../templates', __FILE__)
15
15
 
16
- argument :values,
17
- type: :array,
18
- default: [],
19
- banner: "value{:ruby_value} value{:ruby_value} ...",
20
- desc: "Values for this enum (if present, ruby_value will be inserted verbatim)"
16
+ private
21
17
 
22
- def create_type_file
23
- template "enum.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
18
+ def graphql_type
19
+ "enum"
24
20
  end
25
21
 
26
- private
27
-
28
22
  def prepared_values
29
- values.map { |v| v.split(":", 2) }
23
+ custom_fields.map { |v| v.split(":", 2) }
30
24
  end
31
25
  end
32
26
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ module FieldExtractor
7
+ def fields
8
+ columns = []
9
+ columns += (klass&.columns&.map { |c| generate_column_string(c) } || [])
10
+ columns + custom_fields
11
+ end
12
+
13
+ def generate_column_string(column)
14
+ name = column.name
15
+ required = column.null ? "" : "!"
16
+ type = column_type_string(column)
17
+ "#{name}:#{required}#{type}"
18
+ end
19
+
20
+ def column_type_string(column)
21
+ column.name == "id" ? "ID" : column.type.to_s.camelize
22
+ end
23
+
24
+ def klass
25
+ @klass ||= Module.const_get(name.camelize)
26
+ rescue NameError
27
+ @klass = nil
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ require 'generators/graphql/type_generator'
3
+ require 'generators/graphql/field_extractor'
4
+
5
+ module Graphql
6
+ module Generators
7
+ # Generate an input type by name,
8
+ # with the specified fields.
9
+ #
10
+ # ```
11
+ # rails g graphql:object PostType name:string!
12
+ # ```
13
+ class InputGenerator < TypeGeneratorBase
14
+ desc "Create a GraphQL::InputObjectType with the given name and fields"
15
+ source_root File.expand_path('../templates', __FILE__)
16
+ include FieldExtractor
17
+
18
+ def self.normalize_type_expression(type_expression, mode:, null: true)
19
+ case type_expression.camelize
20
+ when "Text", "Citext"
21
+ ["String", null]
22
+ when "Decimal"
23
+ ["Float", null]
24
+ when "DateTime", "Datetime"
25
+ ["GraphQL::Types::ISO8601DateTime", null]
26
+ when "Date"
27
+ ["GraphQL::Types::ISO8601Date", null]
28
+ when "Json", "Jsonb", "Hstore"
29
+ ["GraphQL::Types::JSON", null]
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def graphql_type
38
+ "input"
39
+ end
40
+
41
+ def type_ruby_name
42
+ super.gsub(/Type\z/, "InputType")
43
+ end
44
+
45
+ def type_file_name
46
+ super.gsub(/_type\z/, "_input_type")
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require_relative "../core"
5
+
6
+ module Graphql
7
+ module Generators
8
+ module Install
9
+ class MutationRootGenerator < Rails::Generators::Base
10
+ include Core
11
+
12
+ desc "Create mutation base type, mutation root tipe, and adds the latter to the schema"
13
+ source_root File.expand_path('../templates', __FILE__)
14
+
15
+ class_option :schema,
16
+ type: :string,
17
+ default: nil,
18
+ desc: "Name for the schema constant (default: {app_name}Schema)"
19
+
20
+ class_option :skip_keeps,
21
+ type: :boolean,
22
+ default: false,
23
+ desc: "Skip .keep files for source control"
24
+
25
+ def generate
26
+ create_dir("#{options[:directory]}/mutations")
27
+ template("base_mutation.erb", "#{options[:directory]}/mutations/base_mutation.rb", { skip: true })
28
+ template("mutation_type.erb", "#{options[:directory]}/types/mutation_type.rb", { skip: true })
29
+ insert_root_type('mutation', 'MutationType')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+ require 'rails/generators'
2
3
  require 'rails/generators/base'
3
4
  require_relative 'core'
5
+ require_relative 'relay'
4
6
 
5
7
  module Graphql
6
8
  module Generators
@@ -43,9 +45,6 @@ module Graphql
43
45
  # post "/graphql", to: "graphql#execute"
44
46
  # ```
45
47
  #
46
- # Accept a `--relay` option which adds
47
- # The root `node(id: ID!)` field.
48
- #
49
48
  # Accept a `--batch` option which adds `GraphQL::Batch` setup.
50
49
  #
51
50
  # Use `--no-graphiql` to skip `graphiql-rails` installation.
@@ -53,6 +52,7 @@ module Graphql
53
52
  # TODO: also add base classes
54
53
  class InstallGenerator < Rails::Generators::Base
55
54
  include Core
55
+ include Relay
56
56
 
57
57
  desc "Install GraphQL folder structure and boilerplate code"
58
58
  source_root File.expand_path('../templates', __FILE__)
@@ -79,8 +79,8 @@ module Graphql
79
79
 
80
80
  class_option :relay,
81
81
  type: :boolean,
82
- default: false,
83
- desc: "Include GraphQL::Relay installation"
82
+ default: true,
83
+ desc: "Include installation of Relay conventions (nodes, connections, edges)"
84
84
 
85
85
  class_option :batch,
86
86
  type: :boolean,
@@ -109,7 +109,7 @@ module Graphql
109
109
  template("query_type.erb", "#{options[:directory]}/types/query_type.rb")
110
110
  insert_root_type('query', 'QueryType')
111
111
 
112
- create_mutation_root_type unless options.skip_mutation_root_type?
112
+ invoke "graphql:install:mutation_root" unless options.skip_mutation_root_type?
113
113
 
114
114
  template("graphql_controller.erb", "app/controllers/graphql_controller.rb")
115
115
  route('post "/graphql", to: "graphql#execute"')
@@ -123,7 +123,14 @@ module Graphql
123
123
  say("Skipped graphiql, as this rails project is API only")
124
124
  say(" You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app")
125
125
  elsif !options[:skip_graphiql]
126
- gem("graphiql-rails", group: :development)
126
+ # `gem(...)` uses `gsub_file(...)` under the hood, which is a no-op for `rails destroy...` (when `behavior == :revoke`).
127
+ # So handle that case by calling `gsub_file` with `force: true`.
128
+ if behavior == :invoke && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
129
+ gem("graphiql-rails", group: :development)
130
+ elsif behavior == :revoke
131
+ gemfile_pattern = /\n\s*gem ('|")graphiql-rails('|"), :?group(:| =>) :development/
132
+ gsub_file Rails.root.join("Gemfile"), gemfile_pattern, "", { force: true }
133
+ end
127
134
 
128
135
  # This is a little cheat just to get cleaner shell output:
129
136
  log :route, 'graphiql-rails'
@@ -164,7 +171,10 @@ if Rails.env.development?
164
171
  RUBY
165
172
  end
166
173
  end
174
+ end
167
175
 
176
+ if options[:relay]
177
+ install_relay
168
178
  end
169
179
 
170
180
  if gemfile_modified?
@@ -13,14 +13,14 @@ module Graphql
13
13
  desc "Create a GraphQL::InterfaceType with the given name and fields"
14
14
  source_root File.expand_path('../templates', __FILE__)
15
15
 
16
- argument :fields,
17
- type: :array,
18
- default: [],
19
- banner: "name:type name:type ...",
20
- desc: "Fields for this interface (type may be expressed as Ruby or GraphQL)"
16
+ private
21
17
 
22
- def create_type_file
23
- template "interface.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
18
+ def graphql_type
19
+ "interface"
20
+ end
21
+
22
+ def fields
23
+ custom_fields
24
24
  end
25
25
  end
26
26
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'rails/generators'
2
3
  require "rails/generators/named_base"
3
4
  require_relative "core"
4
5
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'orm_mutations_base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # TODO: What other options should be supported?
7
+ #
8
+ # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
9
+ # rails g graphql:mutation CreatePostMutation
10
+ class MutationCreateGenerator < OrmMutationsBase
11
+
12
+ desc "Scaffold a Relay Classic ORM create mutation for the given model class"
13
+ source_root File.expand_path('../templates', __FILE__)
14
+
15
+ private
16
+
17
+ def operation_type
18
+ "create"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'orm_mutations_base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # TODO: What other options should be supported?
7
+ #
8
+ # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
9
+ # rails g graphql:mutation CreatePostMutation
10
+ class MutationDeleteGenerator < OrmMutationsBase
11
+
12
+ desc "Scaffold a Relay Classic ORM delete mutation for the given model class"
13
+ source_root File.expand_path('../templates', __FILE__)
14
+
15
+ private
16
+
17
+ def operation_type
18
+ "delete"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'rails/generators'
2
3
  require 'rails/generators/named_base'
3
4
  require_relative 'core'
4
5
 
@@ -8,47 +9,22 @@ module Graphql
8
9
  #
9
10
  # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
10
11
  # rails g graphql:mutation CreatePostMutation
11
- class MutationGenerator < Rails::Generators::Base
12
+ class MutationGenerator < Rails::Generators::NamedBase
12
13
  include Core
13
14
 
14
15
  desc "Create a Relay Classic mutation by name"
15
16
  source_root File.expand_path('../templates', __FILE__)
16
17
 
17
- argument :name, type: :string
18
-
19
- def initialize(args, *options) #:nodoc:
20
- # Unfreeze name in case it's given as a frozen string
21
- args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
22
- super
23
-
24
- assign_names!(name)
25
- end
26
-
27
- attr_reader :file_name, :mutation_name, :field_name
28
-
29
18
  def create_mutation_file
30
- unless @behavior == :revoke
31
- create_mutation_root_type
32
- else
33
- log :gsub, "#{options[:directory]}/types/mutation_type.rb"
34
- end
35
-
36
- template "mutation.erb", "#{options[:directory]}/mutations/#{file_name}.rb"
19
+ template "mutation.erb", File.join(options[:directory], "/mutations/", class_path, "#{file_name}.rb")
37
20
 
38
21
  sentinel = /class .*MutationType\s*<\s*[^\s]+?\n/m
39
22
  in_root do
40
- gsub_file "#{options[:directory]}/types/mutation_type.rb", / \# TODO\: Add Mutations as fields\s*\n/m, ""
41
- inject_into_file "#{options[:directory]}/types/mutation_type.rb", " field :#{field_name}, mutation: Mutations::#{mutation_name}\n", after: sentinel, verbose: false, force: false
23
+ path = "#{options[:directory]}/types/mutation_type.rb"
24
+ invoke "graphql:install:mutation_root" unless File.exist?(path)
25
+ inject_into_file "#{options[:directory]}/types/mutation_type.rb", " field :#{file_name}, mutation: Mutations::#{class_name}\n", after: sentinel, verbose: false, force: false
42
26
  end
43
27
  end
44
-
45
- private
46
-
47
- def assign_names!(name)
48
- @field_name = name.camelize.underscore
49
- @mutation_name = name.camelize(:upper)
50
- @file_name = name.camelize.underscore
51
- end
52
28
  end
53
29
  end
54
30
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'orm_mutations_base'
3
+
4
+ module Graphql
5
+ module Generators
6
+ # TODO: What other options should be supported?
7
+ #
8
+ # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
9
+ # rails g graphql:mutation CreatePostMutation
10
+ class MutationUpdateGenerator < OrmMutationsBase
11
+
12
+ desc "Scaffold a Relay Classic ORM update mutation for the given model class"
13
+ source_root File.expand_path('../templates', __FILE__)
14
+
15
+ private
16
+
17
+ def operation_type
18
+ "update"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'generators/graphql/type_generator'
3
+ require 'generators/graphql/field_extractor'
3
4
 
4
5
  module Graphql
5
6
  module Generators
@@ -12,38 +13,28 @@ module Graphql
12
13
  #
13
14
  # Add the Node interface with `--node`.
14
15
  class ObjectGenerator < TypeGeneratorBase
15
- desc "Create a GraphQL::ObjectType with the given name and fields"
16
+ desc "Create a GraphQL::ObjectType with the given name and fields." \
17
+ "If the given type name matches an existing ActiveRecord model, the generated type will automatically include fields for the models database columns."
16
18
  source_root File.expand_path('../templates', __FILE__)
17
-
18
- argument :custom_fields,
19
- type: :array,
20
- default: [],
21
- banner: "name:type name:type ...",
22
- desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
19
+ include FieldExtractor
23
20
 
24
21
  class_option :node,
25
22
  type: :boolean,
26
23
  default: false,
27
24
  desc: "Include the Relay Node interface"
28
25
 
29
- def create_type_file
30
- template "object.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
31
- end
32
-
33
- def fields
34
- columns = []
35
- columns += klass.columns.map { |c| generate_column_string(c) } if class_exists?
36
- columns + custom_fields
37
- end
38
-
39
26
  def self.normalize_type_expression(type_expression, mode:, null: true)
40
- case type_expression
41
- when "Text"
27
+ case type_expression.camelize
28
+ when "Text", "Citext"
42
29
  ["String", null]
30
+ when "Decimal"
31
+ ["Float", null]
43
32
  when "DateTime", "Datetime"
44
33
  ["GraphQL::Types::ISO8601DateTime", null]
45
34
  when "Date"
46
35
  ["GraphQL::Types::ISO8601Date", null]
36
+ when "Json", "Jsonb", "Hstore"
37
+ ["GraphQL::Types::JSON", null]
47
38
  else
48
39
  super
49
40
  end
@@ -51,25 +42,8 @@ module Graphql
51
42
 
52
43
  private
53
44
 
54
- def generate_column_string(column)
55
- name = column.name
56
- required = column.null ? "" : "!"
57
- type = column_type_string(column)
58
- "#{name}:#{required}#{type}"
59
- end
60
-
61
- def column_type_string(column)
62
- column.name == "id" ? "ID" : column.type.to_s.camelize
63
- end
64
-
65
- def class_exists?
66
- klass.is_a?(Class) && klass.ancestors.include?(ActiveRecord::Base)
67
- rescue NameError
68
- return false
69
- end
70
-
71
- def klass
72
- @klass ||= Module.const_get(type_name.camelize)
45
+ def graphql_type
46
+ "object"
73
47
  end
74
48
  end
75
49
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators'
3
+ require 'rails/generators/named_base'
4
+ require_relative 'core'
5
+
6
+ module Graphql
7
+ module Generators
8
+ # TODO: What other options should be supported?
9
+ #
10
+ # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
11
+ # rails g graphql:mutation CreatePostMutation
12
+ class OrmMutationsBase < Rails::Generators::NamedBase
13
+ include Core
14
+ include Rails::Generators::ResourceHelpers
15
+
16
+ desc "Create a Relay Classic mutation by name"
17
+
18
+ class_option :orm, banner: "NAME", type: :string, required: true,
19
+ desc: "ORM to generate the controller for"
20
+
21
+ class_option 'namespaced_types',
22
+ type: :boolean,
23
+ required: false,
24
+ default: false,
25
+ banner: "Namespaced",
26
+ desc: "If the generated types will be namespaced"
27
+
28
+ def create_mutation_file
29
+ template "mutation_#{operation_type}.erb", File.join(options[:directory], "/mutations/", class_path, "#{file_name}_#{operation_type}.rb")
30
+
31
+ sentinel = /class .*MutationType\s*<\s*[^\s]+?\n/m
32
+ in_root do
33
+ path = "#{options[:directory]}/types/mutation_type.rb"
34
+ invoke "graphql:install:mutation_root" unless File.exist?(path)
35
+ inject_into_file "#{options[:directory]}/types/mutation_type.rb", " field :#{file_name}_#{operation_type}, mutation: Mutations::#{class_name}#{operation_type.classify}\n", after: sentinel, verbose: false, force: false
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ module Graphql
3
+ module Generators
4
+ module Relay
5
+ def install_relay
6
+ # Add Node, `node(id:)`, and `nodes(ids:)`
7
+ template("node_type.erb", "#{options[:directory]}/types/node_type.rb")
8
+ in_root do
9
+ fields = " # Add `node(id: ID!) and `nodes(ids: [ID!]!)`\n include GraphQL::Types::Relay::HasNodeField\n include GraphQL::Types::Relay::HasNodesField\n\n"
10
+ inject_into_file "#{options[:directory]}/types/query_type.rb", fields, after: /class .*QueryType\s*<\s*[^\s]+?\n/m, force: false
11
+ end
12
+
13
+ # Add connections and edges
14
+ template("base_connection.erb", "#{options[:directory]}/types/base_connection.rb")
15
+ template("base_edge.erb", "#{options[:directory]}/types/base_edge.rb")
16
+ connectionable_type_files = {
17
+ "#{options[:directory]}/types/base_object.rb" => /class .*BaseObject\s*<\s*[^\s]+?\n/m,
18
+ "#{options[:directory]}/types/base_union.rb" => /class .*BaseUnion\s*<\s*[^\s]+?\n/m,
19
+ "#{options[:directory]}/types/base_interface.rb" => /include GraphQL::Schema::Interface\n/m,
20
+ }
21
+ in_root do
22
+ connectionable_type_files.each do |type_class_file, sentinel|
23
+ inject_into_file type_class_file, " connection_type_class(Types::BaseConnection)\n", after: sentinel, force: false
24
+ inject_into_file type_class_file, " edge_type_class(Types::BaseEdge)\n", after: sentinel, force: false
25
+ end
26
+ end
27
+
28
+ # Add object ID hooks & connection plugin
29
+ schema_code = <<-RUBY
30
+
31
+ # Relay-style Object Identification:
32
+
33
+ # Return a string UUID for `object`
34
+ def self.id_from_object(object, type_definition, query_ctx)
35
+ # For example, use Rails' GlobalID library (https://github.com/rails/globalid):
36
+ object_id = object.to_global_id.to_s
37
+ # Remove this redundant prefix to make IDs shorter:
38
+ object_id = object_id.sub("gid://\#{GlobalID.app}/", "")
39
+ encoded_id = Base64.urlsafe_encode64(object_id)
40
+ # Remove the "=" padding
41
+ encoded_id = encoded_id.sub(/=+/, "")
42
+ # Add a type hint
43
+ type_hint = type_definition.graphql_name.first
44
+ "\#{type_hint}_\#{encoded_id}"
45
+ end
46
+
47
+ # Given a string UUID, find the object
48
+ def self.object_from_id(encoded_id_with_hint, query_ctx)
49
+ # For example, use Rails' GlobalID library (https://github.com/rails/globalid):
50
+ # Split off the type hint
51
+ _type_hint, encoded_id = encoded_id_with_hint.split("_", 2)
52
+ # Decode the ID
53
+ id = Base64.urlsafe_decode64(encoded_id)
54
+ # Rebuild it for Rails then find the object:
55
+ full_global_id = "gid://\#{GlobalID.app}/\#{id}"
56
+ GlobalID::Locator.locate(full_global_id)
57
+ end
58
+ RUBY
59
+ inject_into_file schema_file_path, schema_code, before: /^end\n/m, force: false
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators'
3
+ require 'rails/generators/base'
4
+ require_relative 'core'
5
+ require_relative 'relay'
6
+
7
+ module Graphql
8
+ module Generators
9
+ class RelayGenerator < Rails::Generators::Base
10
+ include Core
11
+ include Relay
12
+
13
+ desc "Add base types and fields for Relay-style nodes and connections"
14
+ source_root File.expand_path('../templates', __FILE__)
15
+
16
+ def install_relay
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -12,8 +12,10 @@ module Graphql
12
12
  desc "Create a GraphQL::ScalarType with the given name"
13
13
  source_root File.expand_path('../templates', __FILE__)
14
14
 
15
- def create_type_file
16
- template "scalar.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
15
+ private
16
+
17
+ def graphql_type
18
+ "scalar"
17
19
  end
18
20
  end
19
21
  end
@@ -0,0 +1,8 @@
1
+ <% module_namespacing_when_supported do -%>
2
+ module Types
3
+ class BaseConnection < Types::BaseObject
4
+ # add `nodes` and `pageInfo` fields, as well as `edge_type(...)` and `node_nullable(...)` overrides
5
+ include GraphQL::Types::Relay::ConnectionBehaviors
6
+ end
7
+ end
8
+ <% end -%>
@@ -0,0 +1,8 @@
1
+ <% module_namespacing_when_supported do -%>
2
+ module Types
3
+ class BaseEdge < Types::BaseObject
4
+ # add `node` and `cursor` fields, as well as `node_type(...)` override
5
+ include GraphQL::Types::Relay::EdgeBehaviors
6
+ end
7
+ end
8
+ <% end -%>
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  <% module_namespacing_when_supported do -%>
2
4
  module Types
3
- class <%= type_ruby_name.split('::')[-1] %> < Types::BaseEnum
5
+ class <%= ruby_class_name %> < Types::BaseEnum
6
+ description "<%= human_name %> enum"
7
+
4
8
  <% prepared_values.each do |v| %> value "<%= v[0] %>"<%= v.length > 1 ? ", value: #{v[1]}" : "" %>
5
9
  <% end %> end
6
10
  end