public TypeDescriptorModel( OutputTypeModel typeModel, NamedTypeDescriptor namedTypeDescriptor) { TypeModel = typeModel; NamedTypeDescriptor = namedTypeDescriptor; }
private static void RegisterType( ClientModel model, IMapperContext context, Dictionary <NameString, TypeDescriptorModel> typeDescriptors, OutputTypeModel outputType, List <UnionType> unionTypes, TypeKind?kind = null, OperationModel?operationModel = null) { if (typeDescriptors.TryGetValue( outputType.Name, out TypeDescriptorModel descriptorModel)) { return; } if (operationModel is not null && outputType.IsInterface) { descriptorModel = CreateInterfaceTypeModel( model, context, typeDescriptors, outputType, unionTypes, descriptorModel, operationModel, kind); }
public OutputTypeModel AnalyzeOperation( IDocumentAnalyzerContext context, SelectionSetVariants selectionSetVariants) { Path rootSelectionPath = Path.Root.Append(context.OperationName); FragmentNode returnTypeFragment = FragmentHelper.CreateFragmentNode( context.OperationType, rootSelectionPath, selectionSetVariants.ReturnType); returnTypeFragment = FragmentHelper.RewriteForConcreteType(returnTypeFragment); OutputTypeModel returnType = FragmentHelper.CreateInterface( context, returnTypeFragment, rootSelectionPath); FragmentHelper.CreateClass( context, returnTypeFragment, selectionSetVariants.ReturnType, returnType); return(returnType); }
public async Task One_Document_One_Op_One_Field_No_Fragments() { // arrange var schema = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWars() .BuildSchemaAsync(); schema = SchemaHelper.Load( ("", schema.ToDocument()), ("", Utf8GraphQLParser.Parse( @"extend scalar String @runtimeType(name: ""Abc"")"))); var document = Utf8GraphQLParser.Parse(@" query GetHero { hero(episode: NEW_HOPE) { name } }"); // act ClientModel clientModel = DocumentAnalyzer .New() .SetSchema(schema) .AddDocument(document) .Analyze(); // assert Assert.Empty( clientModel.InputObjectTypes); Assert.Collection( clientModel.LeafTypes, type => { Assert.Equal("String", type.Name); Assert.Equal("Abc", type.RuntimeType); }); Assert.Collection( clientModel.Operations, op => { Assert.Equal("IGetHero", op.ResultType.Name); Assert.Collection( op.GetImplementations(op.ResultType), model => Assert.Equal("GetHero", model.Name)); OutputTypeModel fieldResultType = op.GetFieldResultType(op.ResultType.Fields.Single().SyntaxNode); Assert.Equal("IGetHero_Hero", fieldResultType.Name); }); }
private OutputTypeModel AnalyzeWithDefaults( IDocumentAnalyzerContext context, FieldSelection fieldSelection, SelectionSetVariants selectionVariants) { FragmentNode returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionVariants.ReturnType, fieldSelection.Path); OutputTypeModel returnType = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path); context.RegisterSelectionSet( returnType.Type, selectionVariants.ReturnType.SyntaxNode, returnType.SelectionSet); foreach (SelectionSet selectionSet in selectionVariants.Variants) { returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSet, fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.RewriteForConcreteType(returnTypeFragment); OutputTypeModel @interface = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path, new[] { returnType }); OutputTypeModel @class = FragmentHelper.CreateClass( context, returnTypeFragment, selectionSet, @interface); context.RegisterSelectionSet( selectionSet.Type, selectionSet.SyntaxNode, @class.SelectionSet); } return(returnType); }
private static void CollectClassesThatImplementInterface( OperationModel operation, OutputTypeModel outputType, Dictionary <NameString, TypeDescriptorModel> typeDescriptors, HashSet <NamedTypeDescriptor> classes) { foreach (var type in operation.GetImplementations(outputType)) { if (type.IsInterface) { CollectClassesThatImplementInterface( operation, type, typeDescriptors, classes); } else { classes.Add(typeDescriptors[type.Name].NamedTypeDescriptor); } } }
public async Task Create_TypeModels_Infer_From_Fragments_With_HoistedFragment() { // arrange var schema = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWars() .BuildSchemaAsync(); var document = Utf8GraphQLParser.Parse(@" query GetHero { hero(episode: NEW_HOPE) @returns(fragment: ""Hero"") { ... Characters } } fragment Characters on Character { ... Human ... Droid } fragment Hero on Character { name } fragment Human on Human { ... Hero homePlanet } fragment Droid on Droid { ... Hero primaryFunction }"); var context = new DocumentAnalyzerContext(schema, document); var selectionSetVariants = context.CollectFields(); var fieldSelection = selectionSetVariants.ReturnType.Fields.First(); selectionSetVariants = context.CollectFields(fieldSelection); // act var list = new List <OutputTypeModel>(); var returnTypeFragmentName = FragmentHelper.GetReturnTypeName(fieldSelection); var returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSetVariants.Variants[0], fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.GetFragment( returnTypeFragment, returnTypeFragmentName !); list.Add(FragmentHelper.CreateInterface( context, returnTypeFragment !, fieldSelection.Path)); foreach (SelectionSet selectionSet in selectionSetVariants.Variants.OrderBy(t => t.Type.Name.Value)) { returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSet, fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.RewriteForConcreteType(returnTypeFragment); OutputTypeModel @interface = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path, new [] { list[0] }); OutputTypeModel @class = FragmentHelper.CreateClass( context, returnTypeFragment, selectionSet, @interface); list.Add(@interface); list.Add(@class); } // assert Assert.Collection( list, type => { Assert.Equal("IHero", type.Name); Assert.Empty(type.Implements); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name)); }, type => { Assert.Equal("IGetHero_Hero_Droid", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("ICharacters_Droid", impl.Name)); Assert.Empty(type.Fields); }, type => { Assert.Equal("GetHero_Hero_Droid", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero_Droid", impl.Name)); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name), field => Assert.Equal("PrimaryFunction", field.Name)); }, type => { Assert.Equal("IGetHero_Hero_Human", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("ICharacters_Human", impl.Name)); Assert.Empty(type.Fields); }, type => { Assert.Equal("GetHero_Hero_Human", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero_Human", impl.Name)); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name), field => Assert.Equal("HomePlanet", field.Name)); }); }
public async Task Create_TypeModels_Infer_TypeStructure() { // arrange var schema = await new ServiceCollection() .AddStarWarsRepositories() .AddGraphQL() .AddStarWars() .BuildSchemaAsync(); var document = Utf8GraphQLParser.Parse(@" query GetHero { hero(episode: NEW_HOPE) { name } }"); var context = new DocumentAnalyzerContext(schema, document); var selectionSetVariants = context.CollectFields(); var fieldSelection = selectionSetVariants.ReturnType.Fields.First(); selectionSetVariants = context.CollectFields(fieldSelection); // act var list = new List <OutputTypeModel>(); var returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSetVariants.ReturnType, fieldSelection.Path); list.Add(FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path)); foreach (SelectionSet selectionSet in selectionSetVariants.Variants.OrderBy(t => t.Type.Name.Value)) { returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSet, fieldSelection.Path, appendTypeName: true); OutputTypeModel @interface = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path, new [] { list[0] }); OutputTypeModel @class = FragmentHelper.CreateClass( context, returnTypeFragment, selectionSet, @interface); list.Add(@interface); list.Add(@class); } // assert Assert.Collection( list, type => { Assert.Equal("IGetHero_Hero", type.Name); Assert.Empty(type.Implements); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name)); }, type => { Assert.Equal("IGetHero_Hero_Droid", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero", impl.Name)); Assert.Empty(type.Fields); }, type => { Assert.Equal("GetHero_Hero_Droid", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero_Droid", impl.Name)); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name)); }, type => { Assert.Equal("IGetHero_Hero_Human", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero", impl.Name)); Assert.Empty(type.Fields); }, type => { Assert.Equal("GetHero_Hero_Human", type.Name); Assert.Collection( type.Implements, impl => Assert.Equal("IGetHero_Hero_Human", impl.Name)); Assert.Collection( type.Fields, field => Assert.Equal("Name", field.Name)); }); }
private static void RegisterType( ClientModel model, IMapperContext context, Dictionary <NameString, TypeDescriptorModel> typeDescriptors, OutputTypeModel outputType, List <UnionType> unionTypes, TypeKind?kind = null, OperationModel?operationModel = null) { if (!typeDescriptors.TryGetValue( outputType.Name, out TypeDescriptorModel descriptorModel)) { IReadOnlyList <NamedTypeDescriptor> implementedBy = Array.Empty <NamedTypeDescriptor>(); if (operationModel is not null && outputType.IsInterface) { var classes = new HashSet <NamedTypeDescriptor>(); CollectClassesThatImplementInterface( operationModel, outputType, typeDescriptors, classes); implementedBy = classes.ToList(); } TypeKind fallbackKind; string? complexDataTypeParent = null; if (outputType.Type.IsEntity()) { fallbackKind = TypeKind.EntityType; } else { if (outputType.Type.IsAbstractType()) { fallbackKind = TypeKind.ComplexDataType; complexDataTypeParent = outputType.Type.Name; } else { OutputTypeModel?mostAbstractTypeModel = outputType; while (mostAbstractTypeModel.Implements.Count > 0) { mostAbstractTypeModel = mostAbstractTypeModel.Implements[0]; } complexDataTypeParent = mostAbstractTypeModel.Type.Name; if (complexDataTypeParent == outputType.Type.Name) { fallbackKind = TypeKind.DataType; } else { fallbackKind = TypeKind.ComplexDataType; } } } var finalKind = kind ?? fallbackKind; descriptorModel = new TypeDescriptorModel( outputType, new NamedTypeDescriptor( finalKind == TypeKind.ResultType ? NamingConventions.ResultRootTypeNameFromTypeName(outputType.Name) : outputType.Name, context.Namespace, outputType.IsInterface, outputType.Implements.Select( t => finalKind == TypeKind.ResultType ? (NameString)NamingConventions.ResultRootTypeNameFromTypeName( t.Name) : t.Name).ToList(), kind: finalKind, graphQLTypeName: outputType.Type.Name, implementedBy: implementedBy, complexDataTypeParent: complexDataTypeParent)); typeDescriptors.Add( outputType.Name, descriptorModel); } }
private OutputTypeModel AnalyzeWithHoistedFragment( IDocumentAnalyzerContext context, FieldSelection fieldSelection, SelectionSetVariants selectionVariants, string fragmentName) { FragmentNode?returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionVariants.Variants[0], fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.GetFragment(returnTypeFragment, fragmentName); if (returnTypeFragment is null) { // TODO : throw helper throw new GraphQLException( "The specified return fragment does not exist."); } OutputTypeModel returnType = FragmentHelper.CreateInterface(context, returnTypeFragment, fieldSelection.Path); context.RegisterSelectionSet( returnType.Type, selectionVariants.ReturnType.SyntaxNode, returnType.SelectionSet); foreach (SelectionSet selectionSet in selectionVariants.Variants) { returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSet, fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.RewriteForConcreteType(returnTypeFragment); if (FragmentHelper.GetFragment(returnTypeFragment, fragmentName) is null) { // TODO : throw helper throw new GraphQLException( "The specified return fragment must be implement by all type fragments."); } OutputTypeModel @interface = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path, new[] { returnType }); OutputTypeModel @class = FragmentHelper.CreateClass( context, returnTypeFragment, selectionSet, @interface); context.RegisterSelectionSet( selectionSet.Type, selectionSet.SyntaxNode, @class.SelectionSet); } return(returnType); }
private OutputTypeModel AnalyzeWithHoistedFragment( IDocumentAnalyzerContext context, FieldSelection fieldSelection, SelectionSetVariants selectionVariants, string fragmentName) { FragmentNode?returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionVariants.Variants[0], fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.GetFragment(returnTypeFragment, fragmentName); if (returnTypeFragment is null) { throw ThrowHelper.ReturnFragmentDoesNotExist(); } OutputTypeModel returnType = FragmentHelper.CreateInterface(context, returnTypeFragment, fieldSelection.Path); context.RegisterSelectionSet( returnType.Type, selectionVariants.ReturnType.SyntaxNode, returnType.SelectionSet); foreach (SelectionSet selectionSet in selectionVariants.Variants) { returnTypeFragment = FragmentHelper.CreateFragmentNode( selectionSet, fieldSelection.Path, appendTypeName: true); returnTypeFragment = FragmentHelper.RewriteForConcreteType(returnTypeFragment); if (FragmentHelper.GetFragment(returnTypeFragment, fragmentName) is null) { throw ThrowHelper.FragmentMustBeImplementedByAllTypeFragments(); } OutputTypeModel @interface = FragmentHelper.CreateInterface( context, returnTypeFragment, fieldSelection.Path, new[] { returnType }); OutputTypeModel @class = FragmentHelper.CreateClass( context, returnTypeFragment, selectionSet, @interface); context.RegisterSelectionSet( selectionSet.Type, selectionSet.SyntaxNode, @class.SelectionSet); } return(returnType); }