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
@@ -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 InputType
7
7
  #
8
8
  # Input defines a set of input fields; the input fields are either
@@ -34,49 +34,82 @@ module Rails # :nodoc:
34
34
  @gql_name = result
35
35
  end
36
36
 
37
+ # Transforms the given value to its representation in a JSON string
38
+ def as_json(value)
39
+ parse_arguments(value, using: :as_json, key: :gql_name)
40
+ end
41
+
42
+ # Transforms the given value to its representation in a Hash object
43
+ def to_json(value)
44
+ as_json(value).to_json
45
+ end
46
+
37
47
  # Check if a given value is a valid non-deserialized input
38
48
  def valid_input?(value)
49
+ value = GraphQL.config.literal_input_parser.call(value) \
50
+ if valid_token?(value, :hash)
51
+
39
52
  value = value.to_h if value.respond_to?(:to_h)
40
- return false unless value.is_a?(Hash)
53
+ return false unless value.is_a?(::Hash)
41
54
 
42
55
  fields = enabled_fields
43
56
  value = value.transform_keys { |key| key.to_s.camelize(:lower) }
44
57
  value = build_defaults.merge(value)
45
58
 
46
- return false unless value.size.eql?(fields.size)
59
+ return false unless value.size.eql?(fields&.count || 0)
47
60
 
48
- fields.all? { |item| item.valid_input?(value[item.gql_name]) }
61
+ fields&.all? { |item| item.valid_input?(value[item.gql_name]) }
49
62
  end
50
63
 
51
- # Turn the given value into an isntance of the input object
52
- def deserialize(value)
53
- value = value.to_h if value.respond_to?(:to_h)
54
- value = {} unless value.is_a?(Hash)
55
- value = enabled_fields.map do |field|
56
- next unless value.key?(field.gql_name) || value.key?(field.name)
57
- [field.name, field.deserialize(value[field.gql_name] || value[field.name])]
58
- end.compact.to_h
59
-
60
- new(OpenStruct.new(value))
64
+ # Turn the given value into an instance of the input object
65
+ def deserialize(value = nil, **value_as_hash)
66
+ value = value_as_hash if value.nil?
67
+ new(OpenStruct.new(parse_arguments(value, using: :deserialize)))
61
68
  end
62
69
 
70
+ alias build deserialize
71
+
63
72
  # Build a hash with the default values for each of the given fields
64
73
  def build_defaults
65
- enabled_fields.map { |field| [field.gql_name, field.default] }.to_h
74
+ return {} unless fields?
75
+ enabled_fields.each.with_object({}) do |field, hash|
76
+ hash[field.gql_name] = field.default
77
+ end
66
78
  end
67
79
 
68
- def inspect # :nodoc:
69
- args = fields.each_value.map(&:inspect)
70
- args = args.presence && "(#{args.join(', ')})"
71
- "#<GraphQL::Input #{gql_name}#{args}>"
80
+ def inspect
81
+ return super if self.eql?(Type::Input)
82
+ args = fields.values.map(&:inspect)
83
+ args = args.presence && +"(#{args.join(', ')})"
84
+
85
+ directives = inspect_directives
86
+ directives.prepend(' ') if directives.present?
87
+ +"#<GraphQL::Input #{gql_name}#{args}#{directives}>"
72
88
  end
89
+
90
+ private
91
+
92
+ def parse_arguments(value, using:, key: :name)
93
+ value = GraphQL.config.literal_input_parser.call(value) \
94
+ if valid_token?(value, :hash)
95
+
96
+ value = value.to_h if value.respond_to?(:to_h)
97
+ value = {} unless value.is_a?(::Hash)
98
+ value = value.stringify_keys
99
+
100
+ enabled_fields.each.with_object({}) do |field, hash|
101
+ next unless value.key?(field.gql_name) || value.key?(field.name.to_s)
102
+ result = value[field.gql_name] || value[field.name.to_s]
103
+ hash[field.public_send(key)] = field.public_send(using, result)
104
+ end.compact
105
+ end
73
106
  end
74
107
 
75
- attr_reader :args
108
+ attr_reader :args, :assignment_error
76
109
  attr_writer :resource
77
110
 
78
111
  delegate :fields, to: :class
79
- delegate :[], to: :args
112
+ delegate :to_h, :[], to: :args
80
113
 
81
114
  delegate_missing_to :resource
82
115
 
@@ -91,7 +124,10 @@ module Rails # :nodoc:
91
124
  # received arguments. It also accepts extra arguments for inheritance
92
125
  # purposes
93
126
  def resource(*args, **xargs, &block)
94
- @resource ||= (klass = safe_assigned_class).nil? ? nil : begin
127
+ return @resource if defined?(@resource)
128
+ return if (klass = safe_assigned_class).nil?
129
+
130
+ @resource = begin
95
131
  xargs = xargs.reverse_merge(params)
96
132
  klass.new(*args, **xargs, &block)
97
133
  end
@@ -102,6 +138,22 @@ module Rails # :nodoc:
102
138
  parametrize(self)
103
139
  end
104
140
 
141
+ # Correctly turn all the arguments into their +as_json+ version and
142
+ # return a hash of them
143
+ def args_as_json
144
+ self.class.as_json(@args.to_h)
145
+ end
146
+
147
+ alias as_json args_as_json
148
+
149
+ # Correctly turn all the arguments into their +to_json+ version and
150
+ # return a hash of them
151
+ def args_to_json
152
+ self.class.to_json(@args.to_h)
153
+ end
154
+
155
+ alias to_json args_to_json
156
+
105
157
  # Checks if all the values provided to the input instance are valid
106
158
  def validate!(*)
107
159
  errors = []
@@ -112,11 +164,26 @@ module Rails # :nodoc:
112
164
  end
113
165
 
114
166
  return if errors.empty?
115
- raise InvalidValueError, <<~MSG.squish
167
+ raise InvalidValueError, (+<<~MSG).squish
116
168
  Invalid value provided to #{gql_name} field: #{errors.to_sentence}.
117
169
  MSG
118
170
  end
119
171
 
172
+ # Override this method to save any errors that could happen with loading
173
+ # the assigned class
174
+ def safe_assigned_class
175
+ assigned_class
176
+ rescue ::ArgumentError, ::NameError => error
177
+ @assignment_error = error
178
+ nil
179
+ end
180
+
181
+ %i[to_global_id to_gid to_gid_param].each do |method_name|
182
+ define_method(method_name) do
183
+ self.class.public_send(method_name, args_as_json.compact)
184
+ end
185
+ end
186
+
120
187
  private
121
188
 
122
189
  # Make sure to turn inputs into params
@@ -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 InterfaceType
7
7
  #
8
8
  # Interfaces represent a list of named fields and their types.
@@ -16,28 +16,19 @@ module Rails # :nodoc:
16
16
  extend Helpers::WithAssignment
17
17
  extend Helpers::WithFields
18
18
 
19
+ include Helpers::Instantiable
20
+
19
21
  setup! output: true
20
22
 
21
23
  self.field_type = Field::OutputField
22
24
 
23
- # The purpose of instantiating an interface is to have access to its
24
- # public methods. It then runs from the strategy perspective, pointing
25
- # out any other methods to the manually set event
26
- delegate_missing_to :event
27
- attr_reader :event
25
+ # Define the methods for accessing the types attribute
26
+ inherited_collection :types, instance_reader: false
28
27
 
29
28
  class << self
30
- # TODO: Use inherited attribute for types
31
-
32
- # Stores the list of types associated with the interface so it can
33
- # be used during the execution step to find the right object type
34
- def types
35
- @types ||= Set.new
36
- end
37
-
38
- # Get the list of all inherited-aware associated types
39
- def all_types
40
- (superclass.try(:all_types) || Set.new) + (defined?(@types) ? @types : Set.new)
29
+ # Figure out which one of the types is compatible with the provided +value+
30
+ def type_for(value, *)
31
+ all_types&.reverse_each&.find { |t| t.valid_member?(value) }
41
32
  end
42
33
 
43
34
  # Check if the other type is equivalent, by checking if the other is
@@ -49,25 +40,35 @@ module Rails # :nodoc:
49
40
  # When attaching an interface to an object, copy the fields and add to
50
41
  # the list of types. Pre-existing same-named fields with are not
51
42
  # equivalent produces an exception.
52
- def implemented(object)
43
+ def implemented(object, import_fields: true)
44
+ import_fields = false if abstract?
45
+
53
46
  fields.each do |name, field|
54
- defined = object.field?(name)
55
- invalid = defined && object.fields[name] !~ field
56
- raise ArgumentError, <<~MSG.squish if invalid
47
+ defined = object[field.name]
48
+ raise ArgumentError, (+<<~MSG).squish unless defined || import_fields
49
+ The "#{object.gql_name}" object must have a "#{field.gql_name}" field.
50
+ MSG
51
+
52
+ invalid = defined && defined !~ field
53
+ raise ArgumentError, (+<<~MSG).squish if invalid
57
54
  The "#{object.gql_name}" object already has a "#{field.gql_name}" field and it
58
55
  is not equivalent to the one defined on the "#{gql_name}" interface.
59
56
  MSG
60
57
 
61
- object.proxy_field(field) unless defined
58
+ object.proxy_field(field) if import_fields && !defined
62
59
  end
63
60
 
64
61
  types << object
65
62
  end
66
63
 
67
- def inspect # :nodoc:
68
- fields = @fields.values.map(&:inspect)
69
- fields = fields.presence && " {#{fields.join(', ')}}"
70
- "#<GraphQL::Interface #{gql_name}#{fields}>"
64
+ def inspect
65
+ return super if self.eql?(Type::Interface)
66
+ fields = @fields.values.map(&:inspect) if defined?(@fields)
67
+ fields = fields.presence && +" {#{fields.join(', ')}}"
68
+
69
+ directives = inspect_directives
70
+ directives.prepend(' ') if directives.present?
71
+ +"#<GraphQL::Interface #{gql_name}#{fields}#{directives}>"
71
72
  end
72
73
 
73
74
  # Check if the given object is properly implementing this interface
@@ -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
  # The introspection object for directives
7
7
  class Object::DirectiveObject < Object
8
8
  self.assigned_to = 'Rails::GraphQL::Directive'
@@ -14,19 +14,20 @@ module Rails # :nodoc:
14
14
  Directives provide a way to describe alternate runtime execution
15
15
  and type validation behavior in a GraphQL document.
16
16
 
17
- In some cases, you need to provide options to alter GraphQLs execution
17
+ In some cases, you need to provide options to alter GraphQL's execution
18
18
  behavior in ways field arguments will not suffice, such as conditionally
19
19
  including or skipping a field. Directives provide this by describing
20
20
  additional information to the executor.
21
21
  DESC
22
22
 
23
- field :name, :string, null: false, method_name: :gql_name
24
- field :description, :string
25
- field :locations, '__DirectiveLocation', full: true
26
- field :args, '__InputValue', full: true
23
+ field :name, :string, null: false, method_name: :gql_name
24
+ field :description, :string
25
+ field :locations, '__DirectiveLocation', full: true
26
+ field :args, '__InputValue', full: true
27
+ field :is_repeatable, :boolean, null: false, method_name: :repeatable?
27
28
 
28
29
  def args
29
- all_arguments.values
30
+ all_arguments.each_value
30
31
  end
31
32
  end
32
33
  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
  # The introspection object for an enum value
7
7
  class Object::EnumValueObject < Object
8
8
  self.spec_object = true
@@ -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
  # The introspection object for a field on objects and interfaces
7
7
  class Object::FieldObject < Object
8
8
  self.assigned_to = 'Rails::GraphQL::Field'
@@ -25,6 +25,14 @@ module Rails # :nodoc:
25
25
  field :is_deprecated, :boolean, null: false, method_name: :deprecated?
26
26
  field :deprecation_reason, :string
27
27
 
28
+ def description
29
+ if current.method(:description).arity == 0
30
+ current.description
31
+ else
32
+ current.description(schema.namespace)
33
+ end
34
+ end
35
+
28
36
  def build_type
29
37
  result = current.type_klass
30
38
 
@@ -38,16 +46,26 @@ module Rails # :nodoc:
38
46
  end
39
47
 
40
48
  def args
41
- all_arguments.values
49
+ all_arguments&.values || EMPTY_ARRAY
42
50
  end
43
51
 
44
52
  def deprecated?
45
- current.using?(deprecated_directive)
53
+ !deprecated_instance.nil?
46
54
  end
47
55
 
48
56
  def deprecation_reason
49
- current.all_directives.find { |item| item.is_a?(deprecated_directive) }&.args&.reason
57
+ deprecated_instance&.args&.reason
50
58
  end
59
+
60
+ private
61
+
62
+ def deprecated_instance
63
+ current.all_directives&.reverse_each do |item|
64
+ return item if item.class <= deprecated_directive
65
+ end
66
+
67
+ nil
68
+ end
51
69
  end
52
70
  end
53
71
  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
  # The introspection object for a input object
7
7
  class Object::InputValueObject < Object
8
8
  self.assigned_to = 'Rails::GraphQL::Field::InputField'
@@ -17,10 +17,9 @@ module Rails # :nodoc:
17
17
  rename! '__InputValue'
18
18
 
19
19
  desc <<~DESC
20
- Alongside with scalars and enums, input value objects allow the user
21
- to provide values to arguments on fields and directives. Different
22
- from those, input values accepts a list of keyed values, instead of
23
- a single value.
20
+ Arguments provided to Fields or Directives and the input fields of an
21
+ InputObject are represented as Input Values which describe their type
22
+ and optionally a default value.
24
23
  DESC
25
24
 
26
25
  field :name, :string, null: false, method_name: :gql_name
@@ -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
  # The introspection object for a schema object
7
7
  class Object::SchemaObject < Object
8
8
  self.assigned_to = 'Rails::GraphQL::Schema'
@@ -11,8 +11,8 @@ module Rails # :nodoc:
11
11
  rename! '__Schema'
12
12
 
13
13
  desc <<~DESC
14
- A GraphQL services collective type system capabilities are referred
15
- to as that services "schema". A schema is defined in terms of the
14
+ A GraphQL service's collective type system capabilities are referred
15
+ to as that service's "schema". A schema is defined in terms of the
16
16
  types and directives it supports as well as the root operation types
17
17
  for each kind of operation: query, mutation, and subscription; this
18
18
  determines the place in the type system where those operations begin.
@@ -24,14 +24,11 @@ module Rails # :nodoc:
24
24
  field :subscription_type, '__Type'
25
25
  field :directives, '__Directive', full: true, method_name: :read_directives
26
26
 
27
- # TODO: make it work for lazy enumerator
28
27
  def read_types
29
28
  event.schema.types(base_class: :Type).force
30
29
  end
31
30
 
32
- # TODO: it only works after eager_load!
33
31
  def read_directives
34
- Directive.eager_load!
35
32
  event.schema.types(base_class: :Directive).force
36
33
  end
37
34
  end
@@ -1,24 +1,30 @@
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
  # The introspection object for any kind of type
7
7
  class Object::TypeObject < Object
8
+ # List and not null are not actually types, but they still need to
9
+ # some how exist for introspection purposes
8
10
  FAKE_TYPES = {
9
11
  list: {
10
12
  kind: :list,
11
13
  kind_enum: 'LIST',
12
14
  name: 'List',
15
+ gql_name: nil,
13
16
  object?: true,
14
17
  description: nil,
18
+ of_type: nil,
15
19
  },
16
20
  non_null: {
17
21
  kind: :non_null,
18
22
  kind_enum: 'NON_NULL',
19
23
  name: 'Non-Null',
24
+ gql_name: nil,
20
25
  object?: true,
21
26
  description: nil,
27
+ of_type: nil,
22
28
  },
23
29
  }.freeze
24
30
 
@@ -30,7 +36,7 @@ module Rails # :nodoc:
30
36
  end
31
37
 
32
38
  def self.fake_type_object(type, subtype)
33
- OpenStruct.new(**FAKE_TYPES[type].merge(of_type: subtype))
39
+ FAKE_TYPES[type].merge(of_type: subtype)
34
40
  end
35
41
 
36
42
  rename! '__Type'
@@ -57,13 +63,15 @@ module Rails # :nodoc:
57
63
  the schema to define exactly what data is expected.
58
64
  DESC
59
65
 
60
- field :kind, '__TypeKind', null: false,
66
+ field :kind, '__TypeKind', null: false,
61
67
  method_name: :kind_enum
62
68
 
63
- field :name, :string,
69
+ field :name, :string,
64
70
  method_name: :gql_name
65
71
 
66
- field :description, :string
72
+ field :description, :string
73
+
74
+ field :specified_by_url, :string
67
75
 
68
76
  field :fields, '__Field', array: true, nullable: false do
69
77
  desc 'OBJECT and INTERFACE only'
@@ -87,48 +95,77 @@ module Rails # :nodoc:
87
95
  field :of_type, '__Type',
88
96
  desc: 'NON_NULL and LIST only'
89
97
 
98
+ def specified_by_url
99
+ return if fake_type? || !current.scalar?
100
+
101
+ current.all_directives&.find do |dir|
102
+ dir.is_a?(Directive::SpecifiedByDirective)
103
+ end&.args&.url
104
+ end
105
+
90
106
  def fields(include_deprecated:)
91
- return [] unless current.object? || current.interface?
107
+ return if fake_type? || !(current.object? || current.interface?)
108
+
109
+ list =
110
+ if current.respond_to?(:enabled_fields)
111
+ current.enabled_fields
112
+ else
113
+ current.fields.values.select(&:enabled?)
114
+ end
92
115
 
93
- list = current.fields.enum_for(:each_value)
94
- list = list.reject { |field| field.using?(deprecated_directive) } \
95
- unless include_deprecated
116
+ unless include_deprecated
117
+ list = list.reject { |field| field.using?(deprecated_directive) }
118
+ end
96
119
 
97
- list
120
+ list.reject(&:internal?).sort_by do |field|
121
+ (field.name == :id) ? '' : field.gql_name
122
+ end
98
123
  end
99
124
 
100
125
  def enum_values(include_deprecated:)
101
- return [] unless current.enum?
126
+ return if fake_type? || !current.enum?
102
127
 
103
- descs = all_value_description
128
+ descriptions = all_value_description
104
129
  deprecated = all_deprecated_values
105
130
 
106
131
  list = all_values.lazy
107
132
  list = list.reject { |value| deprecated.key?(value) } \
108
- unless include_deprecated
133
+ unless include_deprecated || deprecated.nil?
109
134
 
110
135
  list.map do |value|
111
- OpenStruct.new(
136
+ {
112
137
  name: value,
113
- description: descs[value],
114
- is_deprecated: deprecated.key?(value),
115
- deprecation_reason: deprecated[value],
116
- )
138
+ description: descriptions.try(:[], value),
139
+ is_deprecated: (deprecated.nil? ? false : deprecated.key?(value)),
140
+ deprecation_reason: deprecated.try(:[], value),
141
+ }
117
142
  end
118
143
  end
119
144
 
120
145
  def interfaces
121
- return [] unless current.object?
122
- current.all_interfaces || []
146
+ return if fake_type? || !current.object?
147
+ current.all_interfaces || EMPTY_ARRAY
123
148
  end
124
149
 
125
150
  def possible_types
126
- return all_types if current.interface?
127
- current.union? ? all_members : []
151
+ return if fake_type?
152
+
153
+ if current.interface?
154
+ current.all_types || EMPTY_ARRAY
155
+ elsif current.union?
156
+ current.all_members || EMPTY_ARRAY
157
+ end
128
158
  end
129
159
 
130
160
  def input_fields
131
- current.input? ? current.fields.enum_for(:each_value) : []
161
+ return if fake_type? || !current.input?
162
+ current.enabled_fields || EMPTY_ARRAY
163
+ end
164
+
165
+ private
166
+
167
+ def fake_type?
168
+ Hash === current
132
169
  end
133
170
  end
134
171
  end