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,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Directive
6
+ #
7
+ # This is the base object for directives definition.
8
+ # See: http://spec.graphql.org/June2018/#DirectiveDefinition
9
+ #
10
+ # Whenever you want to use a directive, you can use the ClassName(...)
11
+ # shortcut (which is the same as ClassName.new(...)).
12
+ #
13
+ # Directives works as event listener and trigger, which means that some
14
+ # actions will trigger directives events, and the directive can listen to
15
+ # these events and perform an action
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # argument :test, :boolean, directives: FlagDirective()
20
+ #
21
+ # # On defining an enum value
22
+ # add :old_value, directives: DeprecatedDirective(reason: 'not used anymore')
23
+ class Directive
24
+ extend ActiveSupport::Autoload
25
+ extend Helpers::InheritedCollection
26
+ extend Helpers::WithEvents
27
+ extend Helpers::WithCallbacks
28
+ extend Helpers::WithArguments
29
+ extend Helpers::Registerable
30
+
31
+ VALID_LOCATIONS = Rails::GraphQL::Type::Enum::DirectiveLocationEnum
32
+ .values.to_a.map { |value| value.downcase.to_sym }.freeze
33
+
34
+ EXECUTION_LOCATIONS = VALID_LOCATIONS[0..6].freeze
35
+ DEFINITION_LOCATIONS = VALID_LOCATIONS[7..17].freeze
36
+
37
+ class << self
38
+ def kind # :nodoc
39
+ :directive
40
+ end
41
+
42
+ def gql_name # :nodoc:
43
+ return @gql_name if defined?(@gql_name)
44
+ @gql_name = super.camelize(:lower)
45
+ end
46
+
47
+ # Get the list of locations of a the directive
48
+ def locations
49
+ @locations ||= Set.new
50
+ end
51
+
52
+ # A secure way to specify the locations of a the directive
53
+ def placed_on(*list)
54
+ validate_locations!(list)
55
+ @locations = (superclass.try(:locations)&.dup || Set.new) \
56
+ unless defined?(@locations)
57
+
58
+ @locations.merge(list)
59
+ end
60
+
61
+ # This method overrides the locations of a the directive
62
+ def placed_on!(*list)
63
+ validate_locations!(list)
64
+ @locations = list.to_set
65
+ end
66
+
67
+ def eager_load! # :nodoc:
68
+ super
69
+
70
+ TypeMap.loaded! :Directive
71
+ end
72
+
73
+ def inspect # :nodoc:
74
+ return '#<GraphQL::Directive>' if eql?(GraphQL::Directive)
75
+
76
+ args = arguments.each_value.map(&:inspect)
77
+ args = args.presence && "(#{args.join(', ')})"
78
+ "#<GraphQL::Directive @#{gql_name}#{args}>"
79
+ end
80
+
81
+ private
82
+
83
+ # Check if the given list the locations are valid
84
+ def validate_locations!(list)
85
+ list.flatten!
86
+ list.map! { |item| item.to_s.underscore.to_sym }
87
+
88
+ invalid = list - VALID_LOCATIONS
89
+ raise ArgumentError, <<~MSG.squish unless invalid.empty?
90
+ Invalid locations for @#{gql_name}: #{invalid.to_sentence}.
91
+ MSG
92
+ end
93
+
94
+ # Provide a nice way to use a directive without calling
95
+ # +Directive.new+, like the +DeprecatedDirective+ can be initialized
96
+ # using +GraphQL::DeprecatedDirective(*args)+
97
+ def inherited(subclass)
98
+ subclass.abstract = false
99
+ super if defined? super
100
+
101
+ return if subclass.anonymous?
102
+ method_name = subclass.name.demodulize
103
+ subclass.module_parent.define_singleton_method(method_name) do |*args, &block|
104
+ subclass.new(*args, &block)
105
+ end
106
+ end
107
+
108
+ # Allows checking value existence
109
+ def respond_to_missing?(method_name, *)
110
+ (const_defined?(method_name) rescue nil) || autoload?(method_name) || super
111
+ end
112
+
113
+ # Allow fast creation of values
114
+ def method_missing(method_name, *args, **xargs, &block)
115
+ const_get(method_name)&.new(*args, **xargs, &block) || super
116
+ rescue ::NameError
117
+ super
118
+ end
119
+ end
120
+
121
+ self.abstract = true
122
+
123
+ eager_autoload do
124
+ autoload :DeprecatedDirective
125
+ autoload :IncludeDirective
126
+ autoload :SkipDirective
127
+ end
128
+
129
+ delegate :locations, :gql_name, to: :class
130
+
131
+ array_sanitizer = ->(setting) do
132
+ Array.wrap(setting)
133
+ end
134
+
135
+ object_sanitizer = ->(setting) do
136
+ Array.wrap(setting).map! do |item|
137
+ next item unless item.is_a?(String) || item.is_a?(Symbol)
138
+ GraphQL.type_map.fetch(item, namespaces: namespaces) ||
139
+ ::GraphQL.const_get(item)
140
+ end
141
+ end
142
+
143
+ event_filter(:for, object_sanitizer) do |options, event|
144
+ options.any?(&event.source.method(:of_type?))
145
+ end
146
+
147
+ event_filter(:on, object_sanitizer) do |options, event|
148
+ event.respond_to?(:on?) && options.any?(&event.method(:on?))
149
+ end
150
+
151
+ event_filter(:during, array_sanitizer) do |options, event|
152
+ event.key?(:phase) && options.include?(event[:phase])
153
+ end
154
+
155
+ attr_reader :args
156
+
157
+ def initialize(args = nil, **xargs)
158
+ @args = args || OpenStruct.new(xargs.transform_keys { |key| key.to_s.underscore })
159
+ @args.freeze
160
+ end
161
+
162
+ # Once the directive is correctly prepared, we need to assign the owner
163
+ def assing_owner!(owner)
164
+ raise ArgumentError, <<~MSG.squish if defined?(@owner)
165
+ Owner already assigned for @#{gql_name} directive.
166
+ MSG
167
+
168
+ @owner = owner
169
+ end
170
+
171
+ # When fetching all the events, embed the actual instance as the context
172
+ # of the callback
173
+ def all_events
174
+ @all_events ||= self.class.all_events.transform_values do |events|
175
+ events.map { |item| Callback.set_context(item, self) }
176
+ end
177
+ end
178
+
179
+ # Checks if all the arguments provided to the directive instance are valid
180
+ def validate!(*)
181
+ invalid = all_arguments.reject { |name, arg| arg.valid?(@args[name]) }
182
+ return if invalid.empty?
183
+
184
+ invalid = invalid.map { |name, _| <<~MSG }
185
+ Invalid value "#{@args[name].inspect}" for #{name} argument.
186
+ MSG
187
+
188
+ raise ArgumentError, <<~MSG.squish
189
+ Invalid usage of @#{gql_name} directive: #{invalid.to_sentence}.
190
+ MSG
191
+ end
192
+
193
+ def inspect # :nodoc:
194
+ args = all_arguments.map do |name, arg|
195
+ "#{arg.gql_name}: #{@args[name].inspect}" unless @args[name].nil?
196
+ end.compact
197
+
198
+ args = args.presence && "(#{args.join(', ')})"
199
+ "@#{gql_name}#{args}"
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Spec Deprecated Directive
6
+ #
7
+ # Mark fields or enum values as deprecated which will include an error
8
+ # message when they are requested or returned
9
+ class Directive::DeprecatedDirective < Directive
10
+ self.spec_object = true
11
+
12
+ placed_on :field_definition, :enum_value
13
+
14
+ desc <<~DESC
15
+ Indicate deprecated portions of a GraphQL service’s schema, such as deprecated
16
+ fields on a type or deprecated enum values.
17
+ DESC
18
+
19
+ argument :reason, :string, desc: <<~DESC
20
+ Explain why the underlying element was marked as deprecated. If possible,
21
+ indicate what element should be used instead. This description is formatted
22
+ using Markdown syntax (as specified by [CommonMark](http://commonmark.org/)).
23
+ DESC
24
+
25
+ on :organized do |event|
26
+ report_for_field(event)
27
+ end
28
+
29
+ on :finalize, for: Type::Enum do |event|
30
+ report_for_enum_value(event)
31
+ end
32
+
33
+ private
34
+
35
+ # Check if the requested field is marked as deprecated
36
+ def report_for_field(event)
37
+ return unless event.field.using?(self.class)
38
+ item = "#{event.source.gql_name} field"
39
+ event.request.report_error(build_message(item))
40
+ end
41
+
42
+ # Check if the resolved enum value is marked as deprecated
43
+ def report_for_enum_value(event)
44
+ return unless event.current_value.deprecated?
45
+
46
+ value = event.current_value.to_s
47
+ item = "#{value} value for the #{event.source.gql_name} field"
48
+ event.request.report_error(build_message(item))
49
+ end
50
+
51
+ # Build the error message to display on the result
52
+ def build_message(item)
53
+ result = "The #{item} is deprecated"
54
+ result += ", reason: #{args.reason}" if args.reason.present?
55
+ result + '.'
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Spec Include Directive
6
+ #
7
+ # Allow including fields only +if+ condition is true
8
+ class Directive::IncludeDirective < Directive
9
+ self.spec_object = true
10
+
11
+ placed_on :field, :fragment_spread, :inline_fragment
12
+
13
+ desc 'Allows for conditional inclusion during execution as described by the if argument.'
14
+
15
+ argument :if, :boolean, null: false, desc: <<~DESC
16
+ When false, the underlying element will be automatically marked as null.
17
+ DESC
18
+
19
+ on :attach do |source|
20
+ source.invalidate! unless args[:if]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Spec Skip Directive
6
+ #
7
+ # Allow skipping fields given an +if+ condition
8
+ class Directive::SkipDirective < Directive
9
+ self.spec_object = true
10
+
11
+ desc 'Allows for conditional exclusion during execution as described by the if argument.'
12
+
13
+ placed_on :field, :fragment_spread, :inline_fragment
14
+
15
+ argument :if, :boolean, null: false, desc: <<~DESC
16
+ When true, the underlying element will be automatically marked as null.
17
+ DESC
18
+
19
+ on :attach do |source|
20
+ source.invalidate! if args[:if]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # Error class tha wrappes all the other error classes
6
+ StandardError = Class.new(::StandardError)
7
+
8
+ # Error class related to problems during the definition process
9
+ DefinitionError = Class.new(StandardError)
10
+
11
+ # Error class related to validation of a value
12
+ ValidationError = Class.new(StandardError)
13
+
14
+ # Errors that can happen related to the arguments given to a method
15
+ ArgumentError = Class.new(DefinitionError)
16
+
17
+ # Errors related to the name of the objects
18
+ NameError = Class.new(DefinitionError)
19
+
20
+ # Errors related to duplciated objects
21
+ DuplicatedError = Class.new(NameError)
22
+
23
+ # Error class related to problems during the execution process
24
+ ExecutionError = Class.new(StandardError)
25
+
26
+ # Error related to the parsing process
27
+ ParseError = Class.new(ExecutionError)
28
+
29
+ # Error class related to problems that happened during execution of fields
30
+ FieldError = Class.new(ExecutionError)
31
+
32
+ # Error class related to when a field was not found on the requested object
33
+ MissingFieldError = Class.new(FieldError)
34
+
35
+ # Error class related to when a field was found but is marked as disabled
36
+ DisabledFieldError = Class.new(FieldError)
37
+
38
+ # Error class related to when the captured output value is invalid due to
39
+ # type checking
40
+ InvalidValueError = Class.new(FieldError)
41
+ end
42
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # = GraphQL Event
6
+ #
7
+ # This class is responsible for trigerring events. It also contains the
8
+ # +data+ that can be used on the event handlers.
9
+ class Event
10
+ attr_reader :source, :data, :name, :object, :last_result
11
+
12
+ alias event itself
13
+
14
+ # List of trigger types used on +trigger+ shortcut
15
+ TRIGGER_TYPES = {
16
+ all?: :trigger_all,
17
+ stack?: :trigger_all,
18
+ object?: :trigger_object,
19
+ single?: :trigger,
20
+ }.freeze
21
+
22
+ # Event trigger shortcut that can perform any mode of trigger
23
+ def self.trigger(event_name, object, source, **xargs, &block)
24
+ extra = xargs.slice!(*TRIGGER_TYPES.keys)
25
+ fallback = extra.delete(:fallback_trigger!) || :trigger
26
+ method_name = xargs.find { |k, v| break TRIGGER_TYPES[k] if v } || fallback
27
+
28
+ instance = new(event_name, source, **extra)
29
+ instance.instance_variable_set(:@object, object) if block.present?
30
+ instance.public_send(method_name, block || object)
31
+ end
32
+
33
+ def initialize(name, source, **data)
34
+ @collect = data.delete(:collect?)
35
+ @reverse = data.delete(:reverse?)
36
+
37
+ @name = name
38
+ @data = data
39
+ @source = source
40
+ @layers = []
41
+ end
42
+
43
+ # Return a given +name+ information from the event
44
+ def parameter(name)
45
+ respond_to?(name) ? public_send(name) : data[name]
46
+ end
47
+
48
+ alias [] parameter
49
+
50
+ # Check if the event has a given +name+ information
51
+ def parameter?(name)
52
+ respond_to?(name) || data.key?(name)
53
+ end
54
+
55
+ alias key? parameter?
56
+
57
+ # Temporarily attach the event into an instance ensuring to set the
58
+ # previous value back
59
+ def set_on(instance, &block)
60
+ send_args = block.arity.eql?(1) ? [instance] : []
61
+ old_event = instance.instance_variable_get(:@event) \
62
+ if instance.instance_variable_defined?(:@event)
63
+
64
+ return block.call(*send_args) if old_event === self
65
+
66
+ begin
67
+ instance.instance_variable_set(:@event, self)
68
+ block.call(*send_args)
69
+ ensure
70
+ instance.instance_variable_set(:@event, old_event)
71
+ end
72
+ end
73
+
74
+ # From the list of all given objects, run the +trigger_object+
75
+ def trigger_all(*objects)
76
+ catchable(:stack) do
77
+ iterator = @collect ? :map : :each
78
+ objects.flatten.send(iterator, &method(:trigger_object))
79
+ end
80
+ end
81
+
82
+ # Fetch all the events from the object, get only the ones that are from
83
+ # the same name as the instance of this class and call +trigger+. It runs
84
+ # in reverse order, so first in first out. Since events can sometimes be
85
+ # cached, using +events+ avoid calculating the +all_events+
86
+ def trigger_object(object, events = nil)
87
+ @items ||= nil
88
+ @object ||= nil
89
+ @last_result ||= nil
90
+
91
+ old_items, old_object, old_result, @object = @items, @object, @last_result, object
92
+
93
+ catchable(:object) do
94
+ events ||= object.all_events[name]
95
+ stop if events.blank?
96
+
97
+ @items = @reverse ? events.reverse_each : events.each
98
+ call_next while @items.peek
99
+ rescue StopIteration
100
+ # TODO: Make sure that the +@collect+ works
101
+ return @last_result
102
+ end
103
+ ensure
104
+ @items = old_items
105
+ @object = old_object
106
+ @last_result = old_result
107
+ end
108
+
109
+ # Call a given block and send the event as reference
110
+ def trigger(block)
111
+ catchable(:item) { @last_result = block.call(self) }
112
+ end
113
+
114
+ # Stop the execution of an event using a given +layer+. The default is to
115
+ # get the last activated layer and stop it
116
+ def stop(*result, layer: nil)
117
+ layer = @layers[layer] if layer.is_a?(Numeric)
118
+ throw(layer || @layers.first, *result)
119
+ end
120
+
121
+ # Call the next item on the queue and return its result
122
+ def call_next
123
+ trigger(@items.next)
124
+ rescue StopIteration
125
+ # Do not do anything when missing next/super
126
+ end
127
+
128
+ alias call_super call_next
129
+
130
+ private
131
+
132
+ # Add the layer, exec the block and remove the layer
133
+ def catchable(layer)
134
+ @layers.unshift(layer)
135
+ catch(layer) { yield }
136
+ ensure
137
+ @layers.pop
138
+ end
139
+ end
140
+ end
141
+ end