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
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
+ module WithDescription
7
+
8
+ # A getter or setter in the same function
9
+ def desc(value = nil)
10
+ value.nil? ? description : (self.description = value)
11
+ end
12
+
13
+ # Define and format description
14
+ def description=(value)
15
+ if !value.nil?
16
+ @description = value.to_s.presence&.strip_heredoc&.chomp
17
+ elsif defined?(@description)
18
+ @description = nil
19
+ end
20
+ end
21
+
22
+ # Return a description, by defined value or I18n
23
+ def description(namespace = nil, kind = nil)
24
+ return @description if description?
25
+ return unless GraphQL.config.enable_i18n_descriptions
26
+
27
+ i18n_description(namespace, kind)
28
+ end
29
+
30
+ # Checks if a description was provided
31
+ def description?
32
+ defined?(@description) && !!@description
33
+ end
34
+
35
+ protected
36
+
37
+ # Return a description from I18n
38
+ def i18n_description(namespace = nil, kind = nil)
39
+ return if (parent = try(:owner)).try(:spec_object?) &&
40
+ parent.kind != :schema
41
+
42
+ values = {
43
+ kind: kind || try(:kind),
44
+ parent: i18n_parent_value(parent),
45
+ namespace: GraphQL.enumerate(namespace || try(:namespaces)).first,
46
+ name: is_a?(Module) ? to_sym : name,
47
+ }
48
+
49
+ options = GraphQL.config.i18n_scopes.dup
50
+ while option = options.shift
51
+ key = format(option, values)
52
+ next if key.include?('..')
53
+
54
+ result = catch(:exception) { ::I18n.translate(key, throw: true) }
55
+ return result if result.is_a?(String)
56
+ end
57
+ end
58
+
59
+ # Properly figure out the parent value for the interpolation
60
+ def i18n_parent_value(parent)
61
+ if parent.respond_to?(:i18n_scope)
62
+ parent.i18n_scope(self)
63
+ elsif parent.is_a?(Helpers::WithSchemaFields) && respond_to?(:schema_type)
64
+ schema_type
65
+ else
66
+ parent.try(:to_sym)
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- module Helpers # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
6
  # Helper module that allows other objects to hold directives during the
7
7
  # definition process
8
8
  module WithDirectives
@@ -15,12 +15,14 @@ module Rails # :nodoc:
15
15
  def self.included(other)
16
16
  other.extend(WithDirectives::DirectiveLocation)
17
17
  other.define_method(:directives) { @directives ||= Set.new }
18
- other.class_attribute(:directive_location, instance_writer: false)
18
+ other.define_method(:all_directives) { @directives if defined?(@directives) }
19
+ other.define_method(:directives?) { defined?(@directives) && @directives.present? }
19
20
  end
20
21
 
21
22
  def initialize_copy(orig)
22
23
  super
23
24
 
25
+ return if orig.directives.nil?
24
26
  @directives = orig.directives.dup
25
27
  end
26
28
 
@@ -35,25 +37,20 @@ module Rails # :nodoc:
35
37
 
36
38
  # Use this once to define the directive location
37
39
  def directive_location=(value)
38
- raise ArgumentError, 'Directive location is already defined' \
40
+ raise ArgumentError, +'Directive location is already defined' \
39
41
  unless directive_location.nil?
40
42
 
41
43
  @directive_location = value
42
44
  end
43
45
  end
44
46
 
45
- # Mostly for correct inheritance on instances
46
- def all_directives
47
- defined?(@directives) ? @directives : Set.new
48
- end
49
-
50
47
  # Use this method to assign directives to the given definition. You can
51
48
  # also provide a symbol as a first argument and extra named-arguments
52
49
  # to auto initialize a new instance of that directive.
53
50
  def use(item_or_symbol, *list, **xargs)
54
51
  if item_or_symbol.is_a?(Symbol)
55
52
  directive = fetch!(item_or_symbol)
56
- raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
53
+ raise ArgumentError, (+<<~MSG).squish unless directive < GraphQL::Directive
57
54
  Unable to find the #{item_or_symbol.inspect} directive.
58
55
  MSG
59
56
 
@@ -62,45 +59,69 @@ module Rails # :nodoc:
62
59
  list << item_or_symbol
63
60
  end
64
61
 
65
- current = try(:all_directives) || @directives
66
- items = GraphQL.directives_to_set(list, current, source: self)
67
- directives.merge(items)
62
+ directives.merge(GraphQL.directives_to_set(list, all_directives, source: self))
63
+ self
68
64
  rescue DefinitionError => e
69
- raise e.class, e.message + "\n Defined at: #{caller(2)[0]}"
65
+ raise e.class, +"#{e.message}\n Defined at: #{caller(2)[0]}"
70
66
  end
71
67
 
72
- # Check wheter a given directive is being used
73
- def using?(item_or_symbol)
74
- directive = item_or_symbol.is_a?(Symbol) ? fetch!(item_or_symbol) : item_or_symbol
75
- raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
76
- The provided #{item_or_symbol.inspect} is not a valid directive.
68
+ # Check whether a given directive is being used
69
+ # TODO: This does not work with the instance
70
+ def using?(item)
71
+ directive = (item.is_a?(Symbol) || item.is_a?(String)) ? fetch!(item) : item
72
+ raise ArgumentError, (+<<~MSG).squish unless directive < GraphQL::Directive
73
+ The provided #{item.inspect} is not a valid directive.
77
74
  MSG
78
75
 
79
- all_directives.any? { |item| item.is_a?(directive) }
76
+ !!all_directives&.any?(directive)
80
77
  end
81
78
 
82
79
  alias has_directive? using?
83
80
 
81
+ # TODO: Maybe implement a method to fetch a specific directive
82
+
84
83
  # Override the +all_listeners+ method since callbacks can eventually be
85
84
  # attached to objects that have directives, which then they need to
86
85
  # be combined
87
- def all_listeners
88
- current = all_directives.map(&:all_listeners).reduce(:+) || Set.new
89
- (defined?(super) ? super : Set.new) + current
86
+ def all_directive_listeners
87
+ inherited = super if defined?(super)
88
+ return inherited unless directives?
89
+
90
+ current = all_directives.map(&:all_listeners).compact.reduce(:+)
91
+ inherited.nil? ? current : inherited + current
90
92
  end
91
93
 
94
+ alias all_listeners all_directive_listeners
95
+
96
+ # Make sure to consider directive listeners while checking for listeners
97
+ def directive_listeners?
98
+ (defined?(super) && super) || all_directives&.any?(&:listeners?)
99
+ end
100
+
101
+ alias listeners? directive_listeners?
102
+
92
103
  # Override the +all_events+ method since callbacks can eventually be
93
104
  # attached to objects that have directives, which then they need to
94
105
  # be combined
95
- def all_events
96
- Helpers::AttributeDelegator.new do
97
- base = defined?(super) ? super : {}
98
- all_directives.map(&:all_events).inject(base) do |lhash, rhash|
99
- Helpers.merge_hash_array(lhash, rhash)
100
- end
106
+ def all_directive_events
107
+ inherited = super if defined?(super)
108
+ return inherited unless directives?
109
+
110
+ all_directives.inject(inherited || {}) do |result, directive|
111
+ next result if (val = directive.all_events).blank?
112
+ Helpers.merge_hash_array(result, val)
101
113
  end
102
114
  end
103
115
 
116
+ alias all_events all_directive_events
117
+
118
+ # Make sure to consider directive events while checking for events
119
+ def directive_events?
120
+ (defined?(super) && super) || all_directives&.any?(&:events?)
121
+ end
122
+
123
+ alias events? directive_events?
124
+
104
125
  # Validate all the directives to make sure the definition is valid
105
126
  def validate!(*)
106
127
  super if defined? super
@@ -110,6 +131,13 @@ module Rails # :nodoc:
110
131
  @directives.freeze
111
132
  end
112
133
 
134
+ protected
135
+
136
+ # Helper method to inspect the directives
137
+ def inspect_directives
138
+ all_directives&.map(&:inspect)&.join(' ')
139
+ end
140
+
113
141
  private
114
142
 
115
143
  # Find a directive for its symbolized name
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- module Helpers # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
6
  # Helper module that allows other objects to hold events, either from a
7
7
  # singleton point-of-view, or for instances
8
8
  module WithEvents
@@ -19,7 +19,12 @@ module Rails # :nodoc:
19
19
  other.delegate(:event_types, to: :class)
20
20
 
21
21
  other.define_method(:events) { @events ||= Hash.new { |h, k| h[k] = [] } }
22
+ other.define_method(:all_events) { @events if defined?(@events) }
23
+ other.define_method(:events?) { defined?(@events) && @events.present? }
24
+
22
25
  other.define_method(:listeners) { @listeners ||= Set.new }
26
+ other.define_method(:all_listeners) { @listeners if defined?(@listeners) }
27
+ other.define_method(:listeners?) { defined?(@listeners) && @listeners.present? }
23
28
  end
24
29
 
25
30
  # Helper module to define static list of valid event types
@@ -27,10 +32,11 @@ module Rails # :nodoc:
27
32
  # Set or get the list of possible event types when attaching events
28
33
  def event_types(*list, append: false, expose: false)
29
34
  return (defined?(@event_types) && @event_types.presence) ||
30
- superclass.try(:event_types) || [] if list.blank?
35
+ superclass.try(:event_types) || EMPTY_ARRAY if list.blank?
36
+
37
+ new_list = list.flatten.compact.map(&:to_sym)
38
+ new_list = event_types + new_list if append
31
39
 
32
- new_list = append ? event_types : []
33
- new_list += list.flatten.compact.map(&:to_sym)
34
40
  @event_types = new_list.uniq.freeze
35
41
  expose_events!(*list) if expose
36
42
  @event_types
@@ -38,7 +44,7 @@ module Rails # :nodoc:
38
44
 
39
45
  protected
40
46
 
41
- # Auxiliar method that creates easy-accessible callback assignment
47
+ # Auxiliary method that creates easy-accessible callback assignment
42
48
  def expose_events!(*list)
43
49
  list.each do |event_name|
44
50
  next if method_defined?(event_name)
@@ -49,31 +55,24 @@ module Rails # :nodoc:
49
55
  end
50
56
  end
51
57
 
52
- # Mostly for correct inheritance on instances
53
- def all_events
54
- current = defined?(@events) ? @events : {}
55
- return current unless defined? super
56
- Helpers.merge_hash_array(current, super)
57
- end
58
-
59
- # Mostly for correct inheritance on instances
60
- def all_listeners
61
- current = (defined?(@listeners) && @listeners) || Set.new
62
- defined?(super) ? (current + super) : current
63
- end
64
-
65
58
  # Add a new event listener for the given +event_name+. It is possible
66
59
  # to prepend the event by setting +unshift: true+. This checks if the
67
60
  # event name is a valid one due to +event_types+.
68
- def on(event_name, unshift: false, &block)
61
+ def on(event_name, callback = nil, unshift: false, &block)
69
62
  event_name = event_name.to_sym
70
63
  valid = !event_types || event_types.include?(event_name)
71
- raise ArgumentError, <<~MSG.squish unless valid
64
+ raise ArgumentError, (+<<~MSG).squish unless valid
72
65
  The #{event_name} is not a valid event type.
73
66
  MSG
74
67
 
68
+ invalid_callback = callback.nil? || callback.is_a?(Callback)
69
+ raise ArgumentError, (+<<~MSG).squish unless invalid_callback
70
+ The provided #{callback.class.name} is not a valid callback.
71
+ MSG
72
+
75
73
  listeners << event_name
76
- events[event_name].send(unshift ? :unshift : :push, block)
74
+ events[event_name].send(unshift ? :unshift : :push, callback || block)
75
+ self
77
76
  end
78
77
  end
79
78
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- module Helpers # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
6
  # Helper module that allows other objects to hold fields during the
7
7
  # definition process. Works very similar to Arguments, but it's more
8
8
  # flexible, since the type of the fields can be dynamic defined by the
@@ -12,19 +12,31 @@ module Rails # :nodoc:
12
12
  # related to the base type, but it's closer associated with the strategy
13
13
  # used to handle them.
14
14
  module WithFields
15
- module ClassMethods # :nodoc: all
15
+ module ClassMethods
16
16
  def inherited(subclass)
17
17
  super if defined? super
18
18
  return unless defined?(@fields)
19
19
  fields.each_value(&subclass.method(:proxy_field))
20
20
  end
21
+
22
+ # Return the list of fields, only initialize when explicitly told
23
+ def fields(initialize = nil)
24
+ return @fields if defined?(@fields)
25
+ return unless initialize
26
+
27
+ @fields = Concurrent::Map.new
28
+ end
29
+
30
+ # Check if there are any fields defined
31
+ def fields?
32
+ defined?(@fields) && @fields.present?
33
+ end
21
34
  end
22
35
 
23
- def self.extended(other) # :nodoc:
36
+ def self.extended(other)
24
37
  other.extend(WithFields::ClassMethods)
25
- other.define_singleton_method(:fields) { @fields ||= Concurrent::Map.new }
26
- other.class_attribute(:field_type, instance_writer: false)
27
- other.class_attribute(:valid_field_types, instance_writer: false, default: [])
38
+ other.class_attribute(:field_type, instance_accessor: false)
39
+ other.class_attribute(:valid_field_types, instance_accessor: false, default: [])
28
40
  end
29
41
 
30
42
  # Check if the field is already defined before actually creating it
@@ -37,32 +49,32 @@ module Rails # :nodoc:
37
49
 
38
50
  # See {Field}[rdoc-ref:Rails::GraphQL::Field] class.
39
51
  def field(name, *args, **xargs, &block)
40
- xargs[:owner] = self
41
- object = field_type.new(name, *args, **xargs, &block)
52
+ object = field_type.new(name, *args, **xargs, owner: self, &block)
42
53
 
43
- raise DuplicatedError, <<~MSG.squish if field?(object.name)
54
+ raise DuplicatedError, (+<<~MSG).squish if has_field?(object.name)
44
55
  The #{name.inspect} field is already defined and can't be redefined.
45
56
  MSG
46
57
 
47
- fields[object.name] = object
58
+ fields(true)[object.name] = object
48
59
  rescue DefinitionError => e
49
- raise e.class, e.message + "\n Defined at: #{caller(2)[0]}"
60
+ raise e.class, +"#{e.message}\n Defined at: #{caller(2)[0]}"
50
61
  end
51
62
 
52
63
  # Add a new field to the list but use a proxy instead of a hard copy of
53
64
  # a given +field+
54
65
  def proxy_field(field, *args, **xargs, &block)
55
- raise ArgumentError, <<~MSG.squish unless field.is_a?(GraphQL::Field)
66
+ field = field.field if field.is_a?(Module) && field <= Alternative::Query
67
+ raise ArgumentError, (+<<~MSG).squish unless field.is_a?(field_type)
56
68
  The #{field.class.name} is not a valid field.
57
69
  MSG
58
70
 
59
71
  xargs[:owner] = self
60
72
  object = field.to_proxy(*args, **xargs, &block)
61
- raise DuplicatedError, <<~MSG.squish if field?(object.name)
73
+ raise DuplicatedError, (+<<~MSG).squish if has_field?(object.name)
62
74
  The #{field.name.inspect} field is already defined and can't be replaced.
63
75
  MSG
64
76
 
65
- fields[object.name] = object
77
+ fields(true)[object.name] = object
66
78
  end
67
79
 
68
80
  # Overwrite attributes of a given field named as +name+, it also allows
@@ -88,35 +100,70 @@ module Rails # :nodoc:
88
100
  list.flatten.map { |item| self[item]&.enable! }
89
101
  end
90
102
 
91
- # Check wheter a given field +object+ is defined in the list of fields
92
- def field?(object)
103
+ # Check whether a given field +object+ is defined in the list of fields
104
+ def has_field?(object)
105
+ return false unless fields?
93
106
  object = object.name if object.is_a?(GraphQL::Field)
94
107
  fields.key?(object.is_a?(String) ? object.underscore.to_sym : object)
95
108
  end
96
109
 
97
110
  # Allow accessing fields using the hash notation
98
- def [](object)
111
+ def find_field(object)
112
+ return unless fields?
99
113
  object = object.name if object.is_a?(GraphQL::Field)
100
114
  fields[object.is_a?(String) ? object.underscore.to_sym : object]
101
115
  end
102
116
 
103
- alias find_field []
117
+ alias [] find_field
104
118
 
105
119
  # If the field is not found it will raise an exception
106
120
  def find_field!(object)
107
- find_field(object) || raise(::ArgumentError, <<~MSG.squish)
121
+ find_field(object) || raise(NotFoundError, (+<<~MSG).squish)
108
122
  The #{object.inspect} field is not defined yet.
109
123
  MSG
110
124
  end
111
125
 
112
- # Get the list of GraphQL names of all the fields difined
126
+ # Get the list of GraphQL names of all the fields defined
113
127
  def field_names(enabled_only = true)
114
- (enabled_only ? enabled_fields : fields.each_value).map(&:gql_name).compact
128
+ (enabled_only ? enabled_fields : lazy_each_field)&.map(&:gql_name)&.eager
115
129
  end
116
130
 
117
131
  # Return a lazy enumerator for enabled fields
118
132
  def enabled_fields
119
- fields.values.select(&:enabled?)
133
+ lazy_each_field&.select(&:enabled?)
134
+ end
135
+
136
+ # Import one or more field into the current list of fields
137
+ def import(source)
138
+ # Import an alternative declaration of a field
139
+ if source.is_a?(Module) && source <= Alternative::Query
140
+ return proxy_field(type, source.field)
141
+ end
142
+
143
+ case source
144
+ when Array
145
+ # Import a list of fields
146
+ source.each { |field| proxy_field(type, field) }
147
+ when Hash, Concurrent::Map
148
+ # Import a keyed list of fields
149
+ source.each_value { |field| proxy_field(type, field) }
150
+ when Helpers::WithFields
151
+ # Import a set of fields
152
+ source.fields.each_value { |field| proxy_field(type, field) }
153
+ else
154
+ return if GraphQL.config.silence_import_warnings
155
+ GraphQL.logger.warn(+"Unable to import #{source.inspect} into #{self.name}.")
156
+ end
157
+ end
158
+
159
+ # Import a module containing several classes to be imported
160
+ def import_all(mod, recursive: false, **xargs)
161
+ mod.constants.each do |const_name|
162
+ object = mod.const_get(const_name)
163
+
164
+ import(object, **xargs) if object.is_a?(Class)
165
+ import_all(object, recursive: recursive, **xargs) if recursive && object.is_a?(Module)
166
+ end
120
167
  end
121
168
 
122
169
  # Validate all the fields to make sure the definition is valid
@@ -125,16 +172,29 @@ module Rails # :nodoc:
125
172
 
126
173
  # TODO: Maybe find a way to freeze the fields, since after validation
127
174
  # the best thing to do is block changes
128
- fields.each_value(&:validate!)
175
+ fields&.each_value(&:validate!)
176
+ end
177
+
178
+ # Find a specific field using its id as +gql_name.type+
179
+ def find_by_gid(gid)
180
+ find_field!(gid.name)
129
181
  end
130
182
 
131
183
  protected
132
184
 
133
185
  # A little helper to define arguments using the :arguments key
134
- def arg(*args, **xargs, &block)
186
+ def argument(*args, **xargs, &block)
135
187
  xargs[:owner] = self
136
188
  GraphQL::Argument.new(*args, **xargs, &block)
137
189
  end
190
+
191
+ alias arg argument
192
+
193
+ private
194
+
195
+ def lazy_each_field
196
+ fields.each_pair.lazy.each_entry.map(&:last) if fields?
197
+ end
138
198
  end
139
199
  end
140
200
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
+ # Helper module that is a different implementation of the
7
+ # +GlobalID::Identification+, but instead of things being found by the
8
+ # class that they are, it uses owners and base classes.
9
+ module WithGlobalID
10
+ def to_global_id(options = nil) # :nodoc:
11
+ GlobalID.create(self, options)
12
+ end
13
+
14
+ alias to_gid to_global_id
15
+
16
+ def to_gid_param(options = nil) # :nodoc:
17
+ to_global_id(options).to_param
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/module/anonymous'
4
+
5
+ module Rails
6
+ module GraphQL
7
+ module Helpers
8
+ # Helper module responsible for name stuff
9
+ module WithName
10
+ NAME_EXP = /GraphQL::(?:Type::\w+::|Directive::)?([:\w]+)\z/.freeze
11
+
12
+ # Here we define a couple of attributes used by registration
13
+ def self.extended(other)
14
+ # TODO: Move to registerable
15
+ # An abstract type won't appear in the introspection and will not be
16
+ # instantiated by requests
17
+ other.class_attribute :abstract, instance_accessor: false, default: false
18
+ end
19
+
20
+ # Return the name of the object as a GraphQL name
21
+ def gql_name
22
+ @gql_name ||= begin
23
+ result = name.match(NAME_EXP).try(:[], 1)
24
+ result.tr(':', '').chomp(base_type.name.demodulize) unless result.nil?
25
+ end unless anonymous?
26
+ end
27
+
28
+ alias graphql_name gql_name
29
+
30
+ # Return the name of the object as a symbol
31
+ def to_sym
32
+ @gql_key ||= gql_name&.underscore&.to_sym
33
+ end
34
+
35
+ protected
36
+
37
+ # Change the gql name of the object
38
+ def rename!(name)
39
+ @gql_name = name.to_s
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- module Helpers # :nodoc:
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
6
  # Helper module that allows other objects to hold namespaces. It can
7
7
  # either work as an extension of the superclass using +add_namespace+ or
8
8
  # it can be reset then set using +namespace+.
@@ -10,7 +10,10 @@ module Rails # :nodoc:
10
10
  # Returns the list of defined namespaces
11
11
  def namespaces
12
12
  return @namespaces if defined?(@namespaces)
13
- superclass.try(:namespaces) || Set.new
13
+ superclass.try(:namespaces) || begin
14
+ value = GraphQL.type_map.associated_namespace_of(self)
15
+ @namespaces = value unless value.nil?
16
+ end
14
17
  end
15
18
 
16
19
  # Set or overwrite the list of namespaces
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails # :nodoc:
4
- module GraphQL # :nodoc:
5
- module Helpers # :nodoc:
6
- # Helper module that allows other objects to hold an +assigned_to+ object
3
+ module Rails
4
+ module GraphQL
5
+ module Helpers
6
+ # Helper focus on event execution when objects have a owner property,
7
+ # pratically allowing resolvers and similar to be called in the owner
7
8
  module WithOwner
8
9
  def self.included(other)
9
10
  other.extend(WithOwner::ClassMethods)
10
11
  other.class_attribute(:owner, instance_writer: false)
11
12
  end
12
13
 
13
- module ClassMethods # :nodoc: all
14
+ module ClassMethods
14
15
  def method_defined?(method_name)
15
16
  super || owner&.method_defined?(method_name)
16
17
  end
@@ -18,11 +19,11 @@ module Rails # :nodoc:
18
19
 
19
20
  private
20
21
 
21
- def respond_to_missing?(*args) # :nodoc:
22
+ def respond_to_missing?(*args)
22
23
  owner_respond_to?(*args) || super
23
24
  end
24
25
 
25
- def method_missing(method_name, *args, **xargs, &block) # :nodoc:
26
+ def method_missing(method_name, *args, **xargs, &block)
26
27
  return super unless owner_respond_to?(method_name)
27
28
  event.on_instance(owner) do |obj|
28
29
  obj.public_send(method_name, *args, **xargs, &block)