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,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Helpers # :nodoc:
6
+ # Helper module that allows other objects to hold arguments
7
+ module WithArguments
8
+ def self.extended(other)
9
+ other.extend(Helpers::InheritedCollection)
10
+ other.extend(WithArguments::ClassMethods)
11
+ other.inherited_collection(:arguments, type: :hash)
12
+ end
13
+
14
+ def self.included(other)
15
+ other.define_method(:arguments) do
16
+ defined?(@arguments) ? @arguments : {}
17
+ end
18
+ end
19
+
20
+ module ClassMethods # :nodoc: all
21
+ def inherited(subclass)
22
+ super if defined? super
23
+ return if arguments.empty?
24
+
25
+ new_arguments = Helpers.dup_all_with_owner(arguments.transform_values, subclass)
26
+ subclass.instance_variable_set(:@arguments, new_arguments)
27
+ end
28
+ end
29
+
30
+ def initialize(*args, arguments: nil, **xargs, &block)
31
+ @arguments = Array.wrap(arguments).map do |object|
32
+ raise ArgumentError, <<~MSG.squish unless object.is_a?(Argument)
33
+ The given "#{object.inspect}" is not a valid Argument object.
34
+ MSG
35
+
36
+ [object.name, Helpers.dup_with_owner(object, self)]
37
+ end.to_h unless arguments.nil?
38
+
39
+ super(*args, **xargs, &block)
40
+ end
41
+
42
+ def initialize_copy(orig)
43
+ super
44
+
45
+ @arguments = Helpers.dup_all_with_owner(orig.arguments.transform_values, self)
46
+ end
47
+
48
+ # Check if all the arguments are compatible
49
+ def =~(other)
50
+ super && other.respond_to?(:all_arguments) && match_arguments?(other)
51
+ end
52
+
53
+ # Mostly for correct inheritance on instances
54
+ def all_arguments
55
+ defined?(@arguments) ? @arguments : {}
56
+ end
57
+
58
+ # See {Argument}[rdoc-ref:Rails::GraphQL::Argument] class.
59
+ def argument(name, base_type, **xargs)
60
+ xargs[:owner] = self
61
+ object = GraphQL::Argument.new(name, base_type, **xargs)
62
+
63
+ raise DuplicatedError, <<~MSG.squish if has_argument?(object.name)
64
+ The #{name.inspect} argument is already defined and can't be redefined.
65
+ MSG
66
+
67
+ (@arguments ||= {})[object.name] = object
68
+ rescue DefinitionError => e
69
+ raise e.class, e.message + "\n Defined at: #{caller(2)[0]}"
70
+ end
71
+
72
+ # Since arguments' owner are more flexible, their instances can be
73
+ # directly associated to objects that have argument
74
+ def ref_argument(object)
75
+ raise ArgumentError, <<~MSG.squish unless object.is_a?(GraphQL::Argument)
76
+ The given object #{object.inspect} is not a valid argument.
77
+ MSG
78
+
79
+ raise DuplicatedError, <<~MSG.squish if has_argument?(object.name)
80
+ The #{object.name.inspect} argument is already defined and can't be redefined.
81
+ MSG
82
+
83
+ (@arguments ||= {})[object.name] = object
84
+ rescue DefinitionError => e
85
+ raise e.class, e.message + "\n Defined at: #{caller(2)[0]}"
86
+ end
87
+
88
+ # A short cute for arguments named and typed as id
89
+ def id_argument(*args, **xargs, &block)
90
+ name = args.size >= 1 ? args.shift : :id
91
+ xargs[:null] = false unless xargs.key?(:null)
92
+ argument(name, :id, *args, **xargs, &block)
93
+ end
94
+
95
+ # Check if a given +name+ is already defined on the list of arguments
96
+ def has_argument?(name)
97
+ defined?(@arguments) && @arguments.key?(name)
98
+ end
99
+
100
+ # Validate all the arguments to make sure the definition is valid
101
+ def validate!(*)
102
+ super if defined? super
103
+
104
+ return unless defined? @arguments
105
+ @arguments.each_value(&:validate!)
106
+ @arguments.freeze
107
+ end
108
+
109
+ protected
110
+
111
+ # Show all the arguments as their inspect version
112
+ def inspect_arguments
113
+ args = all_arguments.each_value.map(&:inspect)
114
+ args.presence && "(#{args.join(', ')})"
115
+ end
116
+
117
+ # Check the equivalency of arguments
118
+ def match_arguments?(other)
119
+ l_args, r_args = all_arguments, other.all_arguments
120
+ l_args.size <= r_args.size && l_args.all? { |key, arg| arg =~ r_args[key] }
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Helpers # :nodoc:
6
+ # Helper module that allows other objects to hold an +assigned_to+ object
7
+ module WithAssignment
8
+ # Add extra instance based methods
9
+ def self.extended(other)
10
+ other.delegate :assigned?, :assigned_to, :safe_assigned_class,
11
+ :assigned_class, to: :class
12
+ end
13
+
14
+ # Check if the class is assgined
15
+ def assigned?
16
+ assigned_to.present?
17
+ end
18
+
19
+ # Check if the given +value+ is a valid input for the assigned class
20
+ def valid_assignment?(value)
21
+ assigned? && (klass = safe_assigned_class).present? &&
22
+ ((value.is_a?(Module) && value <= klass) || value.is_a?(klass))
23
+ end
24
+
25
+ # Check its own class or pass it to the superclass
26
+ def assigned_to
27
+ (defined?(@assigned_to) && @assigned_to.presence) || superclass.try(:assigned_to)
28
+ end
29
+
30
+ # Make sure to always save the assignment as string, so that
31
+ # +assigned_class+ can return the actual object
32
+ def assigned_to=(value)
33
+ if value.is_a?(Module)
34
+ @assigned_class = value
35
+ @assigned_to = value.name
36
+ else
37
+ @assigned_to = value
38
+ end
39
+ end
40
+
41
+ # Return the actual class object of the assignment
42
+ def assigned_class
43
+ @assigned_class ||= begin
44
+ klass = assigned_to.constantize
45
+ validate_assignment!(klass)
46
+ klass
47
+ end
48
+ end
49
+
50
+ # Get the assigned class, but if an known exception happens, just ignore
51
+ def safe_assigned_class
52
+ assigned_class
53
+ rescue ::ArgumentError, ::NameError
54
+ # Ignores the possible errors here related
55
+ end
56
+
57
+ # After a successfully registration, add the assigned class to the
58
+ # type map as a great alias to find the object
59
+ def register!
60
+ return if abstract?
61
+ return super unless assigned?
62
+
63
+ result = super
64
+ return result unless (klass = safe_assigned_class)
65
+
66
+ GraphQL.type_map.register_alias(klass, namespaces: namespaces, &method(:itself))
67
+ result
68
+ end
69
+
70
+ protected
71
+
72
+ # Allows validating the +assigned_class+ before resolving it, making
73
+ # sure that it is a subclass of +base_class+. Use the +block+ to
74
+ # customize the error message
75
+ def validate_assignment(base_class, &block)
76
+ @base_class = base_class
77
+ @error_block = block unless block.nil?
78
+ self.assigned_to = base_class
79
+ end
80
+
81
+ # Check if the given +klass+ is valid, but just when +@base_class+
82
+ # is defined
83
+ def validate_assignment!(klass)
84
+ return if (base_class = base_assignment_class).nil? || klass <= base_class
85
+
86
+ klass = self
87
+ block = until klass === Class
88
+ break klass.instance_variable_get(:@error_block) \
89
+ if klass.instance_variable_defined?(:@error_block)
90
+
91
+ klass = klass.superclass
92
+ end
93
+
94
+ message = !block.nil? ? block.call(klass) : <<~MSG.squish
95
+ The "#{klass.name}" is not a subclass of #{base_class.name}.
96
+ MSG
97
+
98
+ raise ::ArgumentError, message
99
+ end
100
+
101
+ # Find a base class using the inheritance
102
+ def base_assignment_class
103
+ if defined?(@base_class)
104
+ @base_class = @base_class.constantize if @base_class.is_a?(String)
105
+ @base_class
106
+ elsif superclass.respond_to?(:base_assignment_class, true)
107
+ superclass.send(:base_assignment_class)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Helpers # :nodoc:
6
+ # Callbacks is an extension of the events which works with the
7
+ # {Callback}[rdoc-ref:Rails::GraphQL::Callback] class, then having extra
8
+ # powers when actually executing the event against procs or owner-based
9
+ # symbolic methods
10
+ module WithCallbacks
11
+ DEFAULT_EVENT_TYPES = %i[query mutation subscription request attach
12
+ organized prepared finalize].freeze
13
+
14
+ def self.extended(other)
15
+ other.extend(WithCallbacks::Setup)
16
+ end
17
+
18
+ def self.included(other)
19
+ other.extend(WithCallbacks::Setup)
20
+ other.delegate(:event_filters, to: :class)
21
+ end
22
+
23
+ # Add the ability to set up filters before the actual execution of the
24
+ # callback
25
+ module Setup
26
+ # Use the default list of event types when it's not set
27
+ def event_types(*, **)
28
+ (super if defined? super).presence || DEFAULT_EVENT_TYPES
29
+ end
30
+
31
+ # Return the list of event filters hooks
32
+ def event_filters
33
+ return @event_filters if defined? @event_filters
34
+ superclass.try(:event_filters) || {}
35
+ end
36
+
37
+ protected
38
+
39
+ # Attach a new key based event filter
40
+ def event_filter(key, sanitizer = nil, &block)
41
+ @event_filters ||= superclass.try(:event_filters)&.dup || {}
42
+ @event_filters[key.to_sym] = { block: block, sanitizer: sanitizer }
43
+ end
44
+ end
45
+
46
+ # Enhance the event by evolving the block to a
47
+ # {Callback}[rdoc-ref:Rails::GraphQL::Callback] object.
48
+ def on(event_name, *args, unshift: false, **xargs, &block)
49
+ block = Callback.new(self, event_name, *args, **xargs, &block)
50
+ super(event_name, unshift: unshift, &block)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Helpers # :nodoc:
6
+ # Helper module that allows other objects to hold directives during the
7
+ # definition process
8
+ module WithDirectives
9
+ def self.extended(other)
10
+ other.extend(Helpers::InheritedCollection)
11
+ other.extend(WithDirectives::DirectiveLocation)
12
+ other.inherited_collection(:directives)
13
+ end
14
+
15
+ def self.included(other)
16
+ other.extend(WithDirectives::DirectiveLocation)
17
+ other.define_method(:directives) { @directives ||= Set.new }
18
+ other.class_attribute(:directive_location, instance_writer: false)
19
+ end
20
+
21
+ def initialize_copy(orig)
22
+ super
23
+
24
+ @directives = orig.directives.dup
25
+ end
26
+
27
+ module DirectiveLocation
28
+ # Return the symbol that represents the location that the directives
29
+ # must have in order to be added to the list
30
+ def directive_location
31
+ defined?(@directive_location) \
32
+ ? @directive_location \
33
+ : superclass.try(:directive_location)
34
+ end
35
+
36
+ # Use this once to define the directive location
37
+ def directive_location=(value)
38
+ raise ArgumentError, 'Directive location is already defined' \
39
+ unless directive_location.nil?
40
+
41
+ @directive_location = value
42
+ end
43
+ end
44
+
45
+ # Mostly for correct inheritance on instances
46
+ def all_directives
47
+ defined?(@directives) ? @directives : Set.new
48
+ end
49
+
50
+ # Use this method to assign directives to the given definition. You can
51
+ # also provide a symbol as a first argument and extra named-arguments
52
+ # to auto initialize a new instance of that directive.
53
+ def use(item_or_symbol, *list, **xargs)
54
+ if item_or_symbol.is_a?(Symbol)
55
+ directive = fetch!(item_or_symbol)
56
+ raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
57
+ Unable to find the #{item_or_symbol.inspect} directive.
58
+ MSG
59
+
60
+ list = [directive.new(**xargs)]
61
+ else
62
+ list << item_or_symbol
63
+ end
64
+
65
+ current = try(:all_directives) || @directives
66
+ items = GraphQL.directives_to_set(list, current, source: self)
67
+ directives.merge(items)
68
+ rescue DefinitionError => e
69
+ raise e.class, e.message + "\n Defined at: #{caller(2)[0]}"
70
+ end
71
+
72
+ # Check wheter a given directive is being used
73
+ def using?(item_or_symbol)
74
+ directive = item_or_symbol.is_a?(Symbol) ? fetch!(item_or_symbol) : item_or_symbol
75
+ raise ArgumentError, <<~MSG.squish unless directive < GraphQL::Directive
76
+ The provided #{item_or_symbol.inspect} is not a valid directive.
77
+ MSG
78
+
79
+ all_directives.any? { |item| item.is_a?(directive) }
80
+ end
81
+
82
+ alias has_directive? using?
83
+
84
+ # Override the +all_listeners+ method since callbacks can eventually be
85
+ # attached to objects that have directives, which then they need to
86
+ # be combined
87
+ def all_listeners
88
+ current = all_directives.map(&:all_listeners).reduce(:+) || Set.new
89
+ (defined?(super) ? super : Set.new) + current
90
+ end
91
+
92
+ # Override the +all_events+ method since callbacks can eventually be
93
+ # attached to objects that have directives, which then they need to
94
+ # be combined
95
+ def all_events
96
+ Helpers::AttributeDelegator.new do
97
+ base = defined?(super) ? super : {}
98
+ all_directives.map(&:all_events).inject(base) do |lhash, rhash|
99
+ Helpers.merge_hash_array(lhash, rhash)
100
+ end
101
+ end
102
+ end
103
+
104
+ # Validate all the directives to make sure the definition is valid
105
+ def validate!(*)
106
+ super if defined? super
107
+
108
+ return unless defined? @directives
109
+ @directives.each(&:validate!)
110
+ @directives.freeze
111
+ end
112
+
113
+ private
114
+
115
+ # Find a directive for its symbolized name
116
+ def fetch!(name)
117
+ GraphQL.type_map.fetch!(name,
118
+ base_class: :Directive,
119
+ namespaces: namespaces,
120
+ prevent_register: try(:owner) || self,
121
+ )
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Helpers # :nodoc:
6
+ # Helper module that allows other objects to hold events, either from a
7
+ # singleton point-of-view, or for instances
8
+ module WithEvents
9
+ def self.extended(other)
10
+ other.extend(Helpers::InheritedCollection)
11
+ other.extend(WithEvents::FixedTypes)
12
+
13
+ other.inherited_collection(:events, type: :hash_array)
14
+ other.inherited_collection(:listeners)
15
+ end
16
+
17
+ def self.included(other)
18
+ other.extend(WithEvents::FixedTypes)
19
+ other.delegate(:event_types, to: :class)
20
+
21
+ other.define_method(:events) { @events ||= Hash.new { |h, k| h[k] = [] } }
22
+ other.define_method(:listeners) { @listeners ||= Set.new }
23
+ end
24
+
25
+ # Helper module to define static list of valid event types
26
+ module FixedTypes
27
+ # Set or get the list of possible event types when attaching events
28
+ def event_types(*list, append: false, expose: false)
29
+ return (defined?(@event_types) && @event_types.presence) ||
30
+ superclass.try(:event_types) if list.blank?
31
+
32
+ list = event_types if append
33
+ list += list.flatten.compact.map(&:to_sym)
34
+ @event_types = list.uniq.freeze
35
+ expose_events! if expose
36
+ @event_types
37
+ end
38
+
39
+ protected
40
+
41
+ # Auxiliar method that creates easy-accessible callback assignment
42
+ def expose_events!
43
+ event_types.each do |event_name|
44
+ next if method_defined?(event_name)
45
+ define_method(event_name) do |*args, **xargs, &block|
46
+ on(event_name, *args, **xargs, &block)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Mostly for correct inheritance on instances
53
+ def all_events
54
+ current = (@events || {})
55
+ return current unless defined? super
56
+ Helpers.merge_hash_array(current, super)
57
+ end
58
+
59
+ # Mostly for correct inheritance on instances
60
+ def all_listeners
61
+ current = (defined?(@listeners) && @listeners) || Set.new
62
+ defined?(super) ? (current + super) : current
63
+ end
64
+
65
+ # Add a new event listener for the given +event_name+. It is possible
66
+ # to prepend the event by setting +unshift: true+. This checks if the
67
+ # event name is a valid one due to +event_types+.
68
+ def on(event_name, unshift: false, &block)
69
+ event_name = event_name.to_sym
70
+ valid = !event_types || event_types.include?(event_name)
71
+ raise ArgumentError, <<~MSG.squish unless valid
72
+ The #{event_name} is not a valid event type.
73
+ MSG
74
+
75
+ listeners << event_name
76
+ events[event_name].send(unshift ? :unshift : :push, block)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end