rails-graphql 0.2.1 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (315) hide show
  1. checksums.yaml +4 -4
  2. data/ext/console.rb +18 -0
  3. data/ext/extconf.h +3 -0
  4. data/ext/extconf.rb +1 -54
  5. data/ext/gql_parser.c +631 -0
  6. data/ext/gql_parser.h +21 -0
  7. data/ext/shared.c +477 -0
  8. data/ext/shared.h +177 -0
  9. data/lib/generators/graphql/channel_generator.rb +27 -0
  10. data/lib/generators/graphql/controller_generator.rb +9 -4
  11. data/lib/generators/graphql/install_generator.rb +49 -0
  12. data/lib/generators/graphql/schema_generator.rb +9 -4
  13. data/lib/generators/graphql/templates/channel.erb +7 -0
  14. data/lib/generators/graphql/templates/config.rb +97 -0
  15. data/lib/generators/graphql/templates/controller.erb +2 -0
  16. data/lib/generators/graphql/templates/schema.erb +5 -3
  17. data/lib/gql_parser.so +0 -0
  18. data/lib/rails/graphql/adapters/mysql_adapter.rb +59 -0
  19. data/lib/rails/graphql/adapters/pg_adapter.rb +25 -22
  20. data/lib/rails/graphql/adapters/sqlite_adapter.rb +17 -14
  21. data/lib/rails/graphql/alternative/field_set.rb +48 -0
  22. data/lib/rails/graphql/alternative/mutation.rb +17 -0
  23. data/lib/rails/graphql/alternative/query.rb +98 -0
  24. data/lib/rails/graphql/alternative/subscription.rb +18 -0
  25. data/lib/rails/graphql/alternative.rb +20 -0
  26. data/lib/rails/graphql/argument.rb +25 -26
  27. data/lib/rails/graphql/callback.rb +30 -14
  28. data/lib/rails/graphql/collectors/hash_collector.rb +26 -7
  29. data/lib/rails/graphql/collectors/idented_collector.rb +10 -7
  30. data/lib/rails/graphql/collectors/json_collector.rb +43 -17
  31. data/lib/rails/graphql/collectors.rb +4 -4
  32. data/lib/rails/graphql/config.rb +154 -23
  33. data/lib/rails/graphql/directive/cached_directive.rb +33 -0
  34. data/lib/rails/graphql/directive/deprecated_directive.rb +10 -10
  35. data/lib/rails/graphql/directive/include_directive.rb +4 -4
  36. data/lib/rails/graphql/directive/skip_directive.rb +4 -4
  37. data/lib/rails/graphql/directive/specified_by_directive.rb +24 -0
  38. data/lib/rails/graphql/directive.rb +134 -73
  39. data/lib/rails/graphql/errors.rb +33 -4
  40. data/lib/rails/graphql/event.rb +21 -9
  41. data/lib/rails/graphql/field/authorized_field.rb +17 -6
  42. data/lib/rails/graphql/field/input_field.rb +8 -12
  43. data/lib/rails/graphql/field/mutation_field.rb +43 -9
  44. data/lib/rails/graphql/field/output_field.rb +112 -12
  45. data/lib/rails/graphql/field/proxied_field.rb +35 -26
  46. data/lib/rails/graphql/field/resolved_field.rb +27 -25
  47. data/lib/rails/graphql/field/scoped_config.rb +10 -4
  48. data/lib/rails/graphql/field/subscription_field.rb +123 -0
  49. data/lib/rails/graphql/field/typed_field.rb +69 -24
  50. data/lib/rails/graphql/field.rb +89 -74
  51. data/lib/rails/graphql/global_id.rb +89 -0
  52. data/lib/rails/graphql/helpers/attribute_delegator.rb +5 -5
  53. data/lib/rails/graphql/helpers/inherited_collection/array.rb +51 -0
  54. data/lib/rails/graphql/helpers/inherited_collection/base.rb +45 -0
  55. data/lib/rails/graphql/helpers/inherited_collection/hash.rb +88 -0
  56. data/lib/rails/graphql/helpers/inherited_collection.rb +25 -76
  57. data/lib/rails/graphql/helpers/instantiable.rb +15 -0
  58. data/lib/rails/graphql/helpers/leaf_from_ar.rb +7 -7
  59. data/lib/rails/graphql/helpers/registerable.rb +44 -62
  60. data/lib/rails/graphql/helpers/unregisterable.rb +16 -0
  61. data/lib/rails/graphql/helpers/with_arguments.rb +33 -28
  62. data/lib/rails/graphql/helpers/with_assignment.rb +6 -6
  63. data/lib/rails/graphql/helpers/with_callbacks.rb +28 -11
  64. data/lib/rails/graphql/helpers/with_description.rb +73 -0
  65. data/lib/rails/graphql/helpers/with_directives.rb +58 -30
  66. data/lib/rails/graphql/helpers/with_events.rb +22 -23
  67. data/lib/rails/graphql/helpers/with_fields.rb +86 -26
  68. data/lib/rails/graphql/helpers/with_global_id.rb +22 -0
  69. data/lib/rails/graphql/helpers/with_name.rb +44 -0
  70. data/lib/rails/graphql/helpers/with_namespace.rb +7 -4
  71. data/lib/rails/graphql/helpers/with_owner.rb +8 -7
  72. data/lib/rails/graphql/helpers/with_schema_fields.rb +162 -56
  73. data/lib/rails/graphql/helpers/with_validator.rb +9 -9
  74. data/lib/rails/graphql/helpers.rb +10 -3
  75. data/lib/rails/graphql/introspection.rb +43 -36
  76. data/lib/rails/graphql/railtie.rb +89 -33
  77. data/lib/rails/graphql/railties/app/base_channel.rb +10 -0
  78. data/lib/rails/graphql/railties/app/base_controller.rb +12 -0
  79. data/lib/rails/graphql/railties/app/views/_cable.js.erb +56 -0
  80. data/lib/rails/graphql/railties/app/views/_fetch.js.erb +20 -0
  81. data/lib/rails/graphql/railties/app/views/graphiql.html.erb +101 -0
  82. data/lib/rails/graphql/railties/base_generator.rb +5 -17
  83. data/lib/rails/graphql/railties/channel.rb +157 -0
  84. data/lib/rails/graphql/railties/controller.rb +91 -25
  85. data/lib/rails/graphql/railties/controller_runtime.rb +5 -5
  86. data/lib/rails/graphql/railties/log_subscriber.rb +81 -14
  87. data/lib/rails/graphql/request/arguments.rb +26 -50
  88. data/lib/rails/graphql/request/backtrace.rb +212 -0
  89. data/lib/rails/graphql/request/component/field.rb +98 -70
  90. data/lib/rails/graphql/request/component/fragment.rb +80 -26
  91. data/lib/rails/graphql/request/component/operation/subscription.rb +162 -4
  92. data/lib/rails/graphql/request/component/operation.rb +73 -34
  93. data/lib/rails/graphql/request/component/spread.rb +79 -27
  94. data/lib/rails/graphql/request/component/typename.rb +28 -13
  95. data/lib/rails/graphql/request/component.rb +77 -36
  96. data/lib/rails/graphql/request/context.rb +19 -9
  97. data/lib/rails/graphql/request/errors.rb +16 -6
  98. data/lib/rails/graphql/request/event.rb +23 -8
  99. data/lib/rails/graphql/request/helpers/directives.rb +69 -27
  100. data/lib/rails/graphql/request/helpers/selection_set.rb +57 -25
  101. data/lib/rails/graphql/request/helpers/value_writers.rb +24 -19
  102. data/lib/rails/graphql/request/prepared_data.rb +100 -0
  103. data/lib/rails/graphql/request/steps/authorizable.rb +24 -14
  104. data/lib/rails/graphql/request/steps/organizable.rb +111 -49
  105. data/lib/rails/graphql/request/steps/{prepareable.rb → preparable.rb} +21 -8
  106. data/lib/rails/graphql/request/steps/{resolveable.rb → resolvable.rb} +16 -7
  107. data/lib/rails/graphql/request/strategy/cached_strategy.rb +64 -0
  108. data/lib/rails/graphql/request/strategy/dynamic_instance.rb +6 -6
  109. data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +6 -13
  110. data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +9 -9
  111. data/lib/rails/graphql/request/strategy.rb +147 -77
  112. data/lib/rails/graphql/request/subscription.rb +82 -0
  113. data/lib/rails/graphql/request.rb +353 -104
  114. data/lib/rails/graphql/schema.rb +251 -106
  115. data/lib/rails/graphql/shortcuts.rb +33 -8
  116. data/lib/rails/graphql/source/active_record/builders.rb +64 -51
  117. data/lib/rails/graphql/source/active_record_source.rb +158 -82
  118. data/lib/rails/graphql/source/base.rb +83 -0
  119. data/lib/rails/graphql/source/builder.rb +115 -0
  120. data/lib/rails/graphql/source/scoped_arguments.rb +39 -21
  121. data/lib/rails/graphql/source.rb +90 -228
  122. data/lib/rails/graphql/subscription/provider/action_cable.rb +113 -0
  123. data/lib/rails/graphql/subscription/provider/base.rb +192 -0
  124. data/lib/rails/graphql/subscription/provider.rb +18 -0
  125. data/lib/rails/graphql/subscription/store/base.rb +141 -0
  126. data/lib/rails/graphql/subscription/store/memory.rb +136 -0
  127. data/lib/rails/graphql/subscription/store.rb +19 -0
  128. data/lib/rails/graphql/subscription.rb +17 -0
  129. data/lib/rails/graphql/to_gql.rb +29 -32
  130. data/lib/rails/graphql/type/creator.rb +196 -0
  131. data/lib/rails/graphql/type/enum/directive_location_enum.rb +11 -11
  132. data/lib/rails/graphql/type/enum/type_kind_enum.rb +3 -3
  133. data/lib/rails/graphql/type/enum.rb +44 -50
  134. data/lib/rails/graphql/type/input.rb +92 -25
  135. data/lib/rails/graphql/type/interface.rb +29 -28
  136. data/lib/rails/graphql/type/object/directive_object.rb +10 -9
  137. data/lib/rails/graphql/type/object/enum_value_object.rb +3 -3
  138. data/lib/rails/graphql/type/object/field_object.rb +24 -6
  139. data/lib/rails/graphql/type/object/input_value_object.rb +6 -7
  140. data/lib/rails/graphql/type/object/schema_object.rb +5 -8
  141. data/lib/rails/graphql/type/object/type_object.rb +62 -25
  142. data/lib/rails/graphql/type/object.rb +34 -26
  143. data/lib/rails/graphql/type/scalar/any_scalar.rb +30 -0
  144. data/lib/rails/graphql/type/scalar/bigint_scalar.rb +5 -5
  145. data/lib/rails/graphql/type/scalar/binary_scalar.rb +5 -3
  146. data/lib/rails/graphql/type/scalar/boolean_scalar.rb +8 -8
  147. data/lib/rails/graphql/type/scalar/date_scalar.rb +5 -3
  148. data/lib/rails/graphql/type/scalar/date_time_scalar.rb +5 -3
  149. data/lib/rails/graphql/type/scalar/decimal_scalar.rb +5 -3
  150. data/lib/rails/graphql/type/scalar/float_scalar.rb +5 -5
  151. data/lib/rails/graphql/type/scalar/id_scalar.rb +6 -5
  152. data/lib/rails/graphql/type/scalar/int_scalar.rb +6 -5
  153. data/lib/rails/graphql/type/scalar/json_scalar.rb +41 -0
  154. data/lib/rails/graphql/type/scalar/string_scalar.rb +18 -4
  155. data/lib/rails/graphql/type/scalar/time_scalar.rb +8 -6
  156. data/lib/rails/graphql/type/scalar.rb +26 -23
  157. data/lib/rails/graphql/type/union.rb +21 -18
  158. data/lib/rails/graphql/type.rb +43 -26
  159. data/lib/rails/graphql/type_map.rb +268 -165
  160. data/lib/rails/graphql/uri.rb +167 -0
  161. data/lib/rails/graphql/version.rb +19 -3
  162. data/lib/rails/graphql.rake +3 -0
  163. data/lib/rails/graphql.rb +91 -56
  164. data/lib/rails-graphql.rb +1 -1
  165. data/test/assets/en.yml +29 -0
  166. data/test/assets/introspection-mem.txt +1 -1
  167. data/test/assets/introspection.gql +2 -0
  168. data/test/assets/mem.gql +86 -99
  169. data/test/assets/mysql.gql +406 -0
  170. data/test/assets/sqlite.gql +96 -73
  171. data/test/assets/translate.gql +346 -0
  172. data/test/config.rb +19 -8
  173. data/test/graphql/schema_test.rb +14 -50
  174. data/test/graphql/source_test.rb +8 -85
  175. data/test/graphql/type/enum_test.rb +207 -203
  176. data/test/graphql/type/input_test.rb +14 -9
  177. data/test/graphql/type/interface_test.rb +12 -9
  178. data/test/graphql/type/object_test.rb +8 -2
  179. data/test/graphql/type/scalar/any_scalar_test.rb +38 -0
  180. data/test/graphql/type/scalar/boolean_scalar_test.rb +6 -3
  181. data/test/graphql/type/scalar/json_scalar_test.rb +23 -0
  182. data/test/graphql/type_map_test.rb +63 -81
  183. data/test/graphql/type_test.rb +0 -19
  184. data/test/graphql_test.rb +1 -1
  185. data/test/integration/{authorization/authorization_test.rb → authorization_test.rb} +40 -14
  186. data/test/integration/config.rb +36 -3
  187. data/test/integration/customization_test.rb +39 -0
  188. data/test/integration/global_id_test.rb +99 -0
  189. data/test/integration/memory/star_wars_introspection_test.rb +24 -16
  190. data/test/integration/memory/star_wars_query_test.rb +54 -3
  191. data/test/integration/memory/star_wars_validation_test.rb +3 -3
  192. data/test/integration/mysql/star_wars_introspection_test.rb +25 -0
  193. data/test/integration/persisted_query_test.rb +87 -0
  194. data/test/integration/resolver_precedence_test.rb +154 -0
  195. data/test/integration/schemas/memory.rb +24 -10
  196. data/test/integration/schemas/mysql.rb +62 -0
  197. data/test/integration/schemas/sqlite.rb +21 -12
  198. data/test/integration/sqlite/star_wars_global_id_test.rb +89 -0
  199. data/test/integration/sqlite/star_wars_introspection_test.rb +10 -0
  200. data/test/integration/sqlite/star_wars_query_test.rb +14 -1
  201. data/test/integration/translate_test.rb +73 -0
  202. data/test/test_ext.rb +16 -13
  203. metadata +125 -161
  204. data/ext/depend +0 -3
  205. data/ext/graphqlparser/Ast.cpp +0 -346
  206. data/ext/graphqlparser/Ast.h +0 -1214
  207. data/ext/graphqlparser/AstNode.h +0 -36
  208. data/ext/graphqlparser/AstVisitor.h +0 -137
  209. data/ext/graphqlparser/GraphQLParser.cpp +0 -76
  210. data/ext/graphqlparser/GraphQLParser.h +0 -55
  211. data/ext/graphqlparser/JsonVisitor.cpp +0 -161
  212. data/ext/graphqlparser/JsonVisitor.cpp.inc +0 -456
  213. data/ext/graphqlparser/JsonVisitor.h +0 -121
  214. data/ext/graphqlparser/JsonVisitor.h.inc +0 -110
  215. data/ext/graphqlparser/VERSION +0 -1
  216. data/ext/graphqlparser/c/GraphQLAst.cpp +0 -324
  217. data/ext/graphqlparser/c/GraphQLAst.h +0 -180
  218. data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +0 -44
  219. data/ext/graphqlparser/c/GraphQLAstNode.cpp +0 -25
  220. data/ext/graphqlparser/c/GraphQLAstNode.h +0 -33
  221. data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +0 -21
  222. data/ext/graphqlparser/c/GraphQLAstToJSON.h +0 -24
  223. data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +0 -55
  224. data/ext/graphqlparser/c/GraphQLAstVisitor.h +0 -53
  225. data/ext/graphqlparser/c/GraphQLParser.cpp +0 -35
  226. data/ext/graphqlparser/c/GraphQLParser.h +0 -54
  227. data/ext/graphqlparser/dump_json_ast.cpp +0 -48
  228. data/ext/graphqlparser/lexer.lpp +0 -324
  229. data/ext/graphqlparser/parser.ypp +0 -693
  230. data/ext/graphqlparser/parsergen/lexer.cpp +0 -2633
  231. data/ext/graphqlparser/parsergen/lexer.h +0 -528
  232. data/ext/graphqlparser/parsergen/location.hh +0 -189
  233. data/ext/graphqlparser/parsergen/parser.tab.cpp +0 -3300
  234. data/ext/graphqlparser/parsergen/parser.tab.hpp +0 -646
  235. data/ext/graphqlparser/parsergen/position.hh +0 -179
  236. data/ext/graphqlparser/parsergen/stack.hh +0 -156
  237. data/ext/graphqlparser/syntaxdefs.h +0 -19
  238. data/ext/libgraphqlparser/AstNode.h +0 -36
  239. data/ext/libgraphqlparser/CMakeLists.txt +0 -148
  240. data/ext/libgraphqlparser/CONTRIBUTING.md +0 -23
  241. data/ext/libgraphqlparser/GraphQLParser.cpp +0 -76
  242. data/ext/libgraphqlparser/GraphQLParser.h +0 -55
  243. data/ext/libgraphqlparser/JsonVisitor.cpp +0 -161
  244. data/ext/libgraphqlparser/JsonVisitor.h +0 -121
  245. data/ext/libgraphqlparser/LICENSE +0 -22
  246. data/ext/libgraphqlparser/README.clang-tidy +0 -7
  247. data/ext/libgraphqlparser/README.md +0 -84
  248. data/ext/libgraphqlparser/ast/ast.ast +0 -203
  249. data/ext/libgraphqlparser/ast/ast.py +0 -61
  250. data/ext/libgraphqlparser/ast/c.py +0 -100
  251. data/ext/libgraphqlparser/ast/c.pyc +0 -0
  252. data/ext/libgraphqlparser/ast/c_impl.py +0 -61
  253. data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
  254. data/ext/libgraphqlparser/ast/c_visitor_impl.py +0 -39
  255. data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
  256. data/ext/libgraphqlparser/ast/casing.py +0 -26
  257. data/ext/libgraphqlparser/ast/casing.pyc +0 -0
  258. data/ext/libgraphqlparser/ast/cxx.py +0 -197
  259. data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
  260. data/ext/libgraphqlparser/ast/cxx_impl.py +0 -61
  261. data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
  262. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +0 -42
  263. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
  264. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +0 -80
  265. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
  266. data/ext/libgraphqlparser/ast/cxx_visitor.py +0 -64
  267. data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
  268. data/ext/libgraphqlparser/ast/js.py +0 -65
  269. data/ext/libgraphqlparser/ast/license.py +0 -10
  270. data/ext/libgraphqlparser/ast/license.pyc +0 -0
  271. data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +0 -25
  272. data/ext/libgraphqlparser/c/GraphQLAstNode.h +0 -33
  273. data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +0 -21
  274. data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +0 -24
  275. data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +0 -55
  276. data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +0 -53
  277. data/ext/libgraphqlparser/c/GraphQLParser.cpp +0 -35
  278. data/ext/libgraphqlparser/c/GraphQLParser.h +0 -54
  279. data/ext/libgraphqlparser/clang-tidy-all.sh +0 -3
  280. data/ext/libgraphqlparser/cmake/version.cmake +0 -16
  281. data/ext/libgraphqlparser/dump_json_ast.cpp +0 -48
  282. data/ext/libgraphqlparser/go/README.md +0 -20
  283. data/ext/libgraphqlparser/go/callbacks.go +0 -18
  284. data/ext/libgraphqlparser/go/gotest.go +0 -64
  285. data/ext/libgraphqlparser/lexer.lpp +0 -324
  286. data/ext/libgraphqlparser/libgraphqlparser.pc.in +0 -11
  287. data/ext/libgraphqlparser/parser.ypp +0 -693
  288. data/ext/libgraphqlparser/parsergen/lexer.cpp +0 -2633
  289. data/ext/libgraphqlparser/parsergen/lexer.h +0 -528
  290. data/ext/libgraphqlparser/parsergen/location.hh +0 -189
  291. data/ext/libgraphqlparser/parsergen/parser.tab.cpp +0 -3300
  292. data/ext/libgraphqlparser/parsergen/parser.tab.hpp +0 -646
  293. data/ext/libgraphqlparser/parsergen/position.hh +0 -179
  294. data/ext/libgraphqlparser/parsergen/stack.hh +0 -156
  295. data/ext/libgraphqlparser/python/CMakeLists.txt +0 -14
  296. data/ext/libgraphqlparser/python/README.md +0 -5
  297. data/ext/libgraphqlparser/python/example.py +0 -31
  298. data/ext/libgraphqlparser/syntaxdefs.h +0 -19
  299. data/ext/libgraphqlparser/test/BuildCAPI.c +0 -5
  300. data/ext/libgraphqlparser/test/CMakeLists.txt +0 -25
  301. data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +0 -28
  302. data/ext/libgraphqlparser/test/ParserTests.cpp +0 -352
  303. data/ext/libgraphqlparser/test/kitchen-sink.graphql +0 -59
  304. data/ext/libgraphqlparser/test/kitchen-sink.json +0 -1
  305. data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +0 -78
  306. data/ext/libgraphqlparser/test/schema-kitchen-sink.json +0 -1
  307. data/ext/libgraphqlparser/test/valgrind.supp +0 -33
  308. data/ext/version.cpp +0 -21
  309. data/lib/graphqlparser.so +0 -0
  310. data/lib/rails/graphql/native/functions.rb +0 -38
  311. data/lib/rails/graphql/native/location.rb +0 -41
  312. data/lib/rails/graphql/native/pointers.rb +0 -23
  313. data/lib/rails/graphql/native/visitor.rb +0 -349
  314. data/lib/rails/graphql/native.rb +0 -56
  315. data/test/integration/schemas/authorization.rb +0 -12
@@ -3,8 +3,8 @@
3
3
  require 'arel/visitors/visitor'
4
4
 
5
5
  # rubocop:disable Naming/MethodParameterName, Naming/MethodName
6
- module Rails # :nodoc:
7
- module GraphQL # :nodoc:
6
+ module Rails
7
+ module GraphQL
8
8
  # = GraphQL ToGQL
9
9
  #
10
10
  # This class can turn any class related to GraphQL into its GraphQL string
@@ -35,14 +35,13 @@ module Rails # :nodoc:
35
35
  collector ||= Collectors::IdentedCollector.new
36
36
  @with_descriptions = with_descriptions
37
37
  @with_spec = with_spec.nil? ? schema.introspection? : with_spec
38
+ @namespace = schema.namespace
38
39
 
39
- accept(schema, collector).eol
40
-
41
- GraphQL.type_map.each_from(schema.namespace, base_class: :Type)
40
+ GraphQL.type_map.each_from(@namespace, base_class: :Type)
42
41
  .group_by(&:kind).values_at(*DESCRIBE_TYPES)
43
- .each do |items|
42
+ .prepend([schema]).each do |items|
44
43
  items&.sort_by(&:gql_name)&.each do |item|
45
- next if !@with_spec && item.internal?
44
+ next if !@with_spec && item.try(:internal?)
46
45
 
47
46
  next visit_Rails_GraphQL_Type_Object(item, collector).eol \
48
47
  if item.is_a?(::OpenStruct) && item.object?
@@ -109,8 +108,9 @@ module Rails # :nodoc:
109
108
  visit_directives(o.directives, collector)
110
109
 
111
110
  collector.indented(' {', '}') do
112
- Helpers::WithSchemaFields::SCHEMA_FIELD_TYPES.each do |key, name|
111
+ Helpers::WithSchemaFields::TYPE_FIELD_CLASS.each_key do |key|
113
112
  next unless key.eql?(:query) || o.fields_for(key).present?
113
+ name = o.type_name_for(key)
114
114
 
115
115
  collector << key.to_s
116
116
  collector << ': '
@@ -152,14 +152,6 @@ module Rails # :nodoc:
152
152
  visit_Rails_GraphQL_Field(o, collector)
153
153
  end
154
154
 
155
- def visit_Rails_GraphQL_Field_OutputField(o, collector)
156
- visit_Rails_GraphQL_Field(o, collector)
157
- end
158
-
159
- def visit_Rails_GraphQL_Field_InputField(o, collector)
160
- visit_Rails_GraphQL_Field(o, collector)
161
- end
162
-
163
155
  def visit_Rails_GraphQL_Type_Enum(o, collector)
164
156
  visit_description(o, collector)
165
157
  collector << 'enum '
@@ -178,9 +170,7 @@ module Rails # :nodoc:
178
170
  collector << o.gql_name
179
171
  visit_directives(o.directives, collector)
180
172
 
181
- collector.indented(' {', '}') do
182
- o.fields.each_value { |x| visit(x, collector) }
183
- end
173
+ collector.indented(' {', '}') { visit_fields(o.fields, collector) }
184
174
  end
185
175
 
186
176
  def visit_Rails_GraphQL_Type_Interface(o, collector)
@@ -190,9 +180,7 @@ module Rails # :nodoc:
190
180
  collector << o.gql_name
191
181
  visit_directives(o.directives, collector)
192
182
 
193
- collector.indented(' {', '}') do
194
- o.fields.each_value { |x| visit(x, collector) }
195
- end
183
+ collector.indented(' {', '}') { visit_fields(o.fields, collector) }
196
184
  end
197
185
 
198
186
  def visit_Rails_GraphQL_Type_Object(o, collector)
@@ -211,9 +199,7 @@ module Rails # :nodoc:
211
199
 
212
200
  visit_directives(o.directives, collector)
213
201
 
214
- collector.indented(' {', '}') do
215
- o.fields.each_value { |x| visit(x, collector) }
216
- end
202
+ collector.indented(' {', '}') { visit_fields(o.fields, collector) }
217
203
  end
218
204
 
219
205
  def visit_Rails_GraphQL_Type_Scalar(o, collector)
@@ -260,8 +246,16 @@ module Rails # :nodoc:
260
246
  visit_typed_object(o, collector)
261
247
  end
262
248
 
249
+ def visit_fields(list, collector)
250
+ return if list.blank?
251
+
252
+ list.values.sort_by do |field|
253
+ field.name == :id ? '' : field.gql_name
254
+ end.each { |x| visit(x, collector) }
255
+ end
256
+
263
257
  def visit_arguments(list, collector)
264
- return if list.empty?
258
+ return if list.blank?
265
259
 
266
260
  indented = @with_descriptions && list.values.any?(&:description?)
267
261
 
@@ -292,15 +286,18 @@ module Rails # :nodoc:
292
286
  end
293
287
 
294
288
  def visit_description(o, collector)
295
- return unless @with_descriptions && o.description?
289
+ return unless @with_descriptions
290
+
291
+ args = o.method(:description).arity == 0 ? [] : [@namespace]
292
+ return if (desc = o.description(*args)).nil?
296
293
 
297
- if o.description.lines.size === 1
298
- collector << o.description.inspect
294
+ if desc.lines.size === 1
295
+ collector << desc.inspect
299
296
  else
300
297
  collector << '"""'
301
298
  collector.eol
302
299
 
303
- collector << o.description
300
+ collector << desc
304
301
  collector.eol
305
302
 
306
303
  collector << '"""'
@@ -344,7 +341,7 @@ module Rails # :nodoc:
344
341
  collector << ' = ' << o.to_json(o.default) if o.try(:default_value?)
345
342
  end
346
343
 
347
- def visit(object, collector = nil) # :nodoc:
344
+ def visit(object, collector = nil)
348
345
  object_class = object.is_a?(Module) ? object : object.class
349
346
  dispatch_method = dispatch[object_class]
350
347
  if collector
@@ -358,7 +355,7 @@ module Rails # :nodoc:
358
355
  respond_to?(dispatch[klass], true)
359
356
  end
360
357
 
361
- raise(::TypeError, "Cannot visit #{object_class}") unless superklass
358
+ raise(::TypeError, +"Cannot visit #{object_class}") unless superklass
362
359
  dispatch[object_class] = dispatch[superklass]
363
360
  retry
364
361
  end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module GraphQL
5
+ class Type
6
+ # = GraphQL Type Creator
7
+ #
8
+ # This class helps to dynamically create types using a large set of
9
+ # settings that are provided through the named arguments. There are
10
+ # setting that are general to all types, and some are specific per base
11
+ # type of the superclass
12
+ class Creator
13
+ NESTED_MODULE = :NestedTypes
14
+ SUPPORTED_KINDS = %i[scalar object interface union enum input_object source].freeze
15
+
16
+ attr_reader :name, :superclass, :klass, :settings
17
+
18
+ delegate :type_map, to: '::Rails::GraphQL'
19
+ delegate :kind, to: :superclass
20
+
21
+ # Simply instantiate the creator and run the process
22
+ def self.create!(*args, **xargs, &block)
23
+ new(*args, **xargs).create!(&block)
24
+ end
25
+
26
+ def initialize(from, name_or_object, superclass, **settings)
27
+ @from = from
28
+ @settings = settings
29
+ @object = name_or_object if name_or_object.is_a?(Class)
30
+
31
+ @superclass = sanitize_superclass(superclass)
32
+ @name = sanitize_name(name_or_object)
33
+ end
34
+
35
+ # Go over the create process
36
+ def create!(&block)
37
+ @klass = find_or_create_class
38
+ klass.instance_variable_set(:@gql_name, gql_name)
39
+
40
+ apply_general_settings
41
+ after_block = apply_specific_settings
42
+
43
+ klass.module_exec(&block) if block.present?
44
+ after_block.call if after_block.is_a?(Proc)
45
+ klass
46
+ end
47
+
48
+ protected
49
+
50
+ # Use the type map to look for a type from the same namespace
51
+ def find_type!(value)
52
+ type_map.fetch!(value, namespaces: namespaces, base_class: :Type)
53
+ end
54
+
55
+ # Same as above, but mapping the list
56
+ def find_all_types!(*list)
57
+ list.map { |item| item.is_a?(Class) ? item : find_type!(item) }
58
+ end
59
+
60
+ # Apply settings that is common for any possible type created
61
+ def apply_general_settings
62
+ klass.abstract = settings[:abstract] if settings.key?(:abstract)
63
+ klass.set_namespace(*namespaces)
64
+
65
+ klass.use(*settings[:directives]) if settings.key?(:directives) &&
66
+ klass.is_a?(Helpers::WithDirectives)
67
+
68
+ if klass.is_a?(Helpers::WithAssignment)
69
+ assignment = settings.fetch(:assigned_to, @object)
70
+ klass.assigned_to = assignment unless assignment.nil?
71
+ end
72
+
73
+ if settings.key?(:owner)
74
+ klass.include(Helpers::WithOwner) unless klass.is_a?(Helpers::WithOwner)
75
+ klass.owner = settings[:owner] == true ? @from : settings[:owner]
76
+ end
77
+ end
78
+
79
+ # Using the kind, call of a specific method to further configure the
80
+ # created class
81
+ def apply_specific_settings
82
+ method_name = +"apply_#{kind}_settings"
83
+ send(method_name) if respond_to?(method_name, true)
84
+ end
85
+
86
+ # Specific settings when creating an enum
87
+ def apply_enum_settings
88
+ klass.indexed! if settings[:indexed]
89
+ return if (values = settings[:values]).nil?
90
+ GraphQL.enumerate(values).each(&klass.method(:add))
91
+ end
92
+
93
+ # Specific settings when creating an union
94
+ def apply_union_settings
95
+ types = settings[:of_types]
96
+ klass.append(*find_all_types!(*types)) unless types.nil?
97
+ end
98
+
99
+ # Specific settings when creating a source
100
+ def apply_source_settings
101
+ build = settings[:build]
102
+
103
+ -> do
104
+ return klass.build_all if build == true
105
+ GraphQL.enumerate(build).each do |step|
106
+ klass.public_send(+"build_#{step}")
107
+ end
108
+ end if build
109
+ end
110
+
111
+ private
112
+
113
+ # Either get the gql name from settings or properly resolve one from
114
+ # the name
115
+ def gql_name
116
+ settings[:gql_name].presence || begin
117
+ gql_name = name.dup
118
+ gql_name = gql_name.chomp(name_suffix) unless kind == :input_object
119
+ gql_name.tr('_', '')
120
+ end
121
+ end
122
+
123
+ # Add the nested module to the source of the creating and create the
124
+ # class. If any of those exist, return the constant instead
125
+ def find_or_create_class
126
+ base = base_module
127
+
128
+ # Create the class under the nested module
129
+ return base.const_set(name, Class.new(superclass)) \
130
+ unless base.const_defined?(name)
131
+
132
+ # Get the existing class and check for the once setting
133
+ klass = base.const_get(name)
134
+ return klass unless !once? && klass < superclass
135
+
136
+ # Created once or not from the same superclass
137
+ raise DuplicatedError, (+<<~MSG).squish
138
+ A type named "#{name}" already exists for the "#{base.name}" module.
139
+ MSG
140
+ end
141
+
142
+ # Make sure to properly get the superclass
143
+ def sanitize_superclass(value)
144
+ value = Type.const_get(value.to_s.classify) unless value.is_a?(Class)
145
+
146
+ valid_class = value.is_a?(Class) && value.respond_to?(:kind)
147
+ valid_class &= SUPPORTED_KINDS.include?(value.kind)
148
+ return value if valid_class
149
+
150
+ raise ::ArgumentError, +"The \"#{value.inspect}\" is not a valid superclass."
151
+ rescue ::NameError
152
+ raise ::ArgumentError, +"Unable to find a \"#{value}\" superclass."
153
+ end
154
+
155
+ # Let's clean up the name
156
+ def sanitize_name(name_or_object)
157
+ name = name_or_object.is_a?(Module) ? name_or_object.name : name_or_object.to_s
158
+ name = name.classify.gsub(/::/, '_')
159
+ name.end_with?(name_suffix) ? name : name + name_suffix
160
+ end
161
+
162
+ # Figure out the suffix that is supposed to be used for the name
163
+ def name_suffix
164
+ @name_suffix ||= @settings[:suffix] || begin
165
+ if kind == :input_object
166
+ GraphQL.config.auto_suffix_input_objects
167
+ else
168
+ superclass.kind.to_s.classify
169
+ end
170
+ end
171
+ end
172
+
173
+ # Get or set the base module using the from argument
174
+ def base_module
175
+ base = @from.is_a?(Module) ? @from : @from.class
176
+ if base.const_defined?(NESTED_MODULE, false)
177
+ base.const_get(NESTED_MODULE)
178
+ else
179
+ base.const_set(NESTED_MODULE, Module.new)
180
+ end
181
+ end
182
+
183
+ # Get the namespaces from the settings or from the source
184
+ def namespaces
185
+ @namespaces ||= settings[:namespace] || settings[:namespaces] || @from.namespace
186
+ end
187
+
188
+ # Check if the type should be create only once, meaning that returning
189
+ # an existing one is not an option
190
+ def once?
191
+ settings.fetch(:once, true)
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- class Type # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ class Type
6
6
  # Bigint basically removes the limit of the value, but it serializes as
7
7
  # a string so it won't go against the spec
8
8
  class Enum::DirectiveLocationEnum < Enum
@@ -12,17 +12,17 @@ module Rails # :nodoc:
12
12
 
13
13
  desc 'The valid locations that a directive may be placed.'
14
14
 
15
- %w[QUERY MUTATION SUBSCRIPTION FIELD FRAGMENT_DEFINITION
16
- FRAGMENT_SPREAD INLINE_FRAGMENT].each do |value|
17
- desc = value.downcase.tr('_', ' ')
18
- add(value, desc: "Mark as a executable directive usable on #{desc} objects.")
15
+ Directive::EXECUTION_LOCATIONS.each do |value|
16
+ name = value.to_s.upcase
17
+ desc = value.to_s.tr('_', ' ')
18
+ add(name, desc: "Mark as a executable directive usable on #{desc} objects.")
19
19
  end
20
20
 
21
- %w[SCHEMA SCALAR OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION
22
- ENUM ENUM_VALUE INPUT_OBJECT INPUT_FIELD_DEFINITION].each do |value|
23
- desc = value.downcase.tr('_', ' ')
21
+ Directive::DEFINITION_LOCATIONS.each do |value|
22
+ name = value.to_s.upcase
23
+ desc = value.to_s.tr('_', ' ')
24
24
  desc = "Mark as a type system directive usable on #{desc} definitions."
25
- add(value, desc: desc.gsub(/definition definitions\.$/, 'definitions.'))
25
+ add(name, desc: desc.sub('definition definitions.', 'definitions.'))
26
26
  end
27
27
  end
28
28
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- class Type # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ class Type
6
6
  # Bigint basically removes the limit of the value, but it serializes as
7
7
  # a string so it won't go against the spec
8
8
  class Enum::TypeKindEnum < Enum
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- class Type # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ class Type
6
6
  # = GraphQL EnumType
7
7
  #
8
8
  # Enum types, like scalar types, also represent leaf values in a GraphQL
@@ -13,10 +13,8 @@ module Rails # :nodoc:
13
13
 
14
14
  setup! leaf: true, input: true, output: true
15
15
 
16
- eager_autoload do
17
- autoload :DirectiveLocationEnum
18
- autoload :TypeKindEnum
19
- end
16
+ autoload :DirectiveLocationEnum
17
+ autoload :TypeKindEnum
20
18
 
21
19
  # Define the methods for accessing the values attribute
22
20
  inherited_collection :values
@@ -25,7 +23,7 @@ module Rails # :nodoc:
25
23
  inherited_collection :value_description, type: :hash
26
24
 
27
25
  # Define the methods for accessing the directives of each enum value
28
- inherited_collection :value_directives, type: :hash
26
+ inherited_collection :value_directives, type: :hash_set
29
27
 
30
28
  class << self
31
29
  # Mark the enum as indexed, allowing values being set by number
@@ -40,7 +38,8 @@ module Rails # :nodoc:
40
38
 
41
39
  # Check if a given value is a valid non-deserialized input
42
40
  def valid_input?(value)
43
- value.is_a?(String) && all_values.include?(value)
41
+ (valid_token?(value, :enum) && all_values.include?(value.to_s)) ||
42
+ (value.is_a?(String) && all_values.include?(value))
44
43
  end
45
44
 
46
45
  # Check if a given value is a valid non-serialized output
@@ -63,7 +62,7 @@ module Rails # :nodoc:
63
62
 
64
63
  # Turn a user input of this given type into an ruby object
65
64
  def deserialize(value)
66
- new(value) if valid_input?(value)
65
+ new(value.is_a?(::GQLParser::Token) ? value.to_s : value) if valid_input?(value)
67
66
  end
68
67
 
69
68
  # Use the instance as decorator
@@ -76,6 +75,7 @@ module Rails # :nodoc:
76
75
  # ==== Options
77
76
  #
78
77
  # * <tt>:desc</tt> - The description of the enum value (defaults to nil).
78
+ # * <tt>:description</tt> - Alias to the above.
79
79
  # * <tt>:directives</tt> - The list of directives associated with the value
80
80
  # (defaults to nil).
81
81
  # * <tt>:deprecated</tt> - A shortcut that auto-attach a @deprecated
@@ -83,18 +83,19 @@ module Rails # :nodoc:
83
83
  # but provide a string so it can be used as the reason of the deprecation.
84
84
  # See {DeprecatedDirective}[rdoc-ref:Rails::GraphQL::Directive::DeprecatedDirective]
85
85
  # (defaults to false).
86
- def add(value, desc: nil, directives: nil, deprecated: false)
87
- raise ArgumentError, <<~MSG.squish unless value.is_a?(String) && value.present?
86
+ def add(value, desc: nil, description: nil, directives: nil, deprecated: false)
87
+ value = value&.to_s
88
+ raise ArgumentError, (+<<~MSG).squish unless value.is_a?(String) && !value.empty?
88
89
  The "#{value}" is invalid.
89
90
  MSG
90
91
 
91
92
  value = value.upcase
92
- raise ArgumentError, <<~MSG.squish if all_values.include?(value)
93
+ raise ArgumentError, (+<<~MSG).squish if all_values&.include?(value)
93
94
  The "#{value}" is already defined for #{gql_name} enum.
94
95
  MSG
95
96
 
96
- directives = Array.wrap(directives)
97
- directives << deprecated_klass.new(
97
+ directives = ::Array.wrap(directives)
98
+ directives << Directive::DeprecatedDirective.new(
98
99
  reason: (deprecated.is_a?(String) ? deprecated : nil),
99
100
  ) if deprecated.present?
100
101
 
@@ -103,55 +104,52 @@ module Rails # :nodoc:
103
104
  source: self,
104
105
  )
105
106
 
107
+ desc = description if desc.nil?
108
+
106
109
  values << value
107
110
  value_description[value] = desc unless desc.nil?
108
- value_directives[value] = directives
111
+ value_directives[value] = directives if directives
109
112
  end
110
113
 
111
114
  # Check if a given +value+ is using a +directive+
112
115
  def value_using?(value, directive)
113
- raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
116
+ raise ArgumentError, (+<<~MSG).squish unless directive < GraphQL::Directive
114
117
  The provided #{item_or_symbol.inspect} is not a valid directive.
115
118
  MSG
116
119
 
117
- !!value_directives[as_json(value)]&.any? { |item| item.is_a?(directive) }
120
+ all_value_directives.try(:[], as_json(value))&.any?(directive) || false
118
121
  end
119
122
 
120
123
  # Build a hash with deprecated values and their respective reason for
121
124
  # logging and introspection purposes
122
125
  def all_deprecated_values
123
126
  @all_deprecated_values ||= begin
124
- all_value_directives.to_a.inject({}) do |list, (value, dirs)|
125
- obj = dirs.find { |dir| dir.is_a?(deprecated_klass) }
126
- obj ? list.merge(value => obj.args.reason) : list
127
+ all_value_directives&.each&.with_object({}) do |(value, dirs), hash|
128
+ obj = dirs&.find { |dir| dir.is_a?(Directive::DeprecatedDirective) }
129
+ hash[value] = obj.args.reason || true unless obj.nil?
127
130
  end
128
131
  end.freeze
129
132
  end
130
133
 
131
- # This returns the field directives and all value directives
132
- def all_directives
133
- all_value_directives.each_value.reduce(:+)
134
- end
134
+ def inspect
135
+ return super if self.eql?(Type::Enum)
135
136
 
136
- def inspect # :nodoc:
137
- <<~INFO.squish + '>'
137
+ values = all_values.to_a
138
+ (+<<~INFO).squish << '>'
138
139
  #<GraphQL::Enum #{gql_name}
139
- (#{all_values.size})
140
- {#{all_values.to_a.join(' | ')}}
140
+ (#{values.size})
141
+ {#{values.to_a.join(' | ')}}
142
+ #{inspect_directives}
141
143
  INFO
142
144
  end
143
-
144
- private
145
-
146
- def deprecated_klass
147
- Directive::DeprecatedDirective
148
- end
149
145
  end
150
146
 
151
147
  attr_reader :value
152
148
 
153
149
  delegate :to_s, :inspect, to: :@value
154
150
 
151
+ # TODO: Maybe add delegate missing
152
+
155
153
  def initialize(value)
156
154
  @value = value
157
155
  end
@@ -163,7 +161,7 @@ module Rails # :nodoc:
163
161
 
164
162
  # Allow finding the indexed position of the value
165
163
  def to_i
166
- self.class.all_values.find_index(@value)
164
+ values.find_index(@value)
167
165
  end
168
166
 
169
167
  # Checks if the current value is valid
@@ -173,33 +171,29 @@ module Rails # :nodoc:
173
171
 
174
172
  # Gets all the description of the current value
175
173
  def description
176
- @description ||= @value && self.class.all_value_description[@value]
174
+ return unless @value
175
+ return @description if defined?(@description)
176
+ @description = all_value_description.try(:[], @value)
177
177
  end
178
178
 
179
179
  # Gets all the directives associated with the current value
180
180
  def directives
181
- @directives ||= @value && self.class.all_value_directives[@value]
181
+ return unless @value
182
+ return @directives if defined?(@directives)
183
+ @directives = all_value_directives.try(:[], @value)
182
184
  end
183
185
 
184
186
  # Checks if the current value is marked as deprecated
185
187
  def deprecated?
186
- self.class.all_deprecated_values.include?(@value)
188
+ directives&.any?(Directive::DeprecatedDirective) || false
187
189
  end
188
190
 
189
191
  # Return the deprecated reason
190
192
  def deprecated_reason
191
- deprecated_directive&.args&.reason
193
+ directives&.find do |dir|
194
+ dir.is_a?(Directive::DeprecatedDirective)
195
+ end&.args&.reason
192
196
  end
193
-
194
- private
195
-
196
- # Find and store the directive that marked the current value as
197
- # deprecated
198
- def deprecated_directive
199
- @deprecated_directive ||= directives.find do |dir|
200
- dir.is_a?(Directive::DeprecatedDirective)
201
- end
202
- end
203
197
  end
204
198
  end
205
199
  end