diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/TypeReferences/FactoryTypeReference.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/TypeReferences/FactoryTypeReference.cs index e36b8df0c65..ce8d2d3fb78 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/TypeReferences/FactoryTypeReference.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/TypeReferences/FactoryTypeReference.cs @@ -131,5 +131,8 @@ public override bool Equals(TypeReference? other) } public override int GetHashCode() - => HashCode.Combine(base.GetHashCode(), TypeStructure, TypeDefinition); + => HashCode.Combine( + base.GetHashCode(), + SyntaxComparer.BySyntax.GetHashCode(TypeStructure), + TypeDefinition); } diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs index d81eee1765a..e4e329a69d6 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs @@ -18,6 +18,18 @@ public async Task Schema_Snapshot() .MatchSnapshotAsync(); } + [Fact] + public async Task Schema_Snapshot_Without_ConnectionName_Inference() + { + await new ServiceCollection() + .AddGraphQLServer(disableDefaultSecurity: true) + .AddIntegrationTestTypes() + .AddGlobalObjectIdentification() + .ModifyPagingOptions(o => o.InferConnectionNameFromField = false) + .BuildSchemaAsync() + .MatchSnapshotAsync(); + } + [Fact] public async Task Subscription_With_Subscribe_With_Delivers_Message_From_Stream() { diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs index 08c3e7cc4cb..9db30d1a1a5 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs @@ -60,6 +60,12 @@ public static IsSelectedNode GetIsSelectedTest([IsSelected("name")] bool isSelec public static Product GetProduct() => new Book { Id = "1", Title = "GraphQL in Action" }; + [UsePaging] + public static IEnumerable GetBooks() => []; + + [UsePaging] + public static IEnumerable GetFavoriteBooks() => []; + [UsePaging] public static IEnumerable GetInts(PagingArguments pagingArguments) { diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap index 44ae9d6fe1e..896faa449a7 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap @@ -13,6 +13,40 @@ type Query { The only product. """ product: Product! + books( + "Returns the first _n_ elements from the list." + first: Int + "Returns the elements in the list that come after the specified cursor." + after: String + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): BooksConnection + @listSize( + assumedSize: 50 + slicingArguments: ["first", "last"] + slicingArgumentDefaultValue: 10 + sizedFields: ["edges", "nodes"] + requireOneSlicingArgument: false + ) + favoriteBooks( + "Returns the first _n_ elements from the list." + first: Int + "Returns the elements in the list that come after the specified cursor." + after: String + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): FavoriteBooksConnection + @listSize( + assumedSize: 50 + slicingArguments: ["first", "last"] + slicingArgumentDefaultValue: 10 + sizedFields: ["edges", "nodes"] + requireOneSlicingArgument: false + ) ints( "Returns the first _n_ elements from the list." first: Int @@ -72,6 +106,42 @@ type Book implements Product { kind: String! } +"A connection to a list of items." +type BooksConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [BooksEdge!] + "A flattened list of the nodes." + nodes: [Book!] +} + +"An edge in a connection." +type BooksEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Book! +} + +"A connection to a list of items." +type FavoriteBooksConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [FavoriteBooksEdge!] + "A flattened list of the nodes." + nodes: [Book!] +} + +"An edge in a connection." +type FavoriteBooksEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Book! +} + "A connection to a list of items." type IntsConnection { "Information to aid in pagination." diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot_Without_ConnectionName_Inference.snap b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot_Without_ConnectionName_Inference.snap new file mode 100644 index 00000000000..d68ef66c10d --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot_Without_ConnectionName_Inference.snap @@ -0,0 +1,180 @@ +schema { + query: Query + subscription: Subscription +} + +type Query { + "Fetches an object given its ID." + node("ID of the object." id: ID!): Node + "Lookup nodes by a list of IDs." + nodes("The list of node IDs." ids: [ID!]!): [Node]! + isSelectedTest: IsSelectedNode! + """ + Gets the product. + + + **Returns:** + The only product. + """ + product: Product! + books( + "Returns the first _n_ elements from the list." + first: Int + "Returns the elements in the list that come after the specified cursor." + after: String + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): BookConnection + favoriteBooks( + "Returns the first _n_ elements from the list." + first: Int + "Returns the elements in the list that come after the specified cursor." + after: String + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): BookConnection + ints( + "Returns the first _n_ elements from the list." + first: Int + "Returns the elements in the list that come after the specified cursor." + after: String + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): IntConnection + products( + "Returns the elements in the list that come after the specified cursor." + after: Version2 + "Returns the first _n_ elements from the list." + first: Int + "Returns the last _n_ elements from the list." + last: Int + "Returns the elements in the list that come before the specified cursor." + before: String + ): ProductConnection + argumentWithExplicitType(arg: Version2): String! + nullableArgumentWithExplicitType(arg: Version2): String! + nullableArrayArgumentRef(items: [String!]): String! + arrayArgumentRef(items: [String!]!): String! + arrayNullableElementArgumentRef(items: [String]!): String! + nullableArrayNullableElementArgumentRef(items: [String]): String! + nullableListArgumentRef(items: [String!]): String! + listArgumentRef(items: [String!]!): String! + listNullableElementArgumentRef(items: [String]!): String! + nullableListNullableElementArgumentRef(items: [String]): String! + issue8057Entity(id: ID!): Issue8057Entity +} + +type Subscription { + onProductAdded(categoryId: Int!): Int! + onProductPriceChanged(productId: Int!): Int! +} + +type Book implements Product { + title: String! + id: String! + kind: String! +} + +"A connection to a list of items." +type BookConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [BookEdge!] + "A flattened list of the nodes." + nodes: [Book!] +} + +"An edge in a connection." +type BookEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Book! +} + +"A connection to a list of items." +type IntConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [IntEdge!] + "A flattened list of the nodes." + nodes: [Int!] +} + +"An edge in a connection." +type IntEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Int! +} + +type IsSelectedNode implements Node { + id: ID! + name: String! + description: String! + wasNameSelected: Boolean! +} + +type Issue8057Entity implements Node { + id: ID! +} + +"Information about pagination in a connection." +type PageInfo { + "Indicates whether more edges exist following the set defined by the clients arguments." + hasNextPage: Boolean! + "Indicates whether more edges exist prior the set defined by the clients arguments." + hasPreviousPage: Boolean! + "When paginating backwards, the cursor to continue." + startCursor: String + "When paginating forwards, the cursor to continue." + endCursor: String +} + +"A connection to a list of items." +type ProductConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [ProductEdge!] + "A flattened list of the nodes." + nodes: [Product!] +} + +"An edge in a connection." +type ProductEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Product! +} + +type Television implements Product { + argumentWithExplicitType(arg: Version!): String! + nullableArgumentWithExplicitType(arg: Version): String! + id: String! + kind: String! +} + +"The node interface is implemented by entities that have a global unique identifier." +interface Node { + id: ID! +} + +interface Product { + kind: String! + id: String! +} + +scalar Version + +scalar Version2