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,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