rails-graphql 0.2.1 → 1.0.0.beta

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 (297) hide show
  1. checksums.yaml +4 -4
  2. data/ext/console.rb +18 -0
  3. data/ext/extconf.h +3 -0
  4. data/ext/extconf.rb +1 -54
  5. data/ext/gql_parser.c +646 -0
  6. data/ext/shared.c +482 -0
  7. data/ext/shared.h +177 -0
  8. data/lib/gql_parser.so +0 -0
  9. data/lib/rails/graphql/adapters/mysql_adapter.rb +59 -0
  10. data/lib/rails/graphql/adapters/pg_adapter.rb +25 -22
  11. data/lib/rails/graphql/adapters/sqlite_adapter.rb +17 -14
  12. data/lib/rails/graphql/alternative/field_set.rb +36 -0
  13. data/lib/rails/graphql/alternative/mutation.rb +17 -0
  14. data/lib/rails/graphql/alternative/query.rb +93 -0
  15. data/lib/rails/graphql/alternative/subscription.rb +17 -0
  16. data/lib/rails/graphql/alternative.rb +20 -0
  17. data/lib/rails/graphql/argument.rb +21 -24
  18. data/lib/rails/graphql/callback.rb +24 -9
  19. data/lib/rails/graphql/collectors/hash_collector.rb +14 -6
  20. data/lib/rails/graphql/collectors/idented_collector.rb +10 -7
  21. data/lib/rails/graphql/collectors/json_collector.rb +22 -17
  22. data/lib/rails/graphql/collectors.rb +4 -4
  23. data/lib/rails/graphql/config.rb +130 -15
  24. data/lib/rails/graphql/directive/cached_directive.rb +33 -0
  25. data/lib/rails/graphql/directive/deprecated_directive.rb +10 -10
  26. data/lib/rails/graphql/directive/include_directive.rb +5 -4
  27. data/lib/rails/graphql/directive/skip_directive.rb +5 -4
  28. data/lib/rails/graphql/directive.rb +118 -63
  29. data/lib/rails/graphql/errors.rb +33 -4
  30. data/lib/rails/graphql/event.rb +16 -5
  31. data/lib/rails/graphql/field/authorized_field.rb +19 -3
  32. data/lib/rails/graphql/field/input_field.rb +11 -10
  33. data/lib/rails/graphql/field/mutation_field.rb +42 -7
  34. data/lib/rails/graphql/field/output_field.rb +102 -13
  35. data/lib/rails/graphql/field/proxied_field.rb +31 -22
  36. data/lib/rails/graphql/field/resolved_field.rb +26 -24
  37. data/lib/rails/graphql/field/scoped_config.rb +10 -4
  38. data/lib/rails/graphql/field/subscription_field.rb +140 -0
  39. data/lib/rails/graphql/field/typed_field.rb +43 -22
  40. data/lib/rails/graphql/field.rb +70 -56
  41. data/lib/rails/graphql/global_id.rb +85 -0
  42. data/lib/rails/graphql/helpers/attribute_delegator.rb +5 -5
  43. data/lib/rails/graphql/helpers/inherited_collection/array.rb +50 -0
  44. data/lib/rails/graphql/helpers/inherited_collection/base.rb +43 -0
  45. data/lib/rails/graphql/helpers/inherited_collection/hash.rb +87 -0
  46. data/lib/rails/graphql/helpers/inherited_collection.rb +25 -76
  47. data/lib/rails/graphql/helpers/instantiable.rb +15 -0
  48. data/lib/rails/graphql/helpers/leaf_from_ar.rb +7 -7
  49. data/lib/rails/graphql/helpers/registerable.rb +44 -62
  50. data/lib/rails/graphql/helpers/unregisterable.rb +16 -0
  51. data/lib/rails/graphql/helpers/with_arguments.rb +31 -27
  52. data/lib/rails/graphql/helpers/with_assignment.rb +6 -6
  53. data/lib/rails/graphql/helpers/with_callbacks.rb +25 -8
  54. data/lib/rails/graphql/helpers/with_description.rb +71 -0
  55. data/lib/rails/graphql/helpers/with_directives.rb +54 -30
  56. data/lib/rails/graphql/helpers/with_events.rb +21 -23
  57. data/lib/rails/graphql/helpers/with_fields.rb +76 -22
  58. data/lib/rails/graphql/helpers/with_global_id.rb +22 -0
  59. data/lib/rails/graphql/helpers/with_name.rb +43 -0
  60. data/lib/rails/graphql/helpers/with_namespace.rb +7 -4
  61. data/lib/rails/graphql/helpers/with_owner.rb +8 -7
  62. data/lib/rails/graphql/helpers/with_schema_fields.rb +137 -55
  63. data/lib/rails/graphql/helpers/with_validator.rb +9 -9
  64. data/lib/rails/graphql/helpers.rb +10 -3
  65. data/lib/rails/graphql/introspection.rb +43 -36
  66. data/lib/rails/graphql/railtie.rb +88 -33
  67. data/lib/rails/graphql/railties/base_generator.rb +3 -9
  68. data/lib/rails/graphql/railties/channel.rb +157 -0
  69. data/lib/rails/graphql/railties/controller.rb +62 -17
  70. data/lib/rails/graphql/railties/controller_runtime.rb +5 -5
  71. data/lib/rails/graphql/railties/log_subscriber.rb +81 -14
  72. data/lib/rails/graphql/request/arguments.rb +24 -49
  73. data/lib/rails/graphql/request/backtrace.rb +191 -0
  74. data/lib/rails/graphql/request/component/field.rb +86 -65
  75. data/lib/rails/graphql/request/component/fragment.rb +72 -24
  76. data/lib/rails/graphql/request/component/operation/subscription.rb +164 -4
  77. data/lib/rails/graphql/request/component/operation.rb +63 -31
  78. data/lib/rails/graphql/request/component/spread.rb +68 -25
  79. data/lib/rails/graphql/request/component/typename.rb +27 -12
  80. data/lib/rails/graphql/request/component.rb +75 -36
  81. data/lib/rails/graphql/request/context.rb +18 -8
  82. data/lib/rails/graphql/request/errors.rb +16 -6
  83. data/lib/rails/graphql/request/event.rb +19 -8
  84. data/lib/rails/graphql/request/helpers/directives.rb +68 -27
  85. data/lib/rails/graphql/request/helpers/selection_set.rb +51 -25
  86. data/lib/rails/graphql/request/helpers/value_writers.rb +18 -16
  87. data/lib/rails/graphql/request/prepared_data.rb +98 -0
  88. data/lib/rails/graphql/request/steps/authorizable.rb +24 -14
  89. data/lib/rails/graphql/request/steps/organizable.rb +110 -48
  90. data/lib/rails/graphql/request/steps/{prepareable.rb → preparable.rb} +20 -7
  91. data/lib/rails/graphql/request/steps/{resolveable.rb → resolvable.rb} +15 -6
  92. data/lib/rails/graphql/request/strategy/cached_strategy.rb +64 -0
  93. data/lib/rails/graphql/request/strategy/dynamic_instance.rb +6 -6
  94. data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +6 -13
  95. data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +9 -9
  96. data/lib/rails/graphql/request/strategy.rb +131 -75
  97. data/lib/rails/graphql/request/subscription.rb +80 -0
  98. data/lib/rails/graphql/request.rb +305 -86
  99. data/lib/rails/graphql/schema.rb +240 -48
  100. data/lib/rails/graphql/shortcuts.rb +22 -3
  101. data/lib/rails/graphql/source/active_record/builders.rb +49 -35
  102. data/lib/rails/graphql/source/active_record_source.rb +70 -54
  103. data/lib/rails/graphql/source/base.rb +111 -0
  104. data/lib/rails/graphql/source/builder.rb +128 -0
  105. data/lib/rails/graphql/source/scoped_arguments.rb +31 -19
  106. data/lib/rails/graphql/source.rb +89 -213
  107. data/lib/rails/graphql/subscription/provider/action_cable.rb +112 -0
  108. data/lib/rails/graphql/subscription/provider/base.rb +191 -0
  109. data/lib/rails/graphql/subscription/provider.rb +18 -0
  110. data/lib/rails/graphql/subscription/store/base.rb +145 -0
  111. data/lib/rails/graphql/subscription/store/memory.rb +127 -0
  112. data/lib/rails/graphql/subscription/store.rb +19 -0
  113. data/lib/rails/graphql/subscription.rb +17 -0
  114. data/lib/rails/graphql/to_gql.rb +29 -32
  115. data/lib/rails/graphql/type/enum/directive_location_enum.rb +11 -11
  116. data/lib/rails/graphql/type/enum/type_kind_enum.rb +3 -3
  117. data/lib/rails/graphql/type/enum.rb +34 -48
  118. data/lib/rails/graphql/type/input.rb +74 -23
  119. data/lib/rails/graphql/type/interface.rb +16 -26
  120. data/lib/rails/graphql/type/object/directive_object.rb +4 -4
  121. data/lib/rails/graphql/type/object/enum_value_object.rb +3 -3
  122. data/lib/rails/graphql/type/object/field_object.rb +24 -6
  123. data/lib/rails/graphql/type/object/input_value_object.rb +3 -3
  124. data/lib/rails/graphql/type/object/schema_object.rb +5 -8
  125. data/lib/rails/graphql/type/object/type_object.rb +29 -19
  126. data/lib/rails/graphql/type/object.rb +26 -23
  127. data/lib/rails/graphql/type/scalar/any_scalar.rb +30 -0
  128. data/lib/rails/graphql/type/scalar/bigint_scalar.rb +5 -5
  129. data/lib/rails/graphql/type/scalar/binary_scalar.rb +3 -3
  130. data/lib/rails/graphql/type/scalar/boolean_scalar.rb +8 -8
  131. data/lib/rails/graphql/type/scalar/date_scalar.rb +3 -3
  132. data/lib/rails/graphql/type/scalar/date_time_scalar.rb +3 -3
  133. data/lib/rails/graphql/type/scalar/decimal_scalar.rb +3 -3
  134. data/lib/rails/graphql/type/scalar/float_scalar.rb +5 -5
  135. data/lib/rails/graphql/type/scalar/id_scalar.rb +6 -5
  136. data/lib/rails/graphql/type/scalar/int_scalar.rb +6 -5
  137. data/lib/rails/graphql/type/scalar/json_scalar.rb +39 -0
  138. data/lib/rails/graphql/type/scalar/string_scalar.rb +18 -4
  139. data/lib/rails/graphql/type/scalar/time_scalar.rb +5 -5
  140. data/lib/rails/graphql/type/scalar.rb +25 -22
  141. data/lib/rails/graphql/type/union.rb +14 -16
  142. data/lib/rails/graphql/type.rb +34 -25
  143. data/lib/rails/graphql/type_map.rb +256 -164
  144. data/lib/rails/graphql/uri.rb +166 -0
  145. data/lib/rails/graphql/version.rb +15 -3
  146. data/lib/rails/graphql.rake +3 -0
  147. data/lib/rails/graphql.rb +85 -52
  148. data/lib/rails-graphql.rb +1 -1
  149. data/test/assets/en.yml +29 -0
  150. data/test/assets/introspection-mem.txt +1 -1
  151. data/test/assets/mem.gql +18 -45
  152. data/test/assets/mysql.gql +392 -0
  153. data/test/assets/sqlite.gql +21 -12
  154. data/test/assets/translate.gql +335 -0
  155. data/test/config.rb +18 -8
  156. data/test/graphql/schema_test.rb +12 -19
  157. data/test/graphql/source_test.rb +8 -75
  158. data/test/graphql/type/enum_test.rb +207 -203
  159. data/test/graphql/type/input_test.rb +14 -9
  160. data/test/graphql/type/interface_test.rb +4 -4
  161. data/test/graphql/type/scalar/any_scalar_test.rb +38 -0
  162. data/test/graphql/type/scalar/boolean_scalar_test.rb +6 -3
  163. data/test/graphql/type/scalar/json_scalar_test.rb +23 -0
  164. data/test/graphql/type_map_test.rb +51 -66
  165. data/test/graphql/type_test.rb +0 -19
  166. data/test/graphql_test.rb +1 -1
  167. data/test/integration/{authorization/authorization_test.rb → authorization_test.rb} +40 -14
  168. data/test/integration/config.rb +36 -3
  169. data/test/integration/customization_test.rb +39 -0
  170. data/test/integration/global_id_test.rb +99 -0
  171. data/test/integration/memory/star_wars_introspection_test.rb +24 -16
  172. data/test/integration/memory/star_wars_query_test.rb +54 -3
  173. data/test/integration/memory/star_wars_validation_test.rb +1 -1
  174. data/test/integration/mysql/star_wars_introspection_test.rb +25 -0
  175. data/test/integration/persisted_query_test.rb +87 -0
  176. data/test/integration/resolver_precedence_test.rb +154 -0
  177. data/test/integration/schemas/memory.rb +22 -7
  178. data/test/integration/schemas/mysql.rb +62 -0
  179. data/test/integration/schemas/sqlite.rb +21 -12
  180. data/test/integration/sqlite/star_wars_global_id_test.rb +83 -0
  181. data/test/integration/sqlite/star_wars_introspection_test.rb +10 -0
  182. data/test/integration/sqlite/star_wars_query_test.rb +14 -1
  183. data/test/integration/translate_test.rb +61 -0
  184. data/test/test_ext.rb +16 -13
  185. metadata +108 -157
  186. data/ext/depend +0 -3
  187. data/ext/graphqlparser/Ast.cpp +0 -346
  188. data/ext/graphqlparser/Ast.h +0 -1214
  189. data/ext/graphqlparser/AstNode.h +0 -36
  190. data/ext/graphqlparser/AstVisitor.h +0 -137
  191. data/ext/graphqlparser/GraphQLParser.cpp +0 -76
  192. data/ext/graphqlparser/GraphQLParser.h +0 -55
  193. data/ext/graphqlparser/JsonVisitor.cpp +0 -161
  194. data/ext/graphqlparser/JsonVisitor.cpp.inc +0 -456
  195. data/ext/graphqlparser/JsonVisitor.h +0 -121
  196. data/ext/graphqlparser/JsonVisitor.h.inc +0 -110
  197. data/ext/graphqlparser/VERSION +0 -1
  198. data/ext/graphqlparser/c/GraphQLAst.cpp +0 -324
  199. data/ext/graphqlparser/c/GraphQLAst.h +0 -180
  200. data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +0 -44
  201. data/ext/graphqlparser/c/GraphQLAstNode.cpp +0 -25
  202. data/ext/graphqlparser/c/GraphQLAstNode.h +0 -33
  203. data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +0 -21
  204. data/ext/graphqlparser/c/GraphQLAstToJSON.h +0 -24
  205. data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +0 -55
  206. data/ext/graphqlparser/c/GraphQLAstVisitor.h +0 -53
  207. data/ext/graphqlparser/c/GraphQLParser.cpp +0 -35
  208. data/ext/graphqlparser/c/GraphQLParser.h +0 -54
  209. data/ext/graphqlparser/dump_json_ast.cpp +0 -48
  210. data/ext/graphqlparser/lexer.lpp +0 -324
  211. data/ext/graphqlparser/parser.ypp +0 -693
  212. data/ext/graphqlparser/parsergen/lexer.cpp +0 -2633
  213. data/ext/graphqlparser/parsergen/lexer.h +0 -528
  214. data/ext/graphqlparser/parsergen/location.hh +0 -189
  215. data/ext/graphqlparser/parsergen/parser.tab.cpp +0 -3300
  216. data/ext/graphqlparser/parsergen/parser.tab.hpp +0 -646
  217. data/ext/graphqlparser/parsergen/position.hh +0 -179
  218. data/ext/graphqlparser/parsergen/stack.hh +0 -156
  219. data/ext/graphqlparser/syntaxdefs.h +0 -19
  220. data/ext/libgraphqlparser/AstNode.h +0 -36
  221. data/ext/libgraphqlparser/CMakeLists.txt +0 -148
  222. data/ext/libgraphqlparser/CONTRIBUTING.md +0 -23
  223. data/ext/libgraphqlparser/GraphQLParser.cpp +0 -76
  224. data/ext/libgraphqlparser/GraphQLParser.h +0 -55
  225. data/ext/libgraphqlparser/JsonVisitor.cpp +0 -161
  226. data/ext/libgraphqlparser/JsonVisitor.h +0 -121
  227. data/ext/libgraphqlparser/LICENSE +0 -22
  228. data/ext/libgraphqlparser/README.clang-tidy +0 -7
  229. data/ext/libgraphqlparser/README.md +0 -84
  230. data/ext/libgraphqlparser/ast/ast.ast +0 -203
  231. data/ext/libgraphqlparser/ast/ast.py +0 -61
  232. data/ext/libgraphqlparser/ast/c.py +0 -100
  233. data/ext/libgraphqlparser/ast/c.pyc +0 -0
  234. data/ext/libgraphqlparser/ast/c_impl.py +0 -61
  235. data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
  236. data/ext/libgraphqlparser/ast/c_visitor_impl.py +0 -39
  237. data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
  238. data/ext/libgraphqlparser/ast/casing.py +0 -26
  239. data/ext/libgraphqlparser/ast/casing.pyc +0 -0
  240. data/ext/libgraphqlparser/ast/cxx.py +0 -197
  241. data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
  242. data/ext/libgraphqlparser/ast/cxx_impl.py +0 -61
  243. data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
  244. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +0 -42
  245. data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
  246. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +0 -80
  247. data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
  248. data/ext/libgraphqlparser/ast/cxx_visitor.py +0 -64
  249. data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
  250. data/ext/libgraphqlparser/ast/js.py +0 -65
  251. data/ext/libgraphqlparser/ast/license.py +0 -10
  252. data/ext/libgraphqlparser/ast/license.pyc +0 -0
  253. data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +0 -25
  254. data/ext/libgraphqlparser/c/GraphQLAstNode.h +0 -33
  255. data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +0 -21
  256. data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +0 -24
  257. data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +0 -55
  258. data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +0 -53
  259. data/ext/libgraphqlparser/c/GraphQLParser.cpp +0 -35
  260. data/ext/libgraphqlparser/c/GraphQLParser.h +0 -54
  261. data/ext/libgraphqlparser/clang-tidy-all.sh +0 -3
  262. data/ext/libgraphqlparser/cmake/version.cmake +0 -16
  263. data/ext/libgraphqlparser/dump_json_ast.cpp +0 -48
  264. data/ext/libgraphqlparser/go/README.md +0 -20
  265. data/ext/libgraphqlparser/go/callbacks.go +0 -18
  266. data/ext/libgraphqlparser/go/gotest.go +0 -64
  267. data/ext/libgraphqlparser/lexer.lpp +0 -324
  268. data/ext/libgraphqlparser/libgraphqlparser.pc.in +0 -11
  269. data/ext/libgraphqlparser/parser.ypp +0 -693
  270. data/ext/libgraphqlparser/parsergen/lexer.cpp +0 -2633
  271. data/ext/libgraphqlparser/parsergen/lexer.h +0 -528
  272. data/ext/libgraphqlparser/parsergen/location.hh +0 -189
  273. data/ext/libgraphqlparser/parsergen/parser.tab.cpp +0 -3300
  274. data/ext/libgraphqlparser/parsergen/parser.tab.hpp +0 -646
  275. data/ext/libgraphqlparser/parsergen/position.hh +0 -179
  276. data/ext/libgraphqlparser/parsergen/stack.hh +0 -156
  277. data/ext/libgraphqlparser/python/CMakeLists.txt +0 -14
  278. data/ext/libgraphqlparser/python/README.md +0 -5
  279. data/ext/libgraphqlparser/python/example.py +0 -31
  280. data/ext/libgraphqlparser/syntaxdefs.h +0 -19
  281. data/ext/libgraphqlparser/test/BuildCAPI.c +0 -5
  282. data/ext/libgraphqlparser/test/CMakeLists.txt +0 -25
  283. data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +0 -28
  284. data/ext/libgraphqlparser/test/ParserTests.cpp +0 -352
  285. data/ext/libgraphqlparser/test/kitchen-sink.graphql +0 -59
  286. data/ext/libgraphqlparser/test/kitchen-sink.json +0 -1
  287. data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +0 -78
  288. data/ext/libgraphqlparser/test/schema-kitchen-sink.json +0 -1
  289. data/ext/libgraphqlparser/test/valgrind.supp +0 -33
  290. data/ext/version.cpp +0 -21
  291. data/lib/graphqlparser.so +0 -0
  292. data/lib/rails/graphql/native/functions.rb +0 -38
  293. data/lib/rails/graphql/native/location.rb +0 -41
  294. data/lib/rails/graphql/native/pointers.rb +0 -23
  295. data/lib/rails/graphql/native/visitor.rb +0 -349
  296. data/lib/rails/graphql/native.rb +0 -56
  297. data/test/integration/schemas/authorization.rb +0 -12
@@ -86,6 +86,21 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
86
86
  GQL
87
87
  end
88
88
 
89
+ def test_using_alias_to_change_key_name_on_array
90
+ friends = [
91
+ { name: 'Han Solo' },
92
+ { name: 'Leia Organa' },
93
+ { name: 'C-3PO' },
94
+ { name: 'R2-D2' },
95
+ ]
96
+
97
+ assert_result({ data: { luke: { name: 'Luke Skywalker', others: friends } } }, <<~GQL)
98
+ query FetchLukeDeepAliased { luke: human(id: "1000") {
99
+ name others: friends { name }
100
+ } }
101
+ GQL
102
+ end
103
+
89
104
  def test_using_alias_to_change_key_name_twice
90
105
  luke = { name: 'Luke Skywalker' }
91
106
  leia = { name: 'Leia Organa' }
@@ -108,6 +123,15 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
108
123
  GQL
109
124
  end
110
125
 
126
+ def test_query_with_field_argument
127
+ vader = { name: 'Darth Vader', greeting: 'Be gone Luke!' }
128
+ assert_result({ data: { human: vader } }, <<~GQL, variables: { name: 'Luke' })
129
+ query WithFieldArgument($name: String!) {
130
+ human(id: "1001") { name greeting(name: $name) }
131
+ }
132
+ GQL
133
+ end
134
+
111
135
  def test_query_with_fragment
112
136
  luke = { name: 'Luke Skywalker', homePlanet: 'Tatooine' }
113
137
  leia = { name: 'Leia Organa', homePlanet: 'Alderaan' }
@@ -124,6 +148,33 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
124
148
  GQL
125
149
  end
126
150
 
151
+ def test_query_with_fragment_and_field_argument
152
+ vader = { name: 'Darth Vader', greeting: 'Be gone Luke!' }
153
+ assert_result({ data: { human: vader } }, <<~GQL, variables: { name: 'Luke' })
154
+ query WithFieldArgument($name: String!) {
155
+ human(id: "1001") { ...HumanFragment }
156
+ }
157
+
158
+ fragment HumanFragment on Human { name greeting(name: $name) }
159
+ GQL
160
+ end
161
+
162
+ def test_query_with_fragment_and_field_argument_and_default_values
163
+ first = { human: { name: 'Darth Vader', greeting: 'Be gone Luke!' } }
164
+ second = { human: { name: 'Darth Vader', greeting: 'Be gone Leia!' } }
165
+ assert_result({ data: { first: first, second: second } }, <<~GQL)
166
+ query first($id: ID! = 1001, $name: String! = "Luke") {
167
+ human(id: $id) { ...HumanFragment }
168
+ }
169
+
170
+ query second($id: ID! = 1001, $name: String! = "Leia") {
171
+ human(id: $id) { ...HumanFragment }
172
+ }
173
+
174
+ fragment HumanFragment on Human { name greeting(name: $name) }
175
+ GQL
176
+ end
177
+
127
178
  def test_get_typename_field
128
179
  assert_result({ data: { hero: { __typename: 'Droid', name: 'R2-D2' } } }, <<~GQL)
129
180
  query CheckTypeOfR2 { hero { __typename name } }
@@ -143,7 +194,7 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
143
194
  message: 'Secret backstory is secret',
144
195
  locations: [{ line: 1, column: 35 }, { line: 1, column: 50 }],
145
196
  path: %w[HeroNameQuery hero secretBackstory],
146
- extensions: { exception: 'RuntimeError' },
197
+ extensions: { stage: 'resolve', exception: 'RuntimeError' },
147
198
  }]
148
199
 
149
200
  assert_result({ data: { hero: hero }, errors: errors }, <<~GQL)
@@ -159,7 +210,7 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
159
210
  message: 'Secret backstory is secret',
160
211
  locations: [{ line: 1, column: 50 }, { line: 1, column: 65 }],
161
212
  path: ['HeroNameQuery', 'hero', 'friends', n, 'secretBackstory'],
162
- extensions: { exception: 'RuntimeError' },
213
+ extensions: { stage: 'resolve', exception: 'RuntimeError' },
163
214
  }
164
215
  end
165
216
 
@@ -174,7 +225,7 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
174
225
  message: 'Secret backstory is secret',
175
226
  locations: [{ line: 1, column: 35 }, { line: 1, column: 57 }],
176
227
  path: %w[HeroNameQuery hero story],
177
- extensions: { exception: 'RuntimeError' },
228
+ extensions: { stage: 'resolve', exception: 'RuntimeError' },
178
229
  }]
179
230
 
180
231
  assert_result({ data: { hero: hero }, errors: errors }, <<~GQL)
@@ -23,7 +23,7 @@ class Integration_Memory_StarWarsValidationTest < GraphQL::IntegrationTestCase
23
23
 
24
24
  def test_invalid_query
25
25
  errors = [{
26
- message: 'syntax error, unexpected EOF',
26
+ message: 'Parser error: unexpected "EOF"',
27
27
  locations: [{ line: 2, column: 1 }],
28
28
  }]
29
29
 
@@ -0,0 +1,25 @@
1
+ require 'integration/config'
2
+
3
+ class Integration_MySQL_StarWarsIntrospectionTest < GraphQL::IntegrationTestCase
4
+ load_schema 'mysql'
5
+
6
+ SCHEMA = ::StartWarsMySQLSchema
7
+
8
+ def test_auto_introspection
9
+ assert(SCHEMA.introspection?)
10
+ assert(SCHEMA.has_field?(:query, :__schema))
11
+ assert(SCHEMA.has_field?(:query, :__type))
12
+ end
13
+
14
+ # Test this spec with all avaliable scalars
15
+ def remove_keys_form_type_map
16
+ end
17
+
18
+ # There are some issues with the end sorting, so compare the string result
19
+ # with sorted characters, which will produce the exact match
20
+ def test_gql_introspection
21
+ # File.write('test/assets/mysql.gql', SCHEMA.to_gql)
22
+ result = gql_file('mysql').split('').sort.join.squish
23
+ assert_equal(result, SCHEMA.to_gql.split('').sort.join.squish)
24
+ end
25
+ end
@@ -0,0 +1,87 @@
1
+ require 'integration/config'
2
+
3
+ class Integration_PersistedQueryTest < GraphQL::IntegrationTestCase
4
+ class SCHEMA < GraphQL::Schema
5
+ namespace :cached
6
+
7
+ configure do |config|
8
+ config.enable_string_collector = false
9
+ config.default_response_format = :json
10
+ end
11
+
12
+ query_fields do
13
+ field(:one, :string).resolve { 'One!' }
14
+ field(:two, :string).resolve { 'Two!' }
15
+ end
16
+
17
+ class_attribute :cache, instance_writer: false, default: {}
18
+
19
+ class << self
20
+ def cached?(name, *)
21
+ cache.key?(name)
22
+ end
23
+
24
+ def delete_from_cache(name, *)
25
+ cache.delete(name)
26
+ end
27
+
28
+ def read_from_cache(name, *)
29
+ cache[name]
30
+ end
31
+
32
+ def write_on_cache(name, value, *)
33
+ cache[name] = value
34
+ end
35
+ end
36
+ end
37
+
38
+ def teardown
39
+ SCHEMA.cache.clear
40
+ end
41
+
42
+ def test_uncached_query
43
+ assert_result('One!', :one)
44
+ end
45
+
46
+ def test_cache_key
47
+ gen_key = cache_key('B')
48
+ assert_equal('graphql/cached/A', SCHEMA.send(:expand_cache_key, 'A'))
49
+ assert_equal('graphql/cached/B', SCHEMA.send(:expand_cache_key, gen_key).cache_key)
50
+ end
51
+
52
+ def test_cached_query
53
+ value = ::GQLParser.parse_execution('{ two }')
54
+ SCHEMA.write_on_cache((key = cache_key), value)
55
+ assert_result('Two!', :two, hash: key, cache_only: true)
56
+ end
57
+
58
+ def test_persist_query
59
+ assert_result('One!', :one, hash: (key = cache_key))
60
+ assert_operator(SCHEMA, :cached?, key)
61
+ end
62
+
63
+ def test_subsequent_query
64
+ assert_result('One!', :one, hash: (key = cache_key))
65
+ assert_result('One!', :one, hash: key, cache_only: true)
66
+ end
67
+
68
+ def test_execute_compiled_query
69
+ query = GraphQL.compile('{ one }', schema: SCHEMA)
70
+ result = GraphQL.execute(query, compiled: true, schema: SCHEMA)
71
+
72
+ assert_equal('One!', result.dig('data', 'one'))
73
+ end
74
+
75
+ private
76
+
77
+ def cache_key(key = nil, version = nil)
78
+ key ||= SCHEMA.config.cache_prefix + SecureRandom.uuid
79
+ Rails::GraphQL::CacheKey.new(key, version)
80
+ end
81
+
82
+ def assert_result(value, field, **options)
83
+ query = options.delete(:cache_only) ? nil : "{ #{field} }"
84
+ result = GraphQL.execute(query, **options, schema: SCHEMA)
85
+ assert_equal(value, result.dig('data', field.to_s))
86
+ end
87
+ end
@@ -0,0 +1,154 @@
1
+ require 'integration/config'
2
+
3
+ class Integration_ResolverPrecedenceTest < GraphQL::IntegrationTestCase
4
+ EVENT_HANDLERS = { resolve: :@resolver, perform: :@performer }
5
+
6
+ class SCHEMA < GraphQL::Schema
7
+ namespace :precedence
8
+
9
+ configure do |config|
10
+ config.enable_string_collector = false
11
+ config.default_response_format = :json
12
+ end
13
+
14
+ object 'Object1' do
15
+ field(:field1, :string)
16
+ end
17
+
18
+ query_fields do
19
+ field(:query1, :string)
20
+ field(:query2, 'Object1').resolve { OpenStruct.new(field1: 'Default Value') }
21
+ end
22
+
23
+ mutation_fields do
24
+ field(:mutation1, :string).perform { }
25
+ end
26
+ end
27
+
28
+ attr_reader :object, :field
29
+
30
+ def test_simple_query
31
+ object = SCHEMA
32
+ field = object[:query][:query1]
33
+
34
+ # (1) Resolver as block comes first
35
+ stub_handler(field, :resolve, -> { 'Ok 1' }) do
36
+ assert_result('Ok 1', 'query1')
37
+ end
38
+
39
+ # (2) Method on schema comes second
40
+ stub_callable(object, field, :query1, -> { 'Ok 2' }) do
41
+ assert_result('Ok 2', 'query1')
42
+ end
43
+
44
+ # (1) Resolver block has higher precedence than method on schema
45
+ stub_callable(object, field, :query1, -> { 'Nok 3' }) do
46
+ stub_handler(field, :resolve, -> { 'Ok 3' }) do
47
+ assert_result('Ok 3', 'query1')
48
+ end
49
+ end
50
+ end
51
+
52
+ def test_simple_mutation
53
+ object = SCHEMA
54
+ field = object[:mutation][:mutation1]
55
+
56
+ # (1) With performer but no resolver has the higher precedence
57
+ $check = true
58
+ stub_handler(field, :perform, -> { 'Ok 1' }) do
59
+ assert_result('Ok 1', 'mutation1', :mutation)
60
+ end
61
+
62
+ # (2) Performer first and then resolver has the second precedence
63
+ result = ''
64
+ stub_handler(field, :perform, -> { result << 'Ok 2' }) do
65
+ stub_handler(field, :resolve, -> { result << 'Ok 3' }) do
66
+ assert_result('Ok 2Ok 3', 'mutation1', :mutation)
67
+ end
68
+ end
69
+
70
+ # (3) Performer as a method but resolver as block
71
+ result = ''
72
+ stub_callable(object, field, :mutation1!, -> { result << 'Ok 4' }) do
73
+ stub_handler(field, :resolve, -> { result << 'Ok 5' }) do
74
+ assert_result('Ok 4Ok 5', 'mutation1', :mutation)
75
+ end
76
+ end
77
+
78
+ # (4) Performer as a method first and then resolve as a method
79
+ result = ''
80
+ stub_callable(object, field, :mutation1!, -> { result << 'Ok 6' }) do
81
+ stub_callable(object, field, :mutation1, -> { result << 'Ok 7' }) do
82
+ assert_result('Ok 6Ok 7', 'mutation1', :mutation)
83
+ end
84
+ end
85
+
86
+ # (2) Blocks has higher precedence than methods
87
+ result = ''
88
+ stub_callable(object, field, :mutation1!, -> { result << 'Nok 8' }) do
89
+ stub_callable(object, field, :mutation1, -> { result << 'Nok 9' }) do
90
+ stub_handler(field, :perform, -> { result << 'Ok 8' }) do
91
+ stub_handler(field, :resolve, -> { result << 'Ok 9' }) do
92
+ assert_result('Ok 8Ok 9', 'mutation1', :mutation)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def test_simple_object
100
+ object = GraphQL::Object1Object
101
+ field = object[:field1]
102
+
103
+ # (1) Block has higher precedence than default value
104
+ stub_handler(field, :resolve, -> { 'Ok 1' }) do
105
+ assert_result('Ok 1', 'field1.query2')
106
+ end
107
+
108
+ # (2) Method on object comes second
109
+ stub_callable(object, field, :field1, -> { 'Ok 2' }) do
110
+ assert_result('Ok 2', 'field1.query2')
111
+ end
112
+
113
+ # (3) Lastly it will simply put the original resolved value
114
+ assert_result('Default Value', 'field1.query2')
115
+
116
+ # (1) Block has higher precedence than methond on object
117
+ stub_callable(object, field, :field1, -> { 'Nok 3' }) do
118
+ stub_handler(field, :resolve, -> { 'Ok 3' }) do
119
+ assert_result('Ok 3', 'field1.query2')
120
+ end
121
+ end
122
+ end
123
+
124
+ protected
125
+
126
+ def assert_result(expected, field, operation = :query)
127
+ doc, data = field.split('.').reduce(['', expected]) do |(d, r), part|
128
+ ["{ #{part} #{d} }", { part => r }]
129
+ end
130
+
131
+ super({ data: data }, "#{operation} #{doc}")
132
+ end
133
+
134
+ def stub_handler(field, event, *args, **xargs)
135
+ block = args.shift if args.first.is_a?(Proc)
136
+ cb = create_callback(field, event, *args, **xargs, &block)
137
+
138
+ field.get_reset_ivar(:@dynamic_resolver, event == :resolve) do
139
+ field.stub_ivar(EVENT_HANDLERS[event], cb) { yield }
140
+ end
141
+ end
142
+
143
+ def stub_callable(object, field, method_name, block)
144
+ field.get_reset_ivar(:@dynamic_resolver) do
145
+ field.get_reset_ivar(:@resolver) do
146
+ object.stub_imethod(method_name, block) { yield }
147
+ end
148
+ end
149
+ end
150
+
151
+ def create_callback(source, event, *args, **xargs, &block)
152
+ Rails::GraphQL::Callback.new(source, event, *args, **xargs, &block)
153
+ end
154
+ end
@@ -25,7 +25,7 @@ module MemoryTest
25
25
  end
26
26
 
27
27
  class Human < Character
28
- attr_accessor :home_planet
28
+ attr_accessor :home_planet, :greeting
29
29
  end
30
30
 
31
31
  class Droid < Character
@@ -39,33 +39,38 @@ module MemoryTest
39
39
  name: 'Luke Skywalker',
40
40
  friends: ['1002', '1003', '2000', '2001'],
41
41
  appears_in: [0, 1, 2],
42
- home_planet: 'Tatooine'
42
+ home_planet: 'Tatooine',
43
+ greeting: 'Hi %s!',
43
44
  ),
44
45
  '1001' => Human.new(
45
46
  id: '1001',
46
47
  name: 'Darth Vader',
47
48
  friends: ['1004'],
48
49
  appears_in: [0, 1, 2],
49
- home_planet: 'Tatooine'
50
+ home_planet: 'Tatooine',
51
+ greeting: 'Be gone %s!',
50
52
  ),
51
53
  '1002' => Human.new(
52
54
  id: '1002',
53
55
  name: 'Han Solo',
54
56
  friends: ['1000', '1003', '2001'],
55
- appears_in: [0, 1, 2]
57
+ appears_in: [0, 1, 2],
58
+ greeting: 'Hello %s!',
56
59
  ),
57
60
  '1003' => Human.new(
58
61
  id: '1003',
59
62
  name: 'Leia Organa',
60
63
  friends: ['1000', '1002', '2000', '2001'],
61
64
  appears_in: [0, 1, 2],
62
- home_planet: 'Alderaan'
65
+ home_planet: 'Alderaan',
66
+ greeting: 'Greetings %s!',
63
67
  ),
64
68
  '1004' => Human.new(
65
69
  id: '1004',
66
70
  name: 'Wilhuff Tarkin',
67
71
  friends: ['1001'],
68
- appears_in: [0]
72
+ appears_in: [0],
73
+ greeting: 'Sup %s!',
69
74
  ),
70
75
  },
71
76
  droids: {
@@ -92,10 +97,12 @@ class StartWarsMemSchema < GraphQL::Schema
92
97
 
93
98
  configure do |config|
94
99
  config.enable_string_collector = false
100
+ config.default_response_format = :json
95
101
  end
96
102
 
97
103
  rescue_from('StandardError') do |exception|
98
- !!field ? request.exception_to_error(exception, field) : raise
104
+ raise unless exception.source.is_a?(Rails::GraphQL::Request::Component::Field)
105
+ exception.request.exception_to_error(exception, exception.source)
99
106
  end
100
107
 
101
108
  enum 'Episode' do
@@ -149,6 +156,14 @@ class StartWarsMemSchema < GraphQL::Schema
149
156
 
150
157
  field :home_planet, :string,
151
158
  desc: 'The home planet of the human, or null if unknown'
159
+
160
+ field :greeting, :string,
161
+ desc: 'A greeting phrase from this person to someone',
162
+ arguments: arg(:name, :string, null: false)
163
+
164
+ def greeting(name:)
165
+ format(current_value.greeting, name)
166
+ end
152
167
  end
153
168
 
154
169
  object 'Droid' do
@@ -0,0 +1,62 @@
1
+ require 'active_record'
2
+
3
+ class MySQLRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+
6
+ establish_connection(
7
+ name: 'mysql',
8
+ adapter: 'mysql2',
9
+ host: ENV.fetch('GQL_MYSQL_HOST', 'localhost'),
10
+ database: ENV.fetch('GQL_MYSQL_DATABASE', 'starwars'),
11
+ username: ENV.fetch('GQL_MYSQL_USERNAME', 'root'),
12
+ password: ENV['GQL_MYSQL_PASSWORD'],
13
+ )
14
+ end
15
+
16
+ MySQLRecord.connection.instance_eval do
17
+ create_table 'jedi_types', force: :cascade do |t|
18
+ t.string 'name'
19
+ end
20
+
21
+ create_table 'jedis', force: :cascade do |t|
22
+ t.integer 'jedi_type_id'
23
+ t.string 'name'
24
+ end
25
+ end
26
+
27
+ class JediType < MySQLRecord
28
+ has_many :jedi, class_name: 'Jedi', foreign_key: :jedi_type_id
29
+
30
+ accepts_nested_attributes_for :jedi
31
+
32
+ MASTER = create!(name: 'Master')
33
+ PADAWAN = create!(name: 'Padawan')
34
+ end
35
+
36
+ class Jedi < MySQLRecord
37
+ belongs_to :jedi_type, class_name: 'JediType', foreign_key: :jedi_type_id
38
+
39
+ validates :name, presence: true, if: -> { true }
40
+
41
+ create!(name: 'Ioda', jedi_type: JediType::MASTER)
42
+ create!(name: 'Obi-Wan Kenobi', jedi_type: JediType::MASTER)
43
+ create!(name: 'Anakin Skywalker', jedi_type: JediType::PADAWAN)
44
+ create!(name: 'Mace Windu', jedi_type: JediType::MASTER)
45
+ end
46
+
47
+ class StartWarsMySQLSchema < GraphQL::Schema
48
+ namespace :star_wars_mysql
49
+
50
+ configure do |config|
51
+ config.enable_string_collector = false
52
+ config.default_response_format = :json
53
+ end
54
+
55
+ source JediType do
56
+ with_options on: 'jediTypes' do
57
+ scoped_argument(:order) { |o| order(name: o) }
58
+ end
59
+ end
60
+
61
+ source Jedi
62
+ end
@@ -1,14 +1,17 @@
1
1
  require 'active_record'
2
-
3
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
2
+ require 'active_record/database_configurations'
4
3
 
5
4
  ActiveSupport::Inflector.inflections(:en) do |inflect|
6
5
  inflect.irregular 'base', 'bases'
7
6
  end
8
7
 
9
- ActiveRecord::Schema.define(version: 1) do
10
- self.verbose = false
8
+ class SQLiteRecord < ActiveRecord::Base
9
+ self.abstract_class = true
11
10
 
11
+ establish_connection(adapter: 'sqlite3', database: ':memory:')
12
+ end
13
+
14
+ SQLiteRecord.connection.instance_eval do
12
15
  create_table 'lite_factions', force: :cascade do |t|
13
16
  t.string 'name'
14
17
  end
@@ -25,10 +28,6 @@ ActiveRecord::Schema.define(version: 1) do
25
28
  end
26
29
  end
27
30
 
28
- class SQLiteRecord < ActiveRecord::Base
29
- self.abstract_class = true
30
- end
31
-
32
31
  class LiteFaction < SQLiteRecord
33
32
  has_many :bases, class_name: 'LiteBase', foreign_key: :faction_id
34
33
  has_many :ships, class_name: 'LiteShip', foreign_key: :faction_id
@@ -43,6 +42,8 @@ end
43
42
  class LiteBase < SQLiteRecord
44
43
  belongs_to :faction, class_name: 'LiteFaction', foreign_key: :faction_id
45
44
 
45
+ validates :name, presence: true
46
+
46
47
  create!(name: 'Yavin', planet: 'Yavin 4', faction: LiteFaction::REBELS)
47
48
  create!(name: 'Echo Base', planet: 'Hoth', faction: LiteFaction::REBELS)
48
49
  create!(name: 'Secret Hideout', planet: 'Dantooine', faction: LiteFaction::REBELS)
@@ -54,6 +55,8 @@ end
54
55
  class LiteShip < SQLiteRecord
55
56
  belongs_to :faction, class_name: 'LiteFaction', foreign_key: :faction_id
56
57
 
58
+ validates :name, presence: true, if: -> { true }
59
+
57
60
  create!(name: 'X-Wing', faction: LiteFaction::REBELS)
58
61
  create!(name: 'Y-Wing', faction: LiteFaction::REBELS)
59
62
  create!(name: 'A-Wing', faction: LiteFaction::REBELS)
@@ -65,18 +68,24 @@ class LiteShip < SQLiteRecord
65
68
  end
66
69
 
67
70
  class StartWarsSqliteSchema < GraphQL::Schema
68
- namespace :start_wars_sqlite
71
+ namespace :star_wars_sqlite
69
72
 
70
73
  configure do |config|
71
74
  config.enable_string_collector = false
75
+ config.default_response_format = :json
72
76
  end
73
77
 
74
- sources LiteFaction do
78
+ source LiteFaction do
75
79
  with_options on: 'liteFactions' do
76
80
  scoped_argument(:order) { |o| order(name: o) }
77
81
  end
78
82
  end
79
83
 
80
- sources LiteBase
81
- sources LiteShip
84
+ source LiteBase do
85
+ with_options on: 'liteBases' do
86
+ scoped_argument(:order, default: :desc) { |o| order(name: o) }
87
+ end
88
+ end
89
+
90
+ source LiteShip
82
91
  end
@@ -0,0 +1,83 @@
1
+ require 'integration/config'
2
+
3
+ class Integration_SQLite_StarWarsGlobalIDTest < GraphQL::IntegrationTestCase
4
+ load_schema 'sqlite'
5
+
6
+ SCHEMA = ::StartWarsSqliteSchema
7
+
8
+ ## CREATE
9
+
10
+ def test_create_query_field
11
+ obj = GraphQL::LiteFactionSource[:query][:lite_factions]
12
+ assert_gid_value('gql://star-wars-sqlite/LiteFactionSource/query/liteFactions', obj)
13
+ end
14
+
15
+ def test_create_object
16
+ obj = GraphQL::LiteFactionSource.object
17
+ assert_gid_value('gql://star-wars-sqlite/Type/LiteFaction', obj)
18
+ end
19
+
20
+ def test_create_input
21
+ obj = GraphQL::LiteFactionSource.input
22
+ assert_gid_value('gql://star-wars-sqlite/Type/LiteFactionInput', obj)
23
+
24
+ obj = GraphQL::LiteFactionSource.input.deserialize(nil)
25
+ assert_gid_value('gql://star-wars-sqlite/Type/LiteFactionInput?', obj)
26
+
27
+ params = { name: 'Sample' }
28
+ obj = GraphQL::LiteFactionSource.input.deserialize(params)
29
+ assert_gid_value('gql://star-wars-sqlite/Type/LiteFactionInput?name=Sample', obj)
30
+
31
+ params = { name: 'Sample', bases_attributes: [{ name: 'Other' }] }
32
+ obj = GraphQL::LiteFactionSource.input.deserialize(params)
33
+ assert_gid_value('gql://star-wars-sqlite/Type/LiteFactionInput?basesAttributes[][name]=Other&name=Sample', obj)
34
+ end
35
+
36
+ def test_create_object_field
37
+ obj = GraphQL::LiteFactionSource.object[:name]
38
+ assert_gid_value('gql://star-wars-sqlite/LiteFactionObject/name', obj)
39
+ end
40
+
41
+ def assert_gid_value(result, object)
42
+ assert_equal(result.gsub(/\[|\]/, { '[' => '%5B', ']' => '%5D' }), object.to_gid.to_s)
43
+ end
44
+
45
+ ## PARSE
46
+
47
+ def test_parse_query_field
48
+ obj = find_gid('gql://star-wars-sqlite/LiteFactionSource/query/liteFactions')
49
+ assert_equal(GraphQL::LiteFactionSource[:query][:lite_factions], obj)
50
+ end
51
+
52
+ def test_parse_object
53
+ obj = find_gid('gql://star-wars-sqlite/Type/LiteFaction')
54
+ assert_equal(GraphQL::LiteFactionSource.object, obj)
55
+ end
56
+
57
+ def test_parse_input
58
+ obj = find_gid('gql://star-wars-sqlite/Type/LiteFactionInput')
59
+ assert_equal(GraphQL::LiteFactionSource.input, obj)
60
+
61
+ obj = find_gid('gql://star-wars-sqlite/Type/LiteFactionInput?')
62
+ assert_instance_of(GraphQL::LiteFactionSource.input, obj)
63
+ assert_empty(obj.params)
64
+
65
+ obj = find_gid('gql://star-wars-sqlite/Type/LiteFactionInput?name=Sample')
66
+ assert_instance_of(GraphQL::LiteFactionSource.input, obj)
67
+ assert_equal('Sample', obj.params[:name])
68
+
69
+ obj = find_gid('gql://star-wars-sqlite/Type/LiteFactionInput?bases_attributes[][name]=Other&name=Sample')
70
+ assert_instance_of(GraphQL::LiteFactionSource.input, obj)
71
+ assert_equal([{name: 'Other'}], obj.params[:bases_attributes])
72
+ assert_equal('Sample', obj.params[:name])
73
+ end
74
+
75
+ def test_parse_object_field
76
+ obj = find_gid('gql://star-wars-sqlite/LiteFactionObject/name')
77
+ assert_equal(GraphQL::LiteFactionSource.object[:name], obj)
78
+ end
79
+
80
+ def find_gid(gid)
81
+ GraphQL::GlobalID.find(gid)
82
+ end
83
+ end