rails-graphql 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +19 -0
  4. data/Rakefile +31 -0
  5. data/ext/depend +3 -0
  6. data/ext/extconf.rb +57 -0
  7. data/ext/graphqlparser/Ast.cpp +346 -0
  8. data/ext/graphqlparser/Ast.h +1214 -0
  9. data/ext/graphqlparser/AstNode.h +36 -0
  10. data/ext/graphqlparser/AstVisitor.h +137 -0
  11. data/ext/graphqlparser/GraphQLParser.cpp +76 -0
  12. data/ext/graphqlparser/GraphQLParser.h +55 -0
  13. data/ext/graphqlparser/JsonVisitor.cpp +161 -0
  14. data/ext/graphqlparser/JsonVisitor.cpp.inc +456 -0
  15. data/ext/graphqlparser/JsonVisitor.h +121 -0
  16. data/ext/graphqlparser/JsonVisitor.h.inc +110 -0
  17. data/ext/graphqlparser/VERSION +1 -0
  18. data/ext/graphqlparser/c/GraphQLAst.cpp +324 -0
  19. data/ext/graphqlparser/c/GraphQLAst.h +180 -0
  20. data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +44 -0
  21. data/ext/graphqlparser/c/GraphQLAstNode.cpp +25 -0
  22. data/ext/graphqlparser/c/GraphQLAstNode.h +33 -0
  23. data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +21 -0
  24. data/ext/graphqlparser/c/GraphQLAstToJSON.h +24 -0
  25. data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +55 -0
  26. data/ext/graphqlparser/c/GraphQLAstVisitor.h +53 -0
  27. data/ext/graphqlparser/c/GraphQLParser.cpp +35 -0
  28. data/ext/graphqlparser/c/GraphQLParser.h +54 -0
  29. data/ext/graphqlparser/dump_json_ast.cpp +48 -0
  30. data/ext/graphqlparser/lexer.lpp +324 -0
  31. data/ext/graphqlparser/parser.ypp +693 -0
  32. data/ext/graphqlparser/parsergen/lexer.cpp +2633 -0
  33. data/ext/graphqlparser/parsergen/lexer.h +528 -0
  34. data/ext/graphqlparser/parsergen/location.hh +189 -0
  35. data/ext/graphqlparser/parsergen/parser.tab.cpp +3300 -0
  36. data/ext/graphqlparser/parsergen/parser.tab.hpp +646 -0
  37. data/ext/graphqlparser/parsergen/position.hh +179 -0
  38. data/ext/graphqlparser/parsergen/stack.hh +156 -0
  39. data/ext/graphqlparser/syntaxdefs.h +19 -0
  40. data/ext/libgraphqlparser/AstNode.h +36 -0
  41. data/ext/libgraphqlparser/CMakeLists.txt +148 -0
  42. data/ext/libgraphqlparser/CONTRIBUTING.md +23 -0
  43. data/ext/libgraphqlparser/GraphQLParser.cpp +76 -0
  44. data/ext/libgraphqlparser/GraphQLParser.h +55 -0
  45. data/ext/libgraphqlparser/JsonVisitor.cpp +161 -0
  46. data/ext/libgraphqlparser/JsonVisitor.h +121 -0
  47. data/ext/libgraphqlparser/LICENSE +22 -0
  48. data/ext/libgraphqlparser/README.clang-tidy +7 -0
  49. data/ext/libgraphqlparser/README.md +84 -0
  50. data/ext/libgraphqlparser/ast/ast.ast +203 -0
  51. data/ext/libgraphqlparser/ast/ast.py +61 -0
  52. data/ext/libgraphqlparser/ast/c.py +100 -0
  53. data/ext/libgraphqlparser/ast/c.pyc +0 -0
  54. data/ext/libgraphqlparser/ast/c_impl.py +61 -0
  55. data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
  56. data/ext/libgraphqlparser/ast/c_visitor_impl.py +39 -0
  57. data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
  58. data/ext/libgraphqlparser/ast/casing.py +26 -0
  59. data/ext/libgraphqlparser/ast/casing.pyc +0 -0
  60. data/ext/libgraphqlparser/ast/cxx.py +197 -0
  61. data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
  62. data/ext/libgraphqlparser/ast/cxx_impl.py +61 -0
  63. data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
  64. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +42 -0
  65. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
  66. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +80 -0
  67. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
  68. data/ext/libgraphqlparser/ast/cxx_visitor.py +64 -0
  69. data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
  70. data/ext/libgraphqlparser/ast/js.py +65 -0
  71. data/ext/libgraphqlparser/ast/license.py +10 -0
  72. data/ext/libgraphqlparser/ast/license.pyc +0 -0
  73. data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +25 -0
  74. data/ext/libgraphqlparser/c/GraphQLAstNode.h +33 -0
  75. data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +21 -0
  76. data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +24 -0
  77. data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +55 -0
  78. data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +53 -0
  79. data/ext/libgraphqlparser/c/GraphQLParser.cpp +35 -0
  80. data/ext/libgraphqlparser/c/GraphQLParser.h +54 -0
  81. data/ext/libgraphqlparser/clang-tidy-all.sh +3 -0
  82. data/ext/libgraphqlparser/cmake/version.cmake +16 -0
  83. data/ext/libgraphqlparser/dump_json_ast.cpp +48 -0
  84. data/ext/libgraphqlparser/go/README.md +20 -0
  85. data/ext/libgraphqlparser/go/callbacks.go +18 -0
  86. data/ext/libgraphqlparser/go/gotest.go +64 -0
  87. data/ext/libgraphqlparser/lexer.lpp +324 -0
  88. data/ext/libgraphqlparser/libgraphqlparser.pc.in +11 -0
  89. data/ext/libgraphqlparser/parser.ypp +693 -0
  90. data/ext/libgraphqlparser/parsergen/lexer.cpp +2633 -0
  91. data/ext/libgraphqlparser/parsergen/lexer.h +528 -0
  92. data/ext/libgraphqlparser/parsergen/location.hh +189 -0
  93. data/ext/libgraphqlparser/parsergen/parser.tab.cpp +3300 -0
  94. data/ext/libgraphqlparser/parsergen/parser.tab.hpp +646 -0
  95. data/ext/libgraphqlparser/parsergen/position.hh +179 -0
  96. data/ext/libgraphqlparser/parsergen/stack.hh +156 -0
  97. data/ext/libgraphqlparser/python/CMakeLists.txt +14 -0
  98. data/ext/libgraphqlparser/python/README.md +5 -0
  99. data/ext/libgraphqlparser/python/example.py +31 -0
  100. data/ext/libgraphqlparser/syntaxdefs.h +19 -0
  101. data/ext/libgraphqlparser/test/BuildCAPI.c +5 -0
  102. data/ext/libgraphqlparser/test/CMakeLists.txt +25 -0
  103. data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +28 -0
  104. data/ext/libgraphqlparser/test/ParserTests.cpp +352 -0
  105. data/ext/libgraphqlparser/test/kitchen-sink.graphql +59 -0
  106. data/ext/libgraphqlparser/test/kitchen-sink.json +1 -0
  107. data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +78 -0
  108. data/ext/libgraphqlparser/test/schema-kitchen-sink.json +1 -0
  109. data/ext/libgraphqlparser/test/valgrind.supp +33 -0
  110. data/ext/version.cpp +21 -0
  111. data/lib/generators/graphql/controller_generator.rb +22 -0
  112. data/lib/generators/graphql/schema_generator.rb +22 -0
  113. data/lib/generators/graphql/templates/controller.erb +5 -0
  114. data/lib/generators/graphql/templates/schema.erb +6 -0
  115. data/lib/graphqlparser.so +0 -0
  116. data/lib/rails-graphql.rb +2 -0
  117. data/lib/rails/graphql.rake +1 -0
  118. data/lib/rails/graphql.rb +185 -0
  119. data/lib/rails/graphql/adapters/mysql_adapter.rb +0 -0
  120. data/lib/rails/graphql/adapters/pg_adapter.rb +50 -0
  121. data/lib/rails/graphql/adapters/sqlite_adapter.rb +39 -0
  122. data/lib/rails/graphql/argument.rb +220 -0
  123. data/lib/rails/graphql/callback.rb +124 -0
  124. data/lib/rails/graphql/collectors.rb +14 -0
  125. data/lib/rails/graphql/collectors/hash_collector.rb +83 -0
  126. data/lib/rails/graphql/collectors/idented_collector.rb +73 -0
  127. data/lib/rails/graphql/collectors/json_collector.rb +114 -0
  128. data/lib/rails/graphql/config.rb +61 -0
  129. data/lib/rails/graphql/directive.rb +203 -0
  130. data/lib/rails/graphql/directive/deprecated_directive.rb +59 -0
  131. data/lib/rails/graphql/directive/include_directive.rb +24 -0
  132. data/lib/rails/graphql/directive/skip_directive.rb +24 -0
  133. data/lib/rails/graphql/errors.rb +42 -0
  134. data/lib/rails/graphql/event.rb +141 -0
  135. data/lib/rails/graphql/field.rb +318 -0
  136. data/lib/rails/graphql/field/input_field.rb +92 -0
  137. data/lib/rails/graphql/field/mutation_field.rb +52 -0
  138. data/lib/rails/graphql/field/output_field.rb +96 -0
  139. data/lib/rails/graphql/field/proxied_field.rb +131 -0
  140. data/lib/rails/graphql/field/resolved_field.rb +96 -0
  141. data/lib/rails/graphql/field/scoped_config.rb +22 -0
  142. data/lib/rails/graphql/field/typed_field.rb +104 -0
  143. data/lib/rails/graphql/helpers.rb +40 -0
  144. data/lib/rails/graphql/helpers/attribute_delegator.rb +39 -0
  145. data/lib/rails/graphql/helpers/inherited_collection.rb +152 -0
  146. data/lib/rails/graphql/helpers/leaf_from_ar.rb +141 -0
  147. data/lib/rails/graphql/helpers/registerable.rb +103 -0
  148. data/lib/rails/graphql/helpers/with_arguments.rb +125 -0
  149. data/lib/rails/graphql/helpers/with_assignment.rb +113 -0
  150. data/lib/rails/graphql/helpers/with_callbacks.rb +55 -0
  151. data/lib/rails/graphql/helpers/with_directives.rb +126 -0
  152. data/lib/rails/graphql/helpers/with_events.rb +81 -0
  153. data/lib/rails/graphql/helpers/with_fields.rb +141 -0
  154. data/lib/rails/graphql/helpers/with_namespace.rb +40 -0
  155. data/lib/rails/graphql/helpers/with_owner.rb +35 -0
  156. data/lib/rails/graphql/helpers/with_schema_fields.rb +230 -0
  157. data/lib/rails/graphql/helpers/with_validator.rb +52 -0
  158. data/lib/rails/graphql/introspection.rb +53 -0
  159. data/lib/rails/graphql/native.rb +56 -0
  160. data/lib/rails/graphql/native/functions.rb +38 -0
  161. data/lib/rails/graphql/native/location.rb +41 -0
  162. data/lib/rails/graphql/native/pointers.rb +23 -0
  163. data/lib/rails/graphql/native/visitor.rb +349 -0
  164. data/lib/rails/graphql/railtie.rb +85 -0
  165. data/lib/rails/graphql/railties/base_generator.rb +35 -0
  166. data/lib/rails/graphql/railties/controller.rb +101 -0
  167. data/lib/rails/graphql/railties/controller_runtime.rb +40 -0
  168. data/lib/rails/graphql/railties/log_subscriber.rb +62 -0
  169. data/lib/rails/graphql/request.rb +343 -0
  170. data/lib/rails/graphql/request/arguments.rb +93 -0
  171. data/lib/rails/graphql/request/component.rb +100 -0
  172. data/lib/rails/graphql/request/component/field.rb +225 -0
  173. data/lib/rails/graphql/request/component/fragment.rb +118 -0
  174. data/lib/rails/graphql/request/component/operation.rb +178 -0
  175. data/lib/rails/graphql/request/component/operation/subscription.rb +16 -0
  176. data/lib/rails/graphql/request/component/spread.rb +119 -0
  177. data/lib/rails/graphql/request/component/typename.rb +82 -0
  178. data/lib/rails/graphql/request/context.rb +51 -0
  179. data/lib/rails/graphql/request/errors.rb +54 -0
  180. data/lib/rails/graphql/request/event.rb +112 -0
  181. data/lib/rails/graphql/request/helpers/directives.rb +64 -0
  182. data/lib/rails/graphql/request/helpers/selection_set.rb +87 -0
  183. data/lib/rails/graphql/request/helpers/value_writers.rb +115 -0
  184. data/lib/rails/graphql/request/steps/organizable.rb +146 -0
  185. data/lib/rails/graphql/request/steps/prepareable.rb +33 -0
  186. data/lib/rails/graphql/request/steps/resolveable.rb +32 -0
  187. data/lib/rails/graphql/request/strategy.rb +249 -0
  188. data/lib/rails/graphql/request/strategy/dynamic_instance.rb +41 -0
  189. data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +36 -0
  190. data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +28 -0
  191. data/lib/rails/graphql/schema.rb +272 -0
  192. data/lib/rails/graphql/shortcuts.rb +77 -0
  193. data/lib/rails/graphql/source.rb +371 -0
  194. data/lib/rails/graphql/source/active_record/builders.rb +154 -0
  195. data/lib/rails/graphql/source/active_record_source.rb +231 -0
  196. data/lib/rails/graphql/source/scoped_arguments.rb +87 -0
  197. data/lib/rails/graphql/to_gql.rb +368 -0
  198. data/lib/rails/graphql/type.rb +138 -0
  199. data/lib/rails/graphql/type/enum.rb +206 -0
  200. data/lib/rails/graphql/type/enum/directive_location_enum.rb +30 -0
  201. data/lib/rails/graphql/type/enum/type_kind_enum.rb +57 -0
  202. data/lib/rails/graphql/type/input.rb +134 -0
  203. data/lib/rails/graphql/type/interface.rb +82 -0
  204. data/lib/rails/graphql/type/object.rb +111 -0
  205. data/lib/rails/graphql/type/object/directive_object.rb +34 -0
  206. data/lib/rails/graphql/type/object/enum_value_object.rb +25 -0
  207. data/lib/rails/graphql/type/object/field_object.rb +54 -0
  208. data/lib/rails/graphql/type/object/input_value_object.rb +49 -0
  209. data/lib/rails/graphql/type/object/schema_object.rb +40 -0
  210. data/lib/rails/graphql/type/object/type_object.rb +136 -0
  211. data/lib/rails/graphql/type/scalar.rb +71 -0
  212. data/lib/rails/graphql/type/scalar/bigint_scalar.rb +34 -0
  213. data/lib/rails/graphql/type/scalar/binary_scalar.rb +30 -0
  214. data/lib/rails/graphql/type/scalar/boolean_scalar.rb +37 -0
  215. data/lib/rails/graphql/type/scalar/date_scalar.rb +34 -0
  216. data/lib/rails/graphql/type/scalar/date_time_scalar.rb +32 -0
  217. data/lib/rails/graphql/type/scalar/decimal_scalar.rb +35 -0
  218. data/lib/rails/graphql/type/scalar/float_scalar.rb +32 -0
  219. data/lib/rails/graphql/type/scalar/id_scalar.rb +39 -0
  220. data/lib/rails/graphql/type/scalar/int_scalar.rb +36 -0
  221. data/lib/rails/graphql/type/scalar/string_scalar.rb +28 -0
  222. data/lib/rails/graphql/type/scalar/time_scalar.rb +40 -0
  223. data/lib/rails/graphql/type/union.rb +87 -0
  224. data/lib/rails/graphql/type_map.rb +347 -0
  225. data/lib/rails/graphql/version.rb +7 -0
  226. data/test/assets/introspection-db.json +0 -0
  227. data/test/assets/introspection-mem.txt +1 -0
  228. data/test/assets/introspection.gql +91 -0
  229. data/test/assets/luke.jpg +0 -0
  230. data/test/assets/mem.gql +428 -0
  231. data/test/assets/sqlite.gql +423 -0
  232. data/test/config.rb +80 -0
  233. data/test/graphql/request/context_test.rb +70 -0
  234. data/test/graphql/schema_test.rb +190 -0
  235. data/test/graphql/source_test.rb +237 -0
  236. data/test/graphql/type/enum_test.rb +203 -0
  237. data/test/graphql/type/input_test.rb +138 -0
  238. data/test/graphql/type/interface_test.rb +72 -0
  239. data/test/graphql/type/object_test.rb +104 -0
  240. data/test/graphql/type/scalar/bigint_scalar_test.rb +42 -0
  241. data/test/graphql/type/scalar/binary_scalar_test.rb +17 -0
  242. data/test/graphql/type/scalar/boolean_scalar_test.rb +40 -0
  243. data/test/graphql/type/scalar/date_scalar_test.rb +29 -0
  244. data/test/graphql/type/scalar/date_time_scalar_test.rb +29 -0
  245. data/test/graphql/type/scalar/decimal_scalar_test.rb +28 -0
  246. data/test/graphql/type/scalar/float_scalar_test.rb +22 -0
  247. data/test/graphql/type/scalar/id_scalar_test.rb +26 -0
  248. data/test/graphql/type/scalar/int_scalar_test.rb +26 -0
  249. data/test/graphql/type/scalar/string_scalar_test.rb +17 -0
  250. data/test/graphql/type/scalar/time_scalar_test.rb +36 -0
  251. data/test/graphql/type/scalar_test.rb +45 -0
  252. data/test/graphql/type/union_test.rb +82 -0
  253. data/test/graphql/type_map_test.rb +362 -0
  254. data/test/graphql/type_test.rb +68 -0
  255. data/test/graphql_test.rb +55 -0
  256. data/test/integration/config.rb +56 -0
  257. data/test/integration/memory/star_wars_introspection_test.rb +144 -0
  258. data/test/integration/memory/star_wars_query_test.rb +184 -0
  259. data/test/integration/memory/star_wars_validation_test.rb +99 -0
  260. data/test/integration/schemas/memory.rb +232 -0
  261. data/test/integration/schemas/sqlite.rb +82 -0
  262. data/test/integration/sqlite/star_wars_introspection_test.rb +15 -0
  263. data/test/integration/sqlite/star_wars_mutation_test.rb +82 -0
  264. data/test/integration/sqlite/star_wars_query_test.rb +71 -0
  265. data/test/test_ext.rb +48 -0
  266. metadata +509 -0
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Output Field
6
+ #
7
+ # Most of the fields in a GraphQL operation are output fields or similar or
8
+ # proxies of it. They can express both leaf and branch data. They can also
9
+ # be the entry point of a GraphQL request.
10
+ class Field::OutputField < Field
11
+ include Helpers::WithArguments
12
+ include Helpers::WithValidator
13
+ include Field::ResolvedField
14
+ include Field::TypedField
15
+
16
+ module Proxied # :nodoc: all
17
+ def initialize(*args, **xargs, &block)
18
+ @method_name = xargs.delete(:method_name) if xargs.key?(:method_name)
19
+ super(*args, **xargs, &block)
20
+ end
21
+
22
+ def all_arguments
23
+ field.arguments.merge(super)
24
+ end
25
+
26
+ def has_argument?(name)
27
+ super || field.has_argument?(name)
28
+ end
29
+ end
30
+
31
+ redefine_singleton_method(:output_type?) { true }
32
+ self.directive_location = :field_definition
33
+
34
+ def initialize(*args, method_name: nil, deprecated: false, **xargs, &block)
35
+ @method_name = method_name.to_s.underscore.to_sym unless method_name.nil?
36
+
37
+ if deprecated.present?
38
+ xargs[:directives] = Array.wrap(xargs[:directives])
39
+ xargs[:directives] << Directive::DeprecatedDirective.new(
40
+ reason: (deprecated.is_a?(String) ? deprecated : nil),
41
+ )
42
+ end
43
+
44
+ super(*args, **xargs, &block)
45
+ end
46
+
47
+ # Check if the arguments are also equivalent
48
+ def =~(other)
49
+ super && match_arguments?(other)
50
+ end
51
+
52
+ # Checks if a given unserialized value is valid for this field
53
+ def valid_output?(value, deep: true)
54
+ return false unless super
55
+ return null? if value.nil?
56
+ return valid_output_array?(value, deep) if array?
57
+
58
+ return true unless leaf_type? || deep
59
+ type_klass.valid_output?(value)
60
+ end
61
+
62
+ # Trigger the exception based value validator
63
+ def validate_output!(value, **xargs)
64
+ super(value, :field, **xargs)
65
+ rescue ValidationError => error
66
+ raise InvalidValueError, error.message
67
+ end
68
+
69
+ # Checks if the default value of the field is valid
70
+ def validate!(*)
71
+ super if defined? super
72
+
73
+ raise ArgumentError, <<~MSG.squish unless type_klass.output_type?
74
+ The "#{type_klass.gql_name}" is not a valid output type.
75
+ MSG
76
+ end
77
+
78
+ protected
79
+
80
+ # Check if the given +value+ is a valid array as output
81
+ def valid_output_array?(value, deep)
82
+ return false unless value.is_a?(Enumerable)
83
+
84
+ value.all? do |val|
85
+ (val.nil? && nullable?) || (leaf_type? || !deep) ||
86
+ type_klass.valid_output?(val)
87
+ end
88
+ end
89
+
90
+ def proxied # :nodoc:
91
+ super if defined? super
92
+ extend Field::OutputField::Proxied
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Proxied Field
6
+ #
7
+ # Proxied fields are a soft way to copy a real field. The good part is that
8
+ # if the field changes for any reason all its copies will change as well.
9
+ #
10
+ # The owner of a proxy field is different from the owner of the actual field
11
+ # but that doesn't affect the field operations.
12
+ #
13
+ # Proxied field also supports aliases, which helps implementing independent
14
+ # fields and then providing them as proxy to other objects.
15
+ #
16
+ # Proxies can be created from any kind of input
17
+ #
18
+ # ==== Options
19
+ #
20
+ # It accepts all the options of any other type of field plus the following
21
+ #
22
+ # * <tt>:owner</tt> - The main object that this field belongs to.
23
+ # * <tt>:as</tt> - The actual name to be used on the field while assigning
24
+ # the proxy (defaults to nil).
25
+ # * <tt>:alias</tt> - Same as the +:as+ key (defaults to nil).
26
+ module Field::ProxiedField
27
+ delegate_missing_to :field
28
+ delegate :leaf_type?, :array?, :internal?, :valid_input?, :valid_output?,
29
+ :to_json, :as_json, :deserialize, :valid?, to: :field
30
+
31
+ Field.proxyable_methods %w[name gql_name method_name resolver description
32
+ null? nullable? enabled?], klass: self
33
+
34
+ def initialize(field, owner:, **xargs, &block)
35
+ @field = field
36
+ @owner = owner
37
+
38
+ apply_changes(**xargs, &block)
39
+ end
40
+
41
+ # Once this module is added then the field becomes a proxy
42
+ def proxy?
43
+ true
44
+ end
45
+
46
+ # Allow chaging most of the general kind-independent initialize settings
47
+ def apply_changes(**xargs, &block)
48
+ if (deprecated = xargs[:deprecated])
49
+ xargs[:directives] = Array.wrap(xargs[:directives])
50
+ xargs[:directives] << Directive::DeprecatedDirective.new(
51
+ reason: (deprecated.is_a?(String) ? deprecated : nil),
52
+ )
53
+ end
54
+
55
+ @directives = GraphQL.directives_to_set(xargs[:directives], source: self) \
56
+ if xargs.key?(:directives)
57
+
58
+ @desc = xargs[:desc]&.strip_heredoc&.chomp if xargs.key?(:desc)
59
+ @enabled = xargs.fetch(:enabled, !xargs.fetch(:disabled, false)) \
60
+ if xargs.key?(:enabled) || xargs.key?(:disabled)
61
+
62
+ normalize_name(xargs.fetch(:alias, xargs[:as]))
63
+ super
64
+ end
65
+
66
+ # Return the original owner from +field+
67
+ def proxied_owner
68
+ field.owner
69
+ end
70
+
71
+ # Return the proxied field
72
+ def proxied_field
73
+ @field
74
+ end
75
+
76
+ def disable! # :nodoc:
77
+ super unless non_interface_proxy!('disable')
78
+ end
79
+
80
+ def enable! # :nodoc:
81
+ super unless non_interface_proxy!('enable')
82
+ end
83
+
84
+ def all_directives # :nodoc:
85
+ field.all_directives + super
86
+ end
87
+
88
+ # It is important to ensure that the proxied field is also valid. If the
89
+ # proxied owner is registered, then it is safe to assume that it is valid
90
+ def validate!(*)
91
+ super if defined? super
92
+ field.validate! unless GraphQL.type_map.object_exist?(
93
+ proxied_owner,
94
+ namespaces: namespaces,
95
+ exclusive: true,
96
+ )
97
+ end
98
+
99
+ protected
100
+
101
+ alias field proxied_field
102
+
103
+ def normalize_name(value) # :nodoc:
104
+ super unless value.blank? || non_interface_proxy!('rename')
105
+ end
106
+
107
+ # Prohibits changes to proxy fields based on interfaces
108
+ def non_interface_proxy!(action)
109
+ raise ::ArgymentError, <<~MSG.squish if interface_proxy?
110
+ Unable to #{action} the "#{gql_name}" field because it is
111
+ associated to the #{field.owner.name} interface.
112
+ MSG
113
+ end
114
+
115
+ # Checks if the proxy is based on an interface field
116
+ def interface_proxy?
117
+ field.owner.try(:interface?)
118
+ end
119
+
120
+ # Display the source of the proxy for inspection
121
+ def inspect_source
122
+ "@source=#{proxied_owner.name}[:#{field.name}] [proxied]"
123
+ end
124
+
125
+ # This is trigerred when the field is proxied
126
+ def proxied
127
+ super if defined? super
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # This provides ways for fields to be resolved manually, by adding callbacks
6
+ # and additional configurations in order to resolve a field value during a
7
+ # request
8
+ module Field::ResolvedField
9
+ module Proxied # :nodoc: all
10
+ def all_listeners
11
+ field.all_listeners + super
12
+ end
13
+
14
+ def all_events
15
+ events = defined?(@events) ? @events : {}
16
+ Helpers.merge_hash_array(field.all_events, events).transform_values do |arr|
17
+ arr.sort_by { |cb| cb.try(:target).is_a?(GraphQL::Field) ? 0 : 1 }
18
+ end
19
+ end
20
+
21
+ def resolver
22
+ super || field.resolver
23
+ end
24
+
25
+ def dynamic_resolver?
26
+ super || field.dynamic_resolver?
27
+ end
28
+ end
29
+
30
+ # Just add the callbacks setup to the field
31
+ def self.included(other)
32
+ other.include(Helpers::WithEvents)
33
+ other.include(Helpers::WithCallbacks)
34
+ other.event_types(:prepare, :finalize, expose: true)
35
+ other.alias_method(:before_resolve, :prepare)
36
+ other.alias_method(:after_resolve, :finalize)
37
+ end
38
+
39
+ # Add a block that is performed while resolving a value of a field
40
+ def resolve(*args, **xargs, &block)
41
+ @resolver = Callback.new(self, :resolve, *args, **xargs, &block)
42
+ end
43
+
44
+ # Get the resolver that can be already defined or used through the
45
+ # +method_name+
46
+ def resolver
47
+ return unless dynamic_resolver?
48
+ @resolver ||= Callback.new(self, :resolve, method_name)
49
+ end
50
+
51
+ # Check if the field has a dynamic resolver
52
+ def dynamic_resolver?
53
+ if defined?(@dynamic_resolver)
54
+ @dynamic_resolver
55
+ elsif defined?(@resolver)
56
+ @resolver.present?
57
+ else
58
+ callable?(method_name)
59
+ end
60
+ end
61
+
62
+ # Checks if all the named callbacks can actually be called
63
+ def validate!(*)
64
+ super if defined? super
65
+
66
+ # Store this result for performance purposes
67
+ @dynamic_resolver = dynamic_resolver?
68
+ return unless defined? @events
69
+
70
+ invalid = @events.each_value.reject do |callback|
71
+ callback.block.is_a?(Proc) || callable?(callback.block)
72
+ end
73
+
74
+ raise ArgumentError, <<~MSG.squish if invalid.present?
75
+ The "#{owner.name}" class does not define the following methods needed
76
+ for performing hooks: #{invalid.map(&:block).to_sentence}.
77
+ MSG
78
+ end
79
+
80
+ protected
81
+
82
+ # Chedck if a given +method_name+ is callable from the owner perspective
83
+ def callable?(method_name)
84
+ owner.is_a?(Class) && owner.try(:gql_resolver?, method_name)
85
+ end
86
+
87
+ def proxied # :nodoc:
88
+ super if defined? super
89
+ extend Field::ResolvedField::Proxied
90
+ end
91
+ end
92
+
93
+ Field::ScopedConfig.delegate :before_resolve, :after_resolve,
94
+ :prepare, :finalize, :resolve, to: :field
95
+ end
96
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # Helper class to be used while configuring a field using a block. An
6
+ # instance of this class works as proxy for changes to the actual field.
7
+ Field::ScopedConfig = Struct.new(:field, :receiver) do
8
+ delegate :argument, :ref_argument, :id_argument, :use, :internal?, :disabled?,
9
+ :enabled?, :disable!, :enable!, to: :field
10
+
11
+ delegate_missing_to :receiver
12
+
13
+ def method_name(value)
14
+ field.instance_variable_set(:@method_name, value.to_sym)
15
+ end
16
+
17
+ def desc(value)
18
+ field.instance_variable_set(:@desc, value.strip_heredoc.chomp)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # This is a helper module that basically works with fields that have an
6
+ # assigned type value
7
+ module Field::TypedField
8
+ module Proxied # :nodoc: all
9
+ delegate :type, to: :field
10
+ end
11
+
12
+ attr_reader :type
13
+
14
+ delegate :input_type?, :output_type?, :leaf_type?, :kind, to: :type_klass
15
+
16
+ def initialize(name, type, *args, **xargs, &block)
17
+ if type.is_a?(Module) && type < GraphQL::Type
18
+ @type_klass = type
19
+ @type = type.to_sym
20
+ else
21
+ @type = type.to_s.underscore.to_sym
22
+ end
23
+
24
+ super(name, *args, **xargs, &block)
25
+ end
26
+
27
+ def initialize_copy(*)
28
+ super
29
+
30
+ @type_klass = nil
31
+ end
32
+
33
+ # Check if types are compatible
34
+ def =~(other)
35
+ other.is_a?(Field::TypedField) && other.type_klass =~ type_klass && super
36
+ end
37
+
38
+ # Sometimes the owner does not designate this, but it is safe to assume it
39
+ # will be associated to the object valyd types
40
+ def valid_field_types
41
+ owner.try(:valid_field_types) || Type::Object.valid_field_types
42
+ end
43
+
44
+ # A little extension of the +is_a?+ method that allows checking it using
45
+ # the +type_klass+
46
+ def of_type?(klass)
47
+ is_a?(klass) || type_klass <= klass
48
+ end
49
+
50
+ # Return the class of the type object
51
+ def type_klass
52
+ @type_klass ||= GraphQL.type_map.fetch!(type,
53
+ prevent_register: owner,
54
+ namespaces: namespaces,
55
+ )
56
+ end
57
+
58
+ # Add the listeners from the associated type
59
+ def all_listeners
60
+ type_klass.all_listeners + super
61
+ end
62
+
63
+ # Add the events from the associated type
64
+ def all_events
65
+ Helpers.merge_hash_array(type_klass.all_events, super)
66
+ end
67
+
68
+ # Checks if the type of the field is valid
69
+ def validate!(*)
70
+ super if defined? super
71
+
72
+ raise ArgumentError, <<~MSG.squish unless type_klass.is_a?(Module)
73
+ Unable to find the "#{type.inspect}" input type on GraphQL context.
74
+ MSG
75
+
76
+ valid_type = valid_field_types.empty? || valid_field_types.any? do |base_type|
77
+ type_klass < base_type
78
+ end
79
+
80
+ raise ArgumentError, <<~MSG.squish unless valid_type
81
+ The "#{type_klass.base_type}" is not accepted in this context.
82
+ MSG
83
+ end
84
+
85
+ protected
86
+
87
+ # Little helper that shows the type of the field
88
+ def inspect_type
89
+ result = ': '
90
+ result += '[' if array?
91
+ result += type_klass.gql_name
92
+ result += '!' if array? && !nullable?
93
+ result += ']' if array?
94
+ result += '!' unless null?
95
+ result
96
+ end
97
+
98
+ def proxied # :nodoc:
99
+ super if defined? super
100
+ extend Field::TypedField::Proxied
101
+ end
102
+ end
103
+ end
104
+ end