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,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ # Module related to some methods regarding the introspection of a schema
6
+ module Introspection
7
+ module ClassMethods # :nodoc: all
8
+ def inherited(subclass)
9
+ super if defined? super
10
+
11
+ subclass.query_fields do
12
+ field(:__schema, '__Schema', null: false) do
13
+ resolve { schema }
14
+ end
15
+
16
+ field(:__type, '__Type') do
17
+ argument(:name, :string, null: false)
18
+ resolve { schema.find_type(argument(:name)) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.extended(other) # :nodoc:
25
+ other.extend(Introspection::ClassMethods)
26
+ end
27
+
28
+ # When register is called, add introspection fields?
29
+ def register!(*)
30
+ super if defined? super
31
+ return unless introspection?
32
+
33
+ Helpers::WithSchemaFields::SCHEMA_FIELD_TYPES.each do |type, name|
34
+ GraphQL.type_map.register_alias(name, namespace: namespace) do
35
+ result = public_send("#{type}_type")
36
+ type.eql?(:query) || result.fields.present? ? result : nil
37
+ end
38
+ end
39
+ end
40
+
41
+ # Check if the schema has introspection enabled
42
+ def introspection?
43
+ true
44
+ end
45
+
46
+ # Remove introspection fields and disable introspection
47
+ def disable_introspection!
48
+ disable_fields(:query, :__schema, :__type)
49
+ redefine_singleton_method(:introspection?) { false }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module Rails # :nodoc:
6
+ module GraphQL # :nodoc:
7
+ module Native # :nodoc:
8
+ extend FFI::Library
9
+
10
+ VERSION = GQLAst::VERSION
11
+
12
+ dl_name = "graphqlparser.#{RbConfig::MAKEFILE_CONFIG['DLEXT']}"
13
+ dl_path = Pathname.new(__dir__)
14
+
15
+ begin
16
+ ffi_lib(dl_path.join("../../#{dl_name}").to_s)
17
+ rescue LoadError
18
+ ffi_lib(dl_path.join("../../../../ext/#{dl_name}").to_s)
19
+ end
20
+
21
+ require_relative 'native/location'
22
+ require_relative 'native/visitor'
23
+ require_relative 'native/pointers'
24
+ require_relative 'native/functions'
25
+
26
+ attach_function :graphql_parse_string, %i[pointer pointer], :pointer
27
+
28
+ attach_function :to_json, :graphql_ast_to_json, [:pointer], :string
29
+
30
+ attach_function :free_node, :graphql_node_free, [:pointer], :void
31
+
32
+ attach_function :graphql_node_get_location, [:pointer, Location], :void
33
+
34
+ attach_function :visit, :graphql_node_visit, [:pointer, Visitor, :pointer], :void
35
+
36
+ # Parse the given GraphQL +content+ string returning the node pointer.
37
+ # The +dup+ here is important to be able to free the memory of the nodes
38
+ # partially. It will raise an exception if +content+ is invalid.
39
+ def self.parse(content)
40
+ error = Native::ParseError.new
41
+ content = FFI::MemoryPointer.from_string(content)
42
+ result = graphql_parse_string(content, error)
43
+ return result if error.empty?
44
+ raise GraphQL::ParseError, error.to_s
45
+ end
46
+
47
+ # Return a {+Location+}[rdoc-ref:Rails::GraphQL::Native::Location] class
48
+ # with the location information of the given +node+.
49
+ def self.get_location(node)
50
+ Native::Location.new.tap do |result|
51
+ graphql_node_get_location(node, result)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Native # :nodoc:
6
+ def self.attach_operation(method_name, function_name, result: :string)
7
+ attach_function(method_name, function_name, [:pointer], result)
8
+ end
9
+
10
+ attach_operation :operation_type, :GraphQLAstOperationDefinition_get_operation
11
+ attach_operation :node_name, :GraphQLAstName_get_value
12
+
13
+ attach_operation :get_int_value, :GraphQLAstIntValue_get_value
14
+ attach_operation :get_float_value, :GraphQLAstFloatValue_get_value
15
+ attach_operation :get_string_value, :GraphQLAstStringValue_get_value
16
+ attach_operation :get_enum_value, :GraphQLAstEnumValue_get_value
17
+
18
+ with_options(result: :pointer) do
19
+ attach_operation :default_value, :GraphQLAstVariableDefinition_get_default_value
20
+ attach_operation :type_name, :GraphQLAstNamedType_get_name
21
+
22
+ attach_operation :argument_name, :GraphQLAstArgument_get_name
23
+ attach_operation :argument_value, :GraphQLAstArgument_get_value
24
+
25
+ attach_operation :ofield_name, :GraphQLAstObjectField_get_name
26
+ attach_operation :ofield_value, :GraphQLAstObjectField_get_value
27
+
28
+ attach_operation :variable_name, :GraphQLAstVariable_get_name
29
+ end
30
+
31
+ with_options(result: :int) do
32
+ attach_operation :list_size, :GraphQLAstListValue_get_values_size
33
+
34
+ attach_operation :get_boolean_value, :GraphQLAstBooleanValue_get_value
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Native # :nodoc:
6
+ class Location < FFI::Struct # :nodoc:
7
+ layout(
8
+ beginLine: :uint,
9
+ beginColumn: :uint,
10
+ endLine: :uint,
11
+ endColumn: :uint,
12
+ )
13
+
14
+ def begin_line
15
+ self[:beginLine]
16
+ end
17
+
18
+ def begin_column
19
+ self[:beginColumn]
20
+ end
21
+
22
+ def end_line
23
+ self[:endLine]
24
+ end
25
+
26
+ def end_column
27
+ self[:endColumn]
28
+ end
29
+
30
+ def to_errors
31
+ [
32
+ { 'line' => begin_line, 'column' => begin_column },
33
+ { 'line' => end_line, 'column' => end_column },
34
+ ]
35
+ end
36
+
37
+ private :[], :[]=
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Native # :nodoc:
6
+ # This helps to make sure that any parser error is correctly initialized
7
+ # and easy to ready. It also release the error using GC.
8
+ class ParseError < FFI::MemoryPointer
9
+ def initialize(*)
10
+ super(:pointer)
11
+ end
12
+
13
+ def to_s
14
+ empty? ? '' : read_pointer.read_string
15
+ end
16
+
17
+ def empty?
18
+ read_pointer.null?
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,349 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails # :nodoc:
4
+ module GraphQL # :nodoc:
5
+ module Native # :nodoc:
6
+ class Visitor < FFI::Struct # :nodoc:
7
+ CALLBACK_LAYOUT = %i[pointer pointer].freeze
8
+
9
+ MACROS = %w[
10
+ document operation_definition variable_definition selection_set field argument
11
+ fragment_spread inline_fragment fragment_definition variable int_value float_value
12
+ string_value boolean_value null_value enum_value list_value object_value object_field
13
+ directive named_type list_type non_null_type name schema_definition
14
+ operation_type_definition scalar_type_definition object_type_definition
15
+ field_definition input_value_definition interface_type_definition
16
+ union_type_definition enum_type_definition enum_value_definition
17
+ input_object_type_definition type_extension_definition directive_definition
18
+ ].freeze
19
+
20
+ AUTO_NESTED = %w[document object_value list_type non_null_type].freeze
21
+
22
+ ArgumentObject = Struct.new(:name, :value, :variable)
23
+ DirectiveObject = Struct.new(:name, :arguments)
24
+ FieldObject = Struct.new(:name, :alias, :arguments, :directives, :selection)
25
+ FragmentObject = Struct.new(:name, :type, :directives, :selection)
26
+ OperationObject = Struct.new(:name, :kind, :variables, :directives, :selection)
27
+ SpreadObject = Struct.new(:name, :type, :inline, :directives, :selection)
28
+ VariableObject = Struct.new(:name, :type, :null, :array, :nullable, :default)
29
+
30
+ macros = MACROS.map do |key|
31
+ [
32
+ [ "visit_#{key}", callback(CALLBACK_LAYOUT, :bool)],
33
+ ["end_visit_#{key}", callback(CALLBACK_LAYOUT, :void)],
34
+ ]
35
+ end.flatten(1).to_h
36
+ layout(macros)
37
+
38
+ @@callbacks = Visitor.new
39
+ @@instances = Concurrent::Map.new
40
+
41
+ MACROS.each do |key|
42
+ @@callbacks["visit_#{key}".to_sym] = ->(node, ref) do
43
+ Visitor.ref_send(key, node, ref)
44
+ end
45
+
46
+ @@callbacks["end_visit_#{key}".to_sym] = ->(node, ref) do
47
+ Visitor.ref_send(key, node, ref, prefix: 'end')
48
+ end
49
+ end
50
+
51
+ def self.ref_send(key, node, ref, prefix: nil)
52
+ instance = @@instances[ref.read_string]
53
+ method_name = [prefix, 'visit', key].compact.join('_')
54
+
55
+ catch :override do
56
+ instance.try(method_name, node)
57
+ prefix.nil? && instance.visit_nested?(key)
58
+ end
59
+ end
60
+
61
+ delegate_missing_to('Rails::GraphQL::Native')
62
+
63
+ attr_reader :stack, :block
64
+
65
+ def initialize
66
+ @data = FFI::MemoryPointer.from_string(SecureRandom.uuid)
67
+ @stack = []
68
+ @visit = nil
69
+ @block = nil
70
+ @error = nil
71
+
72
+ @@instances[uuid] = self
73
+ end
74
+
75
+ # Remove the instance for the set of instances
76
+ def terminate
77
+ @@instances.delete(uuid)
78
+ end
79
+
80
+ # Get the uuid from the string pointer
81
+ def uuid
82
+ @data.read_string
83
+ end
84
+
85
+ # Check if it should go deeper into the node
86
+ def visit_nested?(key)
87
+ @error.nil? && (AUTO_NESTED.include?(key) || @visit&.include?(key))
88
+ end
89
+
90
+ # Return the last object on the stack being visited
91
+ def object
92
+ stack.last
93
+ end
94
+
95
+ # Send the extra needed arguments to the original visitor
96
+ def visit(node)
97
+ Native.visit(node, @@callbacks, @data)
98
+ end
99
+
100
+ # Catches if an exception happens inside the block, because visitors on
101
+ # the C lib does not pop such expections
102
+ def safe_call_block(*args)
103
+ block.call(*args)
104
+ rescue Exception => err
105
+ @error ||= err
106
+ end
107
+
108
+ # Pre caller for calling the visitor on nodes
109
+ def dispatch(visitors, nodes, &block)
110
+ @visit = visitors
111
+ @block = block
112
+
113
+ nodes.each(&method(:visit))
114
+ raise @error unless @error.nil?
115
+ ensure
116
+ @error = @block = @visit = nil
117
+ end
118
+
119
+ # ENTRY POINTS
120
+
121
+ DEFINITION_VISITORS = %w[operation_definition fragment_definition].freeze
122
+ def collect_definitions(*nodes, &block)
123
+ dispatch(DEFINITION_VISITORS, nodes, &block)
124
+ end
125
+
126
+ DIRECTIVES_VISITORS = %w[directive].freeze
127
+ def collect_directives(*nodes, &block)
128
+ dispatch(DIRECTIVES_VISITORS, nodes, &block)
129
+ end
130
+
131
+ ARGUMENTS_VISITORS = %w[argument].freeze
132
+ def collect_arguments(*nodes, &block)
133
+ dispatch(ARGUMENTS_VISITORS, nodes, &block)
134
+ end
135
+
136
+ VARIABLES_VISITORS = %w[variable_definition].freeze
137
+ def collect_variables(*nodes, &block)
138
+ dispatch(VARIABLES_VISITORS, nodes, &block)
139
+ end
140
+
141
+ FIELDS_VISITORS = %w[field fragment_spread inline_fragment].freeze
142
+ def collect_fields(*nodes, &block)
143
+ dispatch(FIELDS_VISITORS, nodes, &block)
144
+ end
145
+
146
+ # MAIN VISITORS
147
+
148
+ # Add an operation object to the stack
149
+ def visit_operation_definition(node)
150
+ stack << OperationObject.new.tap { |obj| obj.kind = operation_type(node) }
151
+ end
152
+
153
+ # Add a fragment object to the stack
154
+ def visit_fragment_definition(_)
155
+ stack << FragmentObject.new
156
+ end
157
+
158
+ # Add a field object to the stack
159
+ def visit_field(_)
160
+ stack << FieldObject.new
161
+ end
162
+
163
+ # Add a spread object to the stack
164
+ def visit_fragment_spread(_)
165
+ stack << SpreadObject.new
166
+ end
167
+
168
+ # Add a spread object to the stack
169
+ def visit_inline_fragment(_)
170
+ stack << SpreadObject.new.tap { |obj| obj.inline = true }
171
+ end
172
+
173
+ # BLOCK DISPATCHER VISITORS
174
+
175
+ # Send the operation object to the set block
176
+ def end_visit_operation_definition(node)
177
+ safe_call_block(:operation, node, stack.pop)
178
+ end
179
+
180
+ # Send the fragment object to the set block
181
+ def end_visit_fragment_definition(node)
182
+ safe_call_block(:fragment, node, stack.pop)
183
+ end
184
+
185
+ # Send the directive object to the set block
186
+ def end_visit_directive(_)
187
+ return unless @visit&.include?('directive')
188
+
189
+ safe_call_block(stack.pop)
190
+ end
191
+
192
+ # Send the argument object to the set block
193
+ def end_visit_argument(_)
194
+ return unless @visit&.include?('argument')
195
+
196
+ stack[-2][:value] = stack.pop if stack.size > 1
197
+ safe_call_block(stack.pop)
198
+ end
199
+
200
+ # Send the variable object to the set block
201
+ def end_visit_variable_definition(node)
202
+ return unless @visit&.include?('variable_definition')
203
+
204
+ stack[-2][:default] = stack.pop unless default_value(node).null?
205
+ safe_call_block(stack.pop, node)
206
+ end
207
+
208
+ # Send the field object to the set block
209
+ def end_visit_field(node)
210
+ safe_call_block(:field, node, stack.pop)
211
+ end
212
+
213
+ # Send the spread object to the set block
214
+ def end_visit_fragment_spread(node)
215
+ safe_call_block(:spread, node, stack.pop)
216
+ end
217
+
218
+ # Send the spread object to the set block
219
+ def end_visit_inline_fragment(node)
220
+ safe_call_block(:spread, node, stack.pop)
221
+ end
222
+
223
+ # SECONDARY VISITORS
224
+
225
+ # Add a variable definition to the current object
226
+ def visit_variable_definition(node)
227
+ if @visit&.include?('variable_definition')
228
+ stack << VariableObject.new.tap do |obj|
229
+ obj.null = true
230
+ obj.array = false
231
+ obj.nullable = true
232
+ end
233
+ else
234
+ (object[:variables] ||= []) << node
235
+ end
236
+ end
237
+
238
+ # Add a directive to the current object
239
+ def visit_directive(node)
240
+ if @visit&.include?('directive')
241
+ stack << DirectiveObject.new
242
+ else
243
+ (object[:directives] ||= []) << node
244
+ end
245
+ end
246
+
247
+ # Add a selection set to the current object
248
+ def visit_selection_set(node)
249
+ throw(:override, true) if object.nil?
250
+ object[:selection] = node
251
+ end
252
+
253
+ # SHARED VISITORS
254
+
255
+ # Set a name into the object
256
+ def visit_name(node)
257
+ object[:alias] = object[:name] unless object[:name].nil?
258
+ object[:name] = node_name(node)
259
+ end
260
+
261
+ # Get the type of the object
262
+ def visit_named_type(node)
263
+ object[:type] = node_name(type_name(node))
264
+ end
265
+
266
+ # Set the object as an array
267
+ def visit_list_type(_)
268
+ object[:array] = true
269
+ end
270
+
271
+ # Set the object as non null or non nullable
272
+ def visit_non_null_type(_)
273
+ object[object[:array] ? :nullable : :null] = false
274
+ end
275
+
276
+ # Get an argument information with its given written value
277
+ def visit_argument(node)
278
+ if @visit&.include?('argument')
279
+ stack << ArgumentObject.new
280
+ elsif @visit&.include?('field')
281
+ (object[:arguments] ||= []) << node
282
+ else
283
+ visit(argument_value(node))
284
+ arg_name = node_name(argument_name(node))
285
+ (stack[-2][:arguments] ||= {})[arg_name] = stack.pop
286
+ end
287
+ end
288
+
289
+ # Add a variable to the stack
290
+ def visit_variable(node)
291
+ if @visit&.include?('argument')
292
+ object[:variable] = variable_name(node)
293
+ elsif @visit&.include?('variable_definition')
294
+ object[:name] = visit_name(variable_name(node))
295
+ else
296
+ stack << variable_name(node)
297
+ end
298
+ end
299
+
300
+ # Add a integer value to the stack
301
+ def visit_int_value(node)
302
+ stack << get_int_value(node)
303
+ end
304
+
305
+ # Add a float value to the stack
306
+ def visit_float_value(node)
307
+ stack << get_float_value(node)
308
+ end
309
+
310
+ # Add a string value to the stack
311
+ def visit_string_value(node)
312
+ stack << get_string_value(node)
313
+ end
314
+
315
+ # Add a boolean value to the stack
316
+ def visit_boolean_value(node)
317
+ stack << get_boolean_value(node).eql?(1)
318
+ end
319
+
320
+ # Add a nil value to the stack
321
+ def visit_null_value(*)
322
+ stack << nil
323
+ end
324
+
325
+ # Add a enum string-like value to the stack
326
+ def visit_enum_value(node)
327
+ stack << get_enum_value(node)
328
+ end
329
+
330
+ # Add a hash value to the stack
331
+ def visit_object_value(*)
332
+ stack << {}
333
+ end
334
+
335
+ # Add a hash key value pair to a hash on the stack
336
+ def visit_object_field(node)
337
+ visit(ofield_value(node))
338
+ key = node_name(ofield_name(node))
339
+ stack[-2][key] = stack.pop
340
+ end
341
+
342
+ # At the end of a list, change the stack based on the size of the list
343
+ def end_visit_list_value(node)
344
+ stack << size.zero? ? [] : stack.slice!(-list_size(node)..-1)
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end