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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +31 -0
- data/ext/depend +3 -0
- data/ext/extconf.rb +57 -0
- data/ext/graphqlparser/Ast.cpp +346 -0
- data/ext/graphqlparser/Ast.h +1214 -0
- data/ext/graphqlparser/AstNode.h +36 -0
- data/ext/graphqlparser/AstVisitor.h +137 -0
- data/ext/graphqlparser/GraphQLParser.cpp +76 -0
- data/ext/graphqlparser/GraphQLParser.h +55 -0
- data/ext/graphqlparser/JsonVisitor.cpp +161 -0
- data/ext/graphqlparser/JsonVisitor.cpp.inc +456 -0
- data/ext/graphqlparser/JsonVisitor.h +121 -0
- data/ext/graphqlparser/JsonVisitor.h.inc +110 -0
- data/ext/graphqlparser/VERSION +1 -0
- data/ext/graphqlparser/c/GraphQLAst.cpp +324 -0
- data/ext/graphqlparser/c/GraphQLAst.h +180 -0
- data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +44 -0
- data/ext/graphqlparser/c/GraphQLAstNode.cpp +25 -0
- data/ext/graphqlparser/c/GraphQLAstNode.h +33 -0
- data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +21 -0
- data/ext/graphqlparser/c/GraphQLAstToJSON.h +24 -0
- data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +55 -0
- data/ext/graphqlparser/c/GraphQLAstVisitor.h +53 -0
- data/ext/graphqlparser/c/GraphQLParser.cpp +35 -0
- data/ext/graphqlparser/c/GraphQLParser.h +54 -0
- data/ext/graphqlparser/dump_json_ast.cpp +48 -0
- data/ext/graphqlparser/lexer.lpp +324 -0
- data/ext/graphqlparser/parser.ypp +693 -0
- data/ext/graphqlparser/parsergen/lexer.cpp +2633 -0
- data/ext/graphqlparser/parsergen/lexer.h +528 -0
- data/ext/graphqlparser/parsergen/location.hh +189 -0
- data/ext/graphqlparser/parsergen/parser.tab.cpp +3300 -0
- data/ext/graphqlparser/parsergen/parser.tab.hpp +646 -0
- data/ext/graphqlparser/parsergen/position.hh +179 -0
- data/ext/graphqlparser/parsergen/stack.hh +156 -0
- data/ext/graphqlparser/syntaxdefs.h +19 -0
- data/ext/libgraphqlparser/AstNode.h +36 -0
- data/ext/libgraphqlparser/CMakeLists.txt +148 -0
- data/ext/libgraphqlparser/CONTRIBUTING.md +23 -0
- data/ext/libgraphqlparser/GraphQLParser.cpp +76 -0
- data/ext/libgraphqlparser/GraphQLParser.h +55 -0
- data/ext/libgraphqlparser/JsonVisitor.cpp +161 -0
- data/ext/libgraphqlparser/JsonVisitor.h +121 -0
- data/ext/libgraphqlparser/LICENSE +22 -0
- data/ext/libgraphqlparser/README.clang-tidy +7 -0
- data/ext/libgraphqlparser/README.md +84 -0
- data/ext/libgraphqlparser/ast/ast.ast +203 -0
- data/ext/libgraphqlparser/ast/ast.py +61 -0
- data/ext/libgraphqlparser/ast/c.py +100 -0
- data/ext/libgraphqlparser/ast/c.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_impl.py +61 -0
- data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.py +39 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/casing.py +26 -0
- data/ext/libgraphqlparser/ast/casing.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx.py +197 -0
- data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_impl.py +61 -0
- data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +42 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +80 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.py +64 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
- data/ext/libgraphqlparser/ast/js.py +65 -0
- data/ext/libgraphqlparser/ast/license.py +10 -0
- data/ext/libgraphqlparser/ast/license.pyc +0 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +25 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.h +33 -0
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +21 -0
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +24 -0
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +55 -0
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +53 -0
- data/ext/libgraphqlparser/c/GraphQLParser.cpp +35 -0
- data/ext/libgraphqlparser/c/GraphQLParser.h +54 -0
- data/ext/libgraphqlparser/clang-tidy-all.sh +3 -0
- data/ext/libgraphqlparser/cmake/version.cmake +16 -0
- data/ext/libgraphqlparser/dump_json_ast.cpp +48 -0
- data/ext/libgraphqlparser/go/README.md +20 -0
- data/ext/libgraphqlparser/go/callbacks.go +18 -0
- data/ext/libgraphqlparser/go/gotest.go +64 -0
- data/ext/libgraphqlparser/lexer.lpp +324 -0
- data/ext/libgraphqlparser/libgraphqlparser.pc.in +11 -0
- data/ext/libgraphqlparser/parser.ypp +693 -0
- data/ext/libgraphqlparser/parsergen/lexer.cpp +2633 -0
- data/ext/libgraphqlparser/parsergen/lexer.h +528 -0
- data/ext/libgraphqlparser/parsergen/location.hh +189 -0
- data/ext/libgraphqlparser/parsergen/parser.tab.cpp +3300 -0
- data/ext/libgraphqlparser/parsergen/parser.tab.hpp +646 -0
- data/ext/libgraphqlparser/parsergen/position.hh +179 -0
- data/ext/libgraphqlparser/parsergen/stack.hh +156 -0
- data/ext/libgraphqlparser/python/CMakeLists.txt +14 -0
- data/ext/libgraphqlparser/python/README.md +5 -0
- data/ext/libgraphqlparser/python/example.py +31 -0
- data/ext/libgraphqlparser/syntaxdefs.h +19 -0
- data/ext/libgraphqlparser/test/BuildCAPI.c +5 -0
- data/ext/libgraphqlparser/test/CMakeLists.txt +25 -0
- data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +28 -0
- data/ext/libgraphqlparser/test/ParserTests.cpp +352 -0
- data/ext/libgraphqlparser/test/kitchen-sink.graphql +59 -0
- data/ext/libgraphqlparser/test/kitchen-sink.json +1 -0
- data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +78 -0
- data/ext/libgraphqlparser/test/schema-kitchen-sink.json +1 -0
- data/ext/libgraphqlparser/test/valgrind.supp +33 -0
- data/ext/version.cpp +21 -0
- data/lib/generators/graphql/controller_generator.rb +22 -0
- data/lib/generators/graphql/schema_generator.rb +22 -0
- data/lib/generators/graphql/templates/controller.erb +5 -0
- data/lib/generators/graphql/templates/schema.erb +6 -0
- data/lib/graphqlparser.so +0 -0
- data/lib/rails-graphql.rb +2 -0
- data/lib/rails/graphql.rake +1 -0
- data/lib/rails/graphql.rb +185 -0
- data/lib/rails/graphql/adapters/mysql_adapter.rb +0 -0
- data/lib/rails/graphql/adapters/pg_adapter.rb +50 -0
- data/lib/rails/graphql/adapters/sqlite_adapter.rb +39 -0
- data/lib/rails/graphql/argument.rb +220 -0
- data/lib/rails/graphql/callback.rb +124 -0
- data/lib/rails/graphql/collectors.rb +14 -0
- data/lib/rails/graphql/collectors/hash_collector.rb +83 -0
- data/lib/rails/graphql/collectors/idented_collector.rb +73 -0
- data/lib/rails/graphql/collectors/json_collector.rb +114 -0
- data/lib/rails/graphql/config.rb +61 -0
- data/lib/rails/graphql/directive.rb +203 -0
- data/lib/rails/graphql/directive/deprecated_directive.rb +59 -0
- data/lib/rails/graphql/directive/include_directive.rb +24 -0
- data/lib/rails/graphql/directive/skip_directive.rb +24 -0
- data/lib/rails/graphql/errors.rb +42 -0
- data/lib/rails/graphql/event.rb +141 -0
- data/lib/rails/graphql/field.rb +318 -0
- data/lib/rails/graphql/field/input_field.rb +92 -0
- data/lib/rails/graphql/field/mutation_field.rb +52 -0
- data/lib/rails/graphql/field/output_field.rb +96 -0
- data/lib/rails/graphql/field/proxied_field.rb +131 -0
- data/lib/rails/graphql/field/resolved_field.rb +96 -0
- data/lib/rails/graphql/field/scoped_config.rb +22 -0
- data/lib/rails/graphql/field/typed_field.rb +104 -0
- data/lib/rails/graphql/helpers.rb +40 -0
- data/lib/rails/graphql/helpers/attribute_delegator.rb +39 -0
- data/lib/rails/graphql/helpers/inherited_collection.rb +152 -0
- data/lib/rails/graphql/helpers/leaf_from_ar.rb +141 -0
- data/lib/rails/graphql/helpers/registerable.rb +103 -0
- data/lib/rails/graphql/helpers/with_arguments.rb +125 -0
- data/lib/rails/graphql/helpers/with_assignment.rb +113 -0
- data/lib/rails/graphql/helpers/with_callbacks.rb +55 -0
- data/lib/rails/graphql/helpers/with_directives.rb +126 -0
- data/lib/rails/graphql/helpers/with_events.rb +81 -0
- data/lib/rails/graphql/helpers/with_fields.rb +141 -0
- data/lib/rails/graphql/helpers/with_namespace.rb +40 -0
- data/lib/rails/graphql/helpers/with_owner.rb +35 -0
- data/lib/rails/graphql/helpers/with_schema_fields.rb +230 -0
- data/lib/rails/graphql/helpers/with_validator.rb +52 -0
- data/lib/rails/graphql/introspection.rb +53 -0
- data/lib/rails/graphql/native.rb +56 -0
- data/lib/rails/graphql/native/functions.rb +38 -0
- data/lib/rails/graphql/native/location.rb +41 -0
- data/lib/rails/graphql/native/pointers.rb +23 -0
- data/lib/rails/graphql/native/visitor.rb +349 -0
- data/lib/rails/graphql/railtie.rb +85 -0
- data/lib/rails/graphql/railties/base_generator.rb +35 -0
- data/lib/rails/graphql/railties/controller.rb +101 -0
- data/lib/rails/graphql/railties/controller_runtime.rb +40 -0
- data/lib/rails/graphql/railties/log_subscriber.rb +62 -0
- data/lib/rails/graphql/request.rb +343 -0
- data/lib/rails/graphql/request/arguments.rb +93 -0
- data/lib/rails/graphql/request/component.rb +100 -0
- data/lib/rails/graphql/request/component/field.rb +225 -0
- data/lib/rails/graphql/request/component/fragment.rb +118 -0
- data/lib/rails/graphql/request/component/operation.rb +178 -0
- data/lib/rails/graphql/request/component/operation/subscription.rb +16 -0
- data/lib/rails/graphql/request/component/spread.rb +119 -0
- data/lib/rails/graphql/request/component/typename.rb +82 -0
- data/lib/rails/graphql/request/context.rb +51 -0
- data/lib/rails/graphql/request/errors.rb +54 -0
- data/lib/rails/graphql/request/event.rb +112 -0
- data/lib/rails/graphql/request/helpers/directives.rb +64 -0
- data/lib/rails/graphql/request/helpers/selection_set.rb +87 -0
- data/lib/rails/graphql/request/helpers/value_writers.rb +115 -0
- data/lib/rails/graphql/request/steps/organizable.rb +146 -0
- data/lib/rails/graphql/request/steps/prepareable.rb +33 -0
- data/lib/rails/graphql/request/steps/resolveable.rb +32 -0
- data/lib/rails/graphql/request/strategy.rb +249 -0
- data/lib/rails/graphql/request/strategy/dynamic_instance.rb +41 -0
- data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +36 -0
- data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +28 -0
- data/lib/rails/graphql/schema.rb +272 -0
- data/lib/rails/graphql/shortcuts.rb +77 -0
- data/lib/rails/graphql/source.rb +371 -0
- data/lib/rails/graphql/source/active_record/builders.rb +154 -0
- data/lib/rails/graphql/source/active_record_source.rb +231 -0
- data/lib/rails/graphql/source/scoped_arguments.rb +87 -0
- data/lib/rails/graphql/to_gql.rb +368 -0
- data/lib/rails/graphql/type.rb +138 -0
- data/lib/rails/graphql/type/enum.rb +206 -0
- data/lib/rails/graphql/type/enum/directive_location_enum.rb +30 -0
- data/lib/rails/graphql/type/enum/type_kind_enum.rb +57 -0
- data/lib/rails/graphql/type/input.rb +134 -0
- data/lib/rails/graphql/type/interface.rb +82 -0
- data/lib/rails/graphql/type/object.rb +111 -0
- data/lib/rails/graphql/type/object/directive_object.rb +34 -0
- data/lib/rails/graphql/type/object/enum_value_object.rb +25 -0
- data/lib/rails/graphql/type/object/field_object.rb +54 -0
- data/lib/rails/graphql/type/object/input_value_object.rb +49 -0
- data/lib/rails/graphql/type/object/schema_object.rb +40 -0
- data/lib/rails/graphql/type/object/type_object.rb +136 -0
- data/lib/rails/graphql/type/scalar.rb +71 -0
- data/lib/rails/graphql/type/scalar/bigint_scalar.rb +34 -0
- data/lib/rails/graphql/type/scalar/binary_scalar.rb +30 -0
- data/lib/rails/graphql/type/scalar/boolean_scalar.rb +37 -0
- data/lib/rails/graphql/type/scalar/date_scalar.rb +34 -0
- data/lib/rails/graphql/type/scalar/date_time_scalar.rb +32 -0
- data/lib/rails/graphql/type/scalar/decimal_scalar.rb +35 -0
- data/lib/rails/graphql/type/scalar/float_scalar.rb +32 -0
- data/lib/rails/graphql/type/scalar/id_scalar.rb +39 -0
- data/lib/rails/graphql/type/scalar/int_scalar.rb +36 -0
- data/lib/rails/graphql/type/scalar/string_scalar.rb +28 -0
- data/lib/rails/graphql/type/scalar/time_scalar.rb +40 -0
- data/lib/rails/graphql/type/union.rb +87 -0
- data/lib/rails/graphql/type_map.rb +347 -0
- data/lib/rails/graphql/version.rb +7 -0
- data/test/assets/introspection-db.json +0 -0
- data/test/assets/introspection-mem.txt +1 -0
- data/test/assets/introspection.gql +91 -0
- data/test/assets/luke.jpg +0 -0
- data/test/assets/mem.gql +428 -0
- data/test/assets/sqlite.gql +423 -0
- data/test/config.rb +80 -0
- data/test/graphql/request/context_test.rb +70 -0
- data/test/graphql/schema_test.rb +190 -0
- data/test/graphql/source_test.rb +237 -0
- data/test/graphql/type/enum_test.rb +203 -0
- data/test/graphql/type/input_test.rb +138 -0
- data/test/graphql/type/interface_test.rb +72 -0
- data/test/graphql/type/object_test.rb +104 -0
- data/test/graphql/type/scalar/bigint_scalar_test.rb +42 -0
- data/test/graphql/type/scalar/binary_scalar_test.rb +17 -0
- data/test/graphql/type/scalar/boolean_scalar_test.rb +40 -0
- data/test/graphql/type/scalar/date_scalar_test.rb +29 -0
- data/test/graphql/type/scalar/date_time_scalar_test.rb +29 -0
- data/test/graphql/type/scalar/decimal_scalar_test.rb +28 -0
- data/test/graphql/type/scalar/float_scalar_test.rb +22 -0
- data/test/graphql/type/scalar/id_scalar_test.rb +26 -0
- data/test/graphql/type/scalar/int_scalar_test.rb +26 -0
- data/test/graphql/type/scalar/string_scalar_test.rb +17 -0
- data/test/graphql/type/scalar/time_scalar_test.rb +36 -0
- data/test/graphql/type/scalar_test.rb +45 -0
- data/test/graphql/type/union_test.rb +82 -0
- data/test/graphql/type_map_test.rb +362 -0
- data/test/graphql/type_test.rb +68 -0
- data/test/graphql_test.rb +55 -0
- data/test/integration/config.rb +56 -0
- data/test/integration/memory/star_wars_introspection_test.rb +144 -0
- data/test/integration/memory/star_wars_query_test.rb +184 -0
- data/test/integration/memory/star_wars_validation_test.rb +99 -0
- data/test/integration/schemas/memory.rb +232 -0
- data/test/integration/schemas/sqlite.rb +82 -0
- data/test/integration/sqlite/star_wars_introspection_test.rb +15 -0
- data/test/integration/sqlite/star_wars_mutation_test.rb +82 -0
- data/test/integration/sqlite/star_wars_query_test.rb +71 -0
- data/test/test_ext.rb +48 -0
- metadata +509 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'config'
|
2
|
+
|
3
|
+
require 'active_support/core_ext/class/subclasses'
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class IntegrationTestCase < TestCase
|
7
|
+
SCHEMAS = Pathname.new(__dir__).join('schemas')
|
8
|
+
ASSETS = Pathname.new(__dir__).join('../assets')
|
9
|
+
|
10
|
+
def setup
|
11
|
+
reset_type_map!
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def self.load_schema(name)
|
17
|
+
require(SCHEMAS.join("#{name}"))
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset_type_map!
|
21
|
+
Rails::GraphQL.type_map.hard_reset!
|
22
|
+
end
|
23
|
+
|
24
|
+
def named_list(*list, **extra)
|
25
|
+
list.map { |x| extra.reverse_merge(name: x) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def gql_file(name)
|
29
|
+
ASSETS.join("#{name}.gql").read
|
30
|
+
end
|
31
|
+
|
32
|
+
def text_file(name)
|
33
|
+
ASSETS.join("#{name}.txt").read
|
34
|
+
end
|
35
|
+
|
36
|
+
def json_file(name)
|
37
|
+
JSON.parse(ASSETS.join("#{name}.json").read)
|
38
|
+
end
|
39
|
+
|
40
|
+
def execute(*args, **xargs)
|
41
|
+
xargs[:as] ||= :object
|
42
|
+
xargs[:schema] ||= self.class.const_get(:SCHEMA)
|
43
|
+
::GraphQL.execute(*args, **xargs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_result(obj, *args, dig: nil, **xargs)
|
47
|
+
result = execute(*args, **xargs)
|
48
|
+
result = result.try(:dig, *dig) if !!dig
|
49
|
+
yield result if block_given?
|
50
|
+
|
51
|
+
obj = obj.deep_stringify_keys if obj.is_a?(Hash)
|
52
|
+
obj = obj.map(&:deep_stringify_keys) if obj.is_a?(Array)
|
53
|
+
obj.nil? ? assert_nil(result) : assert_equal(obj, result)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'integration/config'
|
2
|
+
|
3
|
+
# See: https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsIntrospection-test.js
|
4
|
+
class Integration_Memory_StarWarsIntrospectionTest < GraphQL::IntegrationTestCase
|
5
|
+
load_schema 'memory'
|
6
|
+
|
7
|
+
SCHEMA = ::StartWarsMemSchema
|
8
|
+
|
9
|
+
def test_query_schema_types
|
10
|
+
types = named_list(*%w[Bigint Binary Boolean Character Date DateTime Decimal Droid Episode
|
11
|
+
Float Human ID Int String Time _Mutation _Query __Directive __DirectiveLocation
|
12
|
+
__EnumValue __Field __InputValue __Schema __Type __TypeKind])
|
13
|
+
|
14
|
+
sort_items = ->(result) do
|
15
|
+
result.dig('data', '__schema', 'types').sort_by! { |t| t['name'] }
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_result({ data: { __schema: { types: types } } }, <<~GQL, &sort_items)
|
19
|
+
{ __schema { types { name } } }
|
20
|
+
GQL
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_query_schema_query_type
|
24
|
+
assert_result({ data: { __schema: { queryType: { name: '_Query' } } } }, <<~GQL)
|
25
|
+
{ __schema { queryType { name } } }
|
26
|
+
GQL
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_query_schema_mutation_type
|
30
|
+
assert_result({ data: { __schema: { mutationType: { name: '_Mutation' } } } }, <<~GQL)
|
31
|
+
{ __schema { mutationType { name } } }
|
32
|
+
GQL
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_query_specific_type
|
36
|
+
assert_result({ data: { __type: { name: 'Droid' } } }, <<~GQL)
|
37
|
+
{ __type(name: "Droid") { name } }
|
38
|
+
GQL
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_query_specific_type_with_kind
|
42
|
+
assert_result({ data: { __type: { name: 'Droid', kind: 'OBJECT' } } }, <<~GQL)
|
43
|
+
{ __type(name: "Droid") { name kind } }
|
44
|
+
GQL
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_query_specific_type_as_interface
|
48
|
+
assert_result({ data: { __type: { name: 'Character', kind: 'INTERFACE' } } }, <<~GQL)
|
49
|
+
{ __type(name: "Character") { name kind } }
|
50
|
+
GQL
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_query_object_fields
|
54
|
+
fields = [
|
55
|
+
{ name: 'id', type: { name: nil, kind: 'NON_NULL' } },
|
56
|
+
{ name: 'name', type: { name: 'String', kind: 'SCALAR' } },
|
57
|
+
{ name: 'friends', type: { name: nil, kind: 'LIST' } },
|
58
|
+
{ name: 'appearsIn', type: { name: nil, kind: 'LIST' } },
|
59
|
+
{ name: 'secretBackstory', type: { name: 'String', kind: 'SCALAR' } },
|
60
|
+
{ name: 'primaryFunction', type: { name: 'String', kind: 'SCALAR' } },
|
61
|
+
]
|
62
|
+
|
63
|
+
assert_result({ data: { __type: { name: 'Droid', fields: fields } } }, <<~GQL)
|
64
|
+
{ __type(name: "Droid") { name fields { name type { name kind } } } }
|
65
|
+
GQL
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_query_object_fields_with_nested_type
|
69
|
+
fields = [
|
70
|
+
{ name: 'id', type: { name: nil, kind: 'NON_NULL', ofType: { name: 'ID', kind: 'SCALAR' } } },
|
71
|
+
{ name: 'name', type: { name: 'String', kind: 'SCALAR', ofType: nil } },
|
72
|
+
{ name: 'friends', type: { name: nil, kind: 'LIST', ofType: { name: 'Character', kind: 'INTERFACE' } } },
|
73
|
+
{ name: 'appearsIn', type: { name: nil, kind: 'LIST', ofType: { name: 'Episode', kind: 'ENUM' } } },
|
74
|
+
{ name: 'secretBackstory', type: { name: 'String', kind: 'SCALAR', ofType: nil } },
|
75
|
+
{ name: 'primaryFunction', type: { name: 'String', kind: 'SCALAR', ofType: nil } },
|
76
|
+
]
|
77
|
+
|
78
|
+
assert_result({ data: { __type: { name: 'Droid', fields: fields } } }, <<~GQL)
|
79
|
+
{
|
80
|
+
__type(name: "Droid") {
|
81
|
+
name fields { name type { name kind ofType { name kind } } }
|
82
|
+
}
|
83
|
+
}
|
84
|
+
GQL
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_query_object_with_arguments
|
88
|
+
name_arg = { name: 'name', description: nil, type: {
|
89
|
+
name: nil, kind: 'NON_NULL', ofType: { name: 'String', kind: 'SCALAR' } ,
|
90
|
+
}, defaultValue: nil }
|
91
|
+
|
92
|
+
epi_arg = { name: 'episode', description: 'Return for a specific episode', type: {
|
93
|
+
name: 'Episode', kind: 'ENUM', ofType: nil,
|
94
|
+
}, defaultValue: nil }
|
95
|
+
|
96
|
+
id_arg = { name: 'id', description: nil, type: {
|
97
|
+
name: nil, kind: 'NON_NULL', ofType: { name: 'ID', kind: 'SCALAR' } ,
|
98
|
+
}, defaultValue: nil }
|
99
|
+
|
100
|
+
fields = [
|
101
|
+
{ name: '__schema', args: [] },
|
102
|
+
{ name: '__type', args: [name_arg] },
|
103
|
+
{ name: 'hero', args: [epi_arg] },
|
104
|
+
{ name: 'human', args: [id_arg.merge(description: 'ID of the human')] },
|
105
|
+
{ name: 'droid', args: [id_arg.merge(description: 'ID of the droid')] },
|
106
|
+
]
|
107
|
+
|
108
|
+
assert_result({ data: { __schema: { queryType: { fields: fields } } } }, <<~GQL)
|
109
|
+
{ __schema { queryType { fields {
|
110
|
+
name
|
111
|
+
args {
|
112
|
+
name
|
113
|
+
description
|
114
|
+
type { name kind ofType { name kind } }
|
115
|
+
defaultValue
|
116
|
+
}
|
117
|
+
} } } }
|
118
|
+
GQL
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_query_schema_documentation
|
122
|
+
description = 'A mechanical creature in the Star Wars universe'
|
123
|
+
assert_result({ data: { __type: { name: 'Droid', description: description } } }, <<~GQL)
|
124
|
+
{ __type(name: "Droid") { name description } }
|
125
|
+
GQL
|
126
|
+
end
|
127
|
+
|
128
|
+
# There are some issues with the end sorting, so compare the string result
|
129
|
+
# with sorted characters, which will produce the exact match
|
130
|
+
def test_query_full_introspection
|
131
|
+
query = gql_file('introspection')
|
132
|
+
result = text_file('introspection-mem').split('').sort.join
|
133
|
+
assert_result(result, query, as: :string) do |res|
|
134
|
+
# File.write('test/assets/introspection-mem.txt', res)
|
135
|
+
res.replace(res.split('').sort.join)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_gql_introspection
|
140
|
+
# File.write('test/assets/mem.gql', SCHEMA.to_gql)
|
141
|
+
result = gql_file('mem').split('').sort.join.squish
|
142
|
+
assert_equal(result, SCHEMA.to_gql.split('').sort.join.squish)
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'integration/config'
|
2
|
+
|
3
|
+
# See: https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsQuery-test.js
|
4
|
+
class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
|
5
|
+
load_schema 'memory'
|
6
|
+
|
7
|
+
SCHEMA = ::StartWarsMemSchema
|
8
|
+
ALL_EPISODES = %w[NEW_HOPE EMPIRE JEDI]
|
9
|
+
|
10
|
+
def test_r2d2_saga_hero
|
11
|
+
assert_result({ data: { hero: { name: 'R2-D2' } } }, <<~GQL)
|
12
|
+
query HeroNameQuery { hero { name } }
|
13
|
+
GQL
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_r2d2_by_id_and_friends
|
17
|
+
friends = named_list('Luke Skywalker', 'Han Solo', 'Leia Organa')
|
18
|
+
hero = { id: '2001', name: 'R2-D2', friends: friends }
|
19
|
+
assert_result({ data: { hero: hero } }, <<~GQL)
|
20
|
+
query HeroNameAndFriendsQuery {
|
21
|
+
hero { id name friends { name } }
|
22
|
+
}
|
23
|
+
GQL
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_r2d2_friends_of_friends
|
27
|
+
friends1 = named_list('Han Solo', 'Leia Organa', 'C-3PO', 'R2-D2')
|
28
|
+
friends2 = named_list('Luke Skywalker', 'Leia Organa', 'R2-D2')
|
29
|
+
friends3 = named_list('Luke Skywalker', 'Han Solo', 'C-3PO', 'R2-D2')
|
30
|
+
friends = [
|
31
|
+
{ name: 'Luke Skywalker', appearsIn: ALL_EPISODES, friends: friends1 },
|
32
|
+
{ name: 'Han Solo', appearsIn: ALL_EPISODES, friends: friends2 },
|
33
|
+
{ name: 'Leia Organa', appearsIn: ALL_EPISODES, friends: friends3 },
|
34
|
+
]
|
35
|
+
|
36
|
+
hero = { name: 'R2-D2', friends: friends }
|
37
|
+
assert_result({ data: { hero: hero } }, <<~GQL)
|
38
|
+
query NestedQuery {
|
39
|
+
hero { name friends { name appearsIn friends { name } } }
|
40
|
+
}
|
41
|
+
GQL
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_using_ids_refetch
|
45
|
+
human = { name: 'Luke Skywalker' }
|
46
|
+
droid = { name: 'C-3PO' }
|
47
|
+
|
48
|
+
assert_result({ data: { human: human, droid: droid } }, <<~GQL)
|
49
|
+
query FetchLukeAndC3POQuery {
|
50
|
+
human(id: "1000") { name }
|
51
|
+
droid(id: "2000") { name }
|
52
|
+
}
|
53
|
+
GQL
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_generic_query_fetch_by_id_luke
|
57
|
+
xargs = { args: { some_id: '1000' } }
|
58
|
+
assert_result({ data: { human: { name: 'Luke Skywalker' } } }, <<~GQL, **xargs)
|
59
|
+
query FetchSomeIDQuery($someId: ID!) {
|
60
|
+
human(id: $someId) { name }
|
61
|
+
}
|
62
|
+
GQL
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_generic_query_fetch_by_id_han
|
66
|
+
xargs = { args: { some_id: '1002' } }
|
67
|
+
assert_result({ data: { human: { name: 'Han Solo' } } }, <<~GQL, **xargs)
|
68
|
+
query FetchSomeIDQuery($someId: ID!) {
|
69
|
+
human(id: $someId) { name }
|
70
|
+
}
|
71
|
+
GQL
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_generic_query_fetch_by_id_invalid
|
75
|
+
xargs = { args: { id: 'not a valid id' } }
|
76
|
+
assert_result({ data: { human: nil } }, <<~GQL, **xargs)
|
77
|
+
query FetchSomeIDQuery($id: ID!) {
|
78
|
+
human(id: $id) { name }
|
79
|
+
}
|
80
|
+
GQL
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_using_alias_to_change_key_name
|
84
|
+
assert_result({ data: { luke: { name: 'Luke Skywalker' } } }, <<~GQL)
|
85
|
+
query FetchLukeAliased { luke: human(id: "1000") { name } }
|
86
|
+
GQL
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_using_alias_to_change_key_name_twice
|
90
|
+
luke = { name: 'Luke Skywalker' }
|
91
|
+
leia = { name: 'Leia Organa' }
|
92
|
+
assert_result({ data: { luke: luke, leia: leia } }, <<~GQL)
|
93
|
+
query FetchLukeAliased {
|
94
|
+
luke: human(id: "1000") { name }
|
95
|
+
leia: human(id: "1003") { name }
|
96
|
+
}
|
97
|
+
GQL
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_query_with_duplicated_content
|
101
|
+
luke = { name: 'Luke Skywalker', homePlanet: 'Tatooine' }
|
102
|
+
leia = { name: 'Leia Organa', homePlanet: 'Alderaan' }
|
103
|
+
assert_result({ data: { luke: luke, leia: leia } }, <<~GQL)
|
104
|
+
query DuplicateFields {
|
105
|
+
luke: human(id: "1000") { name homePlanet }
|
106
|
+
leia: human(id: "1003") { name homePlanet }
|
107
|
+
}
|
108
|
+
GQL
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_query_with_fragment
|
112
|
+
luke = { name: 'Luke Skywalker', homePlanet: 'Tatooine' }
|
113
|
+
leia = { name: 'Leia Organa', homePlanet: 'Alderaan' }
|
114
|
+
assert_result({ data: { luke: luke, leia: leia } }, <<~GQL)
|
115
|
+
query DuplicateFields {
|
116
|
+
luke: human(id: "1000") { ...HumanFragment }
|
117
|
+
leia: human(id: "1003") { ...HumanFragment }
|
118
|
+
}
|
119
|
+
|
120
|
+
fragment HumanFragment on Human {
|
121
|
+
name
|
122
|
+
homePlanet
|
123
|
+
}
|
124
|
+
GQL
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_get_typename_field
|
128
|
+
assert_result({ data: { hero: { __typename: 'Droid', name: 'R2-D2' } } }, <<~GQL)
|
129
|
+
query CheckTypeOfR2 { hero { __typename name } }
|
130
|
+
GQL
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_get_typename_from_luke
|
134
|
+
luke = { __typename: 'Human', name: 'Luke Skywalker' }
|
135
|
+
assert_result({ data: { hero: luke } }, <<~GQL)
|
136
|
+
query CheckTypeOfLuke { hero(episode: EMPIRE) { __typename name } }
|
137
|
+
GQL
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_error_on_secret_backstory
|
141
|
+
hero = { name: 'R2-D2', secretBackstory: nil }
|
142
|
+
errors = [{
|
143
|
+
message: 'Secret backstory is secret',
|
144
|
+
locations: [{ line: 1, column: 35 }, { line: 1, column: 50 }],
|
145
|
+
path: %w[HeroNameQuery hero secretBackstory],
|
146
|
+
extensions: { exception: 'RuntimeError' },
|
147
|
+
}]
|
148
|
+
|
149
|
+
assert_result({ data: { hero: hero }, errors: errors }, <<~GQL)
|
150
|
+
query HeroNameQuery { hero { name secretBackstory } }
|
151
|
+
GQL
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_nested_secret_backstory
|
155
|
+
friends = named_list('Luke Skywalker', 'Han Solo', 'Leia Organa', secretBackstory: nil)
|
156
|
+
hero = { name: 'R2-D2', friends: friends }
|
157
|
+
errors = 3.times.map do |n|
|
158
|
+
{
|
159
|
+
message: 'Secret backstory is secret',
|
160
|
+
locations: [{ line: 1, column: 50 }, { line: 1, column: 65 }],
|
161
|
+
path: ['HeroNameQuery', 'hero', 'friends', n, 'secretBackstory'],
|
162
|
+
extensions: { exception: 'RuntimeError' },
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_result({ data: { hero: hero }, errors: errors }, <<~GQL)
|
167
|
+
query HeroNameQuery { hero { name friends { name secretBackstory } } }
|
168
|
+
GQL
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_backstory_on_alias
|
172
|
+
hero = { name: 'R2-D2', story: nil }
|
173
|
+
errors = [{
|
174
|
+
message: 'Secret backstory is secret',
|
175
|
+
locations: [{ line: 1, column: 35 }, { line: 1, column: 57 }],
|
176
|
+
path: %w[HeroNameQuery hero story],
|
177
|
+
extensions: { exception: 'RuntimeError' },
|
178
|
+
}]
|
179
|
+
|
180
|
+
assert_result({ data: { hero: hero }, errors: errors }, <<~GQL)
|
181
|
+
query HeroNameQuery { hero { name story: secretBackstory } }
|
182
|
+
GQL
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'integration/config'
|
2
|
+
|
3
|
+
# See: https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsValidation-test.js
|
4
|
+
class Integration_Memory_StarWarsValidationTest < GraphQL::IntegrationTestCase
|
5
|
+
load_schema 'memory'
|
6
|
+
|
7
|
+
SCHEMA = ::StartWarsMemSchema
|
8
|
+
|
9
|
+
def test_complex_but_valid_query
|
10
|
+
assert_result(nil, <<~GQL, dig: 'errors')
|
11
|
+
query NestedQueryWithFragment { hero {
|
12
|
+
...NameAndAppearances friends { ...NameAndAppearances friends {
|
13
|
+
...NameAndAppearances
|
14
|
+
} }
|
15
|
+
} }
|
16
|
+
|
17
|
+
fragment NameAndAppearances on Character {
|
18
|
+
name
|
19
|
+
appearsIn
|
20
|
+
}
|
21
|
+
GQL
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_invalid_query
|
25
|
+
errors = [{
|
26
|
+
message: 'syntax error, unexpected EOF',
|
27
|
+
locations: [{ line: 2, column: 1 }],
|
28
|
+
}]
|
29
|
+
|
30
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
31
|
+
query DroidFieldInFragment { hero { name ... on Droid { primaryFunction
|
32
|
+
GQL
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_nonexistent_fields
|
36
|
+
errors = [{
|
37
|
+
message: 'Unable to find a field named "favoriteSpaceship" on GraphQL::CharacterInterface.',
|
38
|
+
locations: [{ line: 1, column: 35 }, { line: 1, column: 52 }],
|
39
|
+
path: %w[HeroSpaceshipQuery hero favoriteSpaceship],
|
40
|
+
extensions: { stage: 'organize', exception: 'Rails::GraphQL::MissingFieldError' },
|
41
|
+
}]
|
42
|
+
|
43
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
44
|
+
query HeroSpaceshipQuery { hero { favoriteSpaceship } }
|
45
|
+
GQL
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_requires_fields
|
49
|
+
errors = [{
|
50
|
+
message: 'The "hero" was assigned to the Character which is not a leaf type and requires a selection of fields.',
|
51
|
+
locations: [{ line: 1, column: 28 }, { line: 1, column: 32 }],
|
52
|
+
path: %w[HeroSpaceshipQuery hero],
|
53
|
+
extensions: { stage: 'organize', exception: 'Rails::GraphQL::FieldError' },
|
54
|
+
}]
|
55
|
+
|
56
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
57
|
+
query HeroSpaceshipQuery { hero }
|
58
|
+
GQL
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_disallows_fields_on_scalars
|
62
|
+
errors = [{
|
63
|
+
message: 'The "name" was assigned to the String which is a leaf type and does not have nested fields.',
|
64
|
+
locations: [{ line: 1, column: 35 }, { line: 1, column: 64 }],
|
65
|
+
path: %w[HeroSpaceshipQuery hero name],
|
66
|
+
extensions: { stage: 'organize', exception: 'Rails::GraphQL::FieldError' },
|
67
|
+
}]
|
68
|
+
|
69
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
70
|
+
query HeroSpaceshipQuery { hero { name { firstCharacterOfName } } }
|
71
|
+
GQL
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_specific_fields_on_interfaces
|
75
|
+
errors = [{
|
76
|
+
message: 'Unable to find a field named "primaryFunction" on GraphQL::CharacterInterface.',
|
77
|
+
locations: [{ line: 1, column: 40 }, { line: 1, column: 55 }],
|
78
|
+
path: %w[HeroSpaceshipQuery hero primaryFunction],
|
79
|
+
extensions: { stage: 'organize', exception: 'Rails::GraphQL::MissingFieldError' },
|
80
|
+
}]
|
81
|
+
|
82
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
83
|
+
query HeroSpaceshipQuery { hero { name primaryFunction } }
|
84
|
+
GQL
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_allow_specific_fields_with_fragments
|
88
|
+
assert_result(nil, <<~GQL, dig: 'errors')
|
89
|
+
query DroidFieldInFragment { hero { name ...DroidFields } }
|
90
|
+
fragment DroidFields on Droid { primaryFunction }
|
91
|
+
GQL
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_allow_specific_fields_with_spread
|
95
|
+
assert_result(nil, <<~GQL, dig: 'errors')
|
96
|
+
query DroidFieldInFragment { hero { name ... on Droid { primaryFunction } } }
|
97
|
+
GQL
|
98
|
+
end
|
99
|
+
end
|