rails-graphql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,318 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Field
6
+ #
7
+ # A field has multiple purposes, which is defined by the specific subclass
8
+ # used. They are also, in various ways, similar to arguments, since they
9
+ # tend to have the same structure.
10
+ # array as input.
11
+ #
12
+ # ==== Options
13
+ #
14
+ # * <tt>:owner</tt> - The main object that this field belongs to.
15
+ # * <tt>:null</tt> - Marks if the overall type can be null
16
+ # (defaults to true).
17
+ # * <tt>:array</tt> - Marks if the type should be wrapped as an array
18
+ # (defaults to false).
19
+ # * <tt>:nullable</tt> - Marks if the internal values of an array can be null
20
+ # (defaults to true).
21
+ # * <tt>:full</tt> - Shortcut for +null: false, nullable: false, array: true+
22
+ # (defaults to false).
23
+ # * <tt>:method_name</tt> - The name of the method used to fetch the field data
24
+ # (defaults to nil).
25
+ # * <tt>:enabled</tt> - Mark the field as enabled
26
+ # (defaults to true).
27
+ # * <tt>:disabled</tt> - Works as the oposite of the enabled option
28
+ # (defaults to false).
29
+ # * <tt>:directives</tt> - The list of directives associated with the value
30
+ # (defaults to nil).
31
+ # * <tt>:desc</tt> - The description of the argument
32
+ # (defaults to nil).
33
+ #
34
+ # It also accepts a block for further configurations
35
+ class Field
36
+ extend ActiveSupport::Autoload
37
+ include Helpers::WithDirectives
38
+
39
+ autoload :ScopedConfig
40
+
41
+ autoload :ResolvedField
42
+ autoload :TypedField
43
+ autoload :ProxiedField
44
+
45
+ autoload :InputField
46
+ autoload :OutputField
47
+ autoload :MutationField
48
+
49
+ delegate :input_type?, :output_type?, :leaf_type?, :proxy?, :mutation?, to: :class
50
+
51
+ delegate :namespaces, to: :owner
52
+
53
+ attr_reader :name, :gql_name, :owner
54
+
55
+ class << self
56
+ # A small shared helper method that allows field information to be
57
+ # proxied
58
+ def proxyable_methods(*list, klass:, allow_nil: false)
59
+ list = list.flatten.compact.map do |method_name|
60
+ ivar = '@' + method_name.delete_suffix('?')
61
+ accessor = 'field' + (allow_nil ? '&.' : '.') + method_name
62
+ "def #{method_name}; defined?(#{ivar}) ? #{ivar} : #{accessor}; end"
63
+ end
64
+
65
+ klass.class_eval(list.join("\n"), __FILE__, __LINE__ + 1)
66
+ end
67
+
68
+ # Defines if the current field is valid as an input type
69
+ def input_type?
70
+ false
71
+ end
72
+
73
+ # Defines if the current field is valid as an output type
74
+ def output_type?
75
+ false
76
+ end
77
+
78
+ # Defines if the current field is considered a leaf output
79
+ def leaf_type?
80
+ false
81
+ end
82
+
83
+ # Checks if the the field is a proxy kind of field
84
+ def proxy?
85
+ false
86
+ end
87
+
88
+ # Checks if the field is associated with a mutation
89
+ def mutation?
90
+ false
91
+ end
92
+ end
93
+
94
+ def initialize(name, owner:, **xargs, &block)
95
+ @owner = owner
96
+ normalize_name(name)
97
+
98
+ @directives = GraphQL.directives_to_set(xargs[:directives], source: self)
99
+ @method_name = xargs[:method_name].to_s.underscore.to_sym \
100
+ unless xargs[:method_name].nil?
101
+
102
+ full = xargs.fetch(:full, false)
103
+ @null = full ? false : xargs.fetch(:null, true)
104
+ @array = full ? true : xargs.fetch(:array, false)
105
+ @nullable = full ? false : xargs.fetch(:nullable, true)
106
+
107
+ @desc = xargs[:desc]&.strip_heredoc&.chomp
108
+ @enabled = xargs.fetch(:enabled, !xargs.fetch(:disabled, false))
109
+
110
+ configure(&block) if block.present?
111
+ end
112
+
113
+ def initialize_copy(*) # :nodoc:
114
+ super
115
+
116
+ @owner = nil
117
+ end
118
+
119
+ # Apply a controlled set of changes to the field
120
+ def apply_changes(**xargs, &block)
121
+ required_items! unless xargs.fetch(:nullable, true)
122
+ required! unless xargs.fetch(:null, true)
123
+ disable! if xargs.fetch(:disabled, false)
124
+ enable! if xargs.fetch(:enabled, false)
125
+
126
+ @desc = xargs[:desc].strip_heredoc.chomp if xargs.key?(:desc)
127
+ configure(&block) if block.present?
128
+ end
129
+
130
+ # Allow extra configurations to be performed using a block
131
+ def configure(&block)
132
+ Field::ScopedConfig.new(self, block.binding.receiver).instance_exec(&block)
133
+ end
134
+
135
+ # Returns the name of the method used to retrieve the information
136
+ def method_name
137
+ defined?(@method_name) ? @method_name : @name
138
+ end
139
+
140
+ # Check if the other field is equivalent
141
+ def =~(other)
142
+ other.is_a?(GraphQL::Field) &&
143
+ other.array? == array? &&
144
+ (other.null? == null? || other.null? && !null?) &&
145
+ (other.nullable? == nullable? || other.nullable? && !nullable?)
146
+ end
147
+
148
+ # Checks if the argument can be null
149
+ def null?
150
+ !!@null
151
+ end
152
+
153
+ # Checks if the argument can be an array
154
+ def array?
155
+ !!@array
156
+ end
157
+
158
+ # Checks if the argument can have null elements in the array
159
+ def nullable?
160
+ !!@nullable
161
+ end
162
+
163
+ # Check if tre field is enabled
164
+ def enabled?
165
+ !!@enabled
166
+ end
167
+
168
+ # Check if tre field is disabled
169
+ def disabled?
170
+ !enabled?
171
+ end
172
+
173
+ # Mark the field as globally enabled
174
+ def enable!
175
+ @enabled = true
176
+ end
177
+
178
+ # Mark the field as globally disabled
179
+ def disable!
180
+ @enabled = false
181
+ end
182
+
183
+ # Return the description of the argument
184
+ def description
185
+ @desc
186
+ end
187
+
188
+ # Checks if a description was provided
189
+ def description?
190
+ defined?(@desc) && !!@desc
191
+ end
192
+
193
+ # Check if the field is an internal one
194
+ def internal?
195
+ name.start_with?('__')
196
+ end
197
+
198
+ # This method must be overridden by children classes
199
+ def valid_input?(*)
200
+ enabled?
201
+ end
202
+
203
+ # This method must be overridden by children classes
204
+ def valid_output?(*)
205
+ enabled?
206
+ end
207
+
208
+ # Transforms the given value to its representation in a JSON string
209
+ def to_json(value)
210
+ return 'null' if value.nil?
211
+ return type_klass.to_json(value) unless array?
212
+ value.map { |part| type_klass.to_json(part) }
213
+ end
214
+
215
+ # Turn the given value into a JSON string representation
216
+ def as_json(value)
217
+ return if value.nil?
218
+ return type_klass.as_json(value) unless array?
219
+ value.map { |part| type_klass.as_json(part) }
220
+ end
221
+
222
+ # Turn a user input of this given type into an ruby object
223
+ def deserialize(value)
224
+ return if value.nil?
225
+ return type_klass.deserialize(value) unless array?
226
+ value.map { |val| type_klass.deserialize(val) unless val.nil? }
227
+ end
228
+
229
+ # Check if the given value is valid using +valid_input?+ or
230
+ # +valid_output?+ depending of the type of the field
231
+ def valid?(value)
232
+ input_type? ? valid_input?(value) : valid_output?(value)
233
+ end
234
+
235
+ # Checks if the definition of the field is valid.
236
+ def validate!(*)
237
+ super if defined? super
238
+
239
+ raise NameError, <<~MSG.squish if gql_name.start_with?('__') && !internal?
240
+ The name "#{gql_name}" is invalid. Only internal fields from the
241
+ spec can have a name starting with "__".
242
+ MSG
243
+ end
244
+
245
+ # Update the null value
246
+ def required!
247
+ @null = false
248
+ end
249
+
250
+ # Update the nullable value
251
+ def required_items!
252
+ @nullable = false
253
+ end
254
+
255
+ # Create a proxy of the current field
256
+ def to_proxy(*args, **xargs, &block)
257
+ proxy = self.class.allocate
258
+ proxy.extend Field::ProxiedField
259
+ proxy.send(:proxied)
260
+ proxy.send(:initialize, self, *args, **xargs, &block)
261
+ proxy
262
+ end
263
+
264
+ def inspect # :nodoc:
265
+ <<~INSPECT.squish + '>'
266
+ #<#{self.class.name}
267
+ #{inspect_owner}
268
+ #{inspect_source}
269
+ #{inspect_enabled}
270
+ #{gql_name}#{inspect_arguments}#{inspect_type}
271
+ #{inspect_default_value}
272
+ #{inspect_directives}
273
+ INSPECT
274
+ end
275
+
276
+ protected
277
+
278
+ # Allow the subclasses to define the extra inspection methods
279
+ def respond_to_missing?(method_name, *)
280
+ method_name.start_with?('inspect_') || super
281
+ end
282
+
283
+ # Allow the subclasses to define the extra inspection methods
284
+ def method_missing(method_name, *)
285
+ method_name.start_with?('inspect_') ? '' : super
286
+ end
287
+
288
+ # Ensures the consistency of the name of the field
289
+ def normalize_name(value)
290
+ return if value.blank?
291
+
292
+ @name = value.to_s.underscore.to_sym
293
+ @gql_name = @name.to_s.gsub(/^_+/, '').camelize(:lower)
294
+
295
+ if internal?
296
+ @gql_name.prepend('__')
297
+ elsif @name.start_with?('_')
298
+ @gql_name.prepend('_')
299
+ end
300
+ end
301
+
302
+ # Helper method to inspect the directives
303
+ def inspect_directives
304
+ all_directives.map(&:inspect)
305
+ end
306
+
307
+ # Show the name of the owner of the object for inspection
308
+ def inspect_owner
309
+ owner.is_a?(Module) ? owner.name : owner.class.name
310
+ end
311
+
312
+ # Add a disable tag to the inspection if the field is disabled
313
+ def inspect_enabled
314
+ '[disabled]' if disabled?
315
+ end
316
+ end
317
+ end
318
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Input Field
6
+ #
7
+ # An input field works the same way as an argument and they are pretty much
8
+ # equivalent. The main difference between an argument and a input field is
9
+ # that input fields holds object-like values and they can be inherited.
10
+ # Arguments can hold object-like values only when their type is associated
11
+ # with an InputField.
12
+ #
13
+ # ==== Options
14
+ #
15
+ # * <tt>:default</tt> - Sets a default value for the argument (defaults to nil).
16
+ # * <tt>:directives</tt> - The list of directives associated with the value
17
+ # (defaults to nil).
18
+ class Field::InputField < Field
19
+ include Field::TypedField
20
+
21
+ attr_reader :default
22
+
23
+ redefine_singleton_method(:input_type?) { true }
24
+ self.directive_location = :input_field_definition
25
+
26
+ def initialize(*args, default: nil, **xargs, &block)
27
+ super(*args, **xargs, &block)
28
+ @default = default
29
+ end
30
+
31
+ def configure # :nodoc:
32
+ raise ArgumentError, 'Input fields can\'t be further configured using blocks'
33
+ end
34
+
35
+ # Allow change the default value for the input
36
+ def apply_changes(**xargs, &block)
37
+ @default = xargs[:default] if xargs.key?(:default)
38
+ super
39
+ end
40
+
41
+ # Checks if a default value was provided
42
+ def default_value?
43
+ !default.nil?
44
+ end
45
+
46
+ # This checks if a given serialized value is valid for this field
47
+ def valid_input?(value, deep: true)
48
+ return false unless super
49
+ return null? if value.nil?
50
+ return valid_input_array?(value, deep) if array?
51
+
52
+ return true unless leaf_type? || deep
53
+ type_klass.valid_input?(value)
54
+ end
55
+
56
+ # Return the default value if the given +value+ is nil
57
+ def deserialize(value = nil)
58
+ value.nil? ? @default : super
59
+ end
60
+
61
+ # Checks if the default value of the field is valid
62
+ def validate!(*)
63
+ super if defined? super
64
+
65
+ raise ArgumentError, <<~MSG.squish unless type_klass.input_type?
66
+ The "#{type_klass.gql_name}" is not a valid input type.
67
+ MSG
68
+
69
+ raise ArgumentError, <<~MSG.squish unless default.nil? || valid_input?(default)
70
+ The given default value "#{default.inspect}" is not valid for this field.
71
+ MSG
72
+ end
73
+
74
+ protected
75
+
76
+ # Check if the given +value+ is a valid array as input
77
+ def valid_input_array?(value, deep)
78
+ return false unless value.is_a?(Array)
79
+
80
+ value.all? do |val|
81
+ (val.nil? && nullable?) || (leaf_type? || !deep) ||
82
+ type_klass.valid_input?(val)
83
+ end
84
+ end
85
+
86
+ # Display the default value when it is present for inspection
87
+ def inspect_default_value
88
+ " = #{to_hash.inspect}" if default?
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Output Field
6
+ #
7
+ # This is an extension of a normal output field, which just add extra
8
+ # validation and ensurance that the +perform+ step can be executed
9
+ class Field::MutationField < Field::OutputField
10
+ redefine_singleton_method(:mutation?) { true }
11
+
12
+ module Proxied # :nodoc: all
13
+ def performer
14
+ super || field.performer
15
+ end
16
+ end
17
+
18
+ # Add a block or a callable method that is executed before the resolver
19
+ # but after all the before resolve
20
+ def perform(*args, **xargs, &block)
21
+ @performer = Callback.new(self, :perform, *args, **xargs, &block)
22
+ end
23
+
24
+ # Get the performer that can be already defined or used through the
25
+ # +method_name+ if that is callable
26
+ def performer
27
+ @performer ||= callable?(method_name) \
28
+ ? Callback.new(self, :perform, method_name) \
29
+ : false
30
+ end
31
+
32
+ # Ensures that the performer is defined
33
+ def validate!(*)
34
+ super if defined? super
35
+
36
+ raise ValidationError, <<~MSG.squish unless performer.present?
37
+ The "#{gql_name}" mutation field must have a perform action through a given
38
+ block or a method named #{method_name} on #{owner.class.name}.
39
+ MSG
40
+ end
41
+
42
+ protected
43
+
44
+ def proxied # :nodoc:
45
+ super if defined? super
46
+ extend Field::MutationField::Proxied
47
+ end
48
+ end
49
+
50
+ Field::ScopedConfig.delegate :perform, to: :field
51
+ end
52
+ end