Repository: strawberry-graphql/strawberry

Issue:
Raise an exception if creating a type with the same name
See https://github.com/strawberry-graphql/strawberry/pull/403/files#r463982907 for context.

Right now when creating a type we check if it is already in our type schema, if it is there we use it, but we don't check for duplicates


Discussion:
Hey @patrick91, I'd like to start contributing to Strawberry and this looks like a good first issue to tackle. Any advice on how to get started and where to look?

My understanding is a test could look like this. Let me know if this looks right to you.

```
def test_raises_exception_with_duplicate_types():
    @strawberry.type
    class Query:
        title: str
        age: int

    @strawberry.type
    class Query:
        title: str
        age: int

    with pytest.raises(
        TypeError, match="Schema contains duplicate types named 'Query'"
    ):
        strawberry.Schema(query=Query)
```

Thanks!
Hi @Kommandat! Thanks for your interest. There's a big refactor PR coming down the pipeline (#906) that's going to completely change how the internal typing system is handled. It's been a long time coming, but I'm aiming to have it done really soon. 

I'd hold off on this issue for now. There's a potential that PR ends up resolving this issue. But if not, I'd be happy to help you tackle this issue afterwards :+1: 
Thanks @BryceBeagle! I'll hold off then. Let me know if there are any other issues you know of where I can lend a hand.
#2356 has caused a regression with generic types. Subscripted types are being counted as "duplicates".
```python
T = TypeVar("T")

@strawberry.type
class A(Generic[T]):
    a: T

@strawberry.type
class Query:
    first: A[int]
    second: A[int]

strawberry.Schema(Query)  # raises TypeError... Duplicated type name: IntA
```
@coady thanks! I'll take a look :)

Resolving patch:
diff --git a/strawberry/schema/schema_converter.py b/strawberry/schema/schema_converter.py
--- a/strawberry/schema/schema_converter.py
+++ b/strawberry/schema/schema_converter.py
@@ -668,5 +668,39 @@ def is_type_of(obj: Any, _info: GraphQLResolveInfo) -> bool:
     def validate_same_type_definition(
         self, name: str, type_definition: StrawberryType, cached_type: ConcreteType
     ) -> None:
-        if cached_type.definition != type_definition:
-            raise DuplicatedTypeName(name)
+        # if the type definitions are the same we can return
+        if cached_type.definition == type_definition:
+            return
+
+        # otherwise we need to check if we are dealing with different instances
+        # of the same type generic type. This happens when using the same generic
+        # type in different places in the schema, like in the following example:
+
+        # >>> @strawberry.type
+        # >>> class A(Generic[T]):
+        # >>>     a: T
+
+        # >>> @strawberry.type
+        # >>> class Query:
+        # >>>     first: A[int]
+        # >>>     second: A[int]
+
+        # in theory we won't ever have duplicated definitions for the same generic,
+        # but we are doing the check in an exhaustive way just in case we missed
+        # something.
+
+        # we only do this check for TypeDefinitions, as they are the only ones
+        # that can be generic.
+        # of they are of the same generic type, we need to check if the type
+        # var map is the same, in that case we can return
+
+        if (
+            isinstance(type_definition, TypeDefinition)
+            and isinstance(cached_type.definition, TypeDefinition)
+            and cached_type.definition.concrete_of is not None
+            and cached_type.definition.concrete_of == type_definition.concrete_of
+        ):
+            if cached_type.definition.type_var_map == type_definition.type_var_map:
+                return
+
+        raise DuplicatedTypeName(name)


Test patch:
diff --git a/tests/schema/test_duplicated_types.py b/tests/schema/test_duplicated_types.py
--- a/tests/schema/test_duplicated_types.py
+++ b/tests/schema/test_duplicated_types.py
@@ -1,4 +1,6 @@
+import textwrap
 from enum import Enum
+from typing import Generic, TypeVar
 
 import pytest
 
@@ -108,3 +110,33 @@ class Query:
         strawberry.Schema(query=Query, types=[B])
 
     assert isinstance(exc_info.value.__cause__, DuplicatedTypeName)
+
+
+def test_allows_multiple_instance_of_same_generic():
+    T = TypeVar("T")
+
+    @strawberry.type
+    class A(Generic[T]):
+        a: T
+
+    @strawberry.type
+    class Query:
+        first: A[int]
+        second: A[int]
+
+    schema = strawberry.Schema(Query)
+
+    expected_schema = textwrap.dedent(
+        """
+        type IntA {
+          a: Int!
+        }
+
+        type Query {
+          first: IntA!
+          second: IntA!
+        }
+        """
+    ).strip()
+
+    assert str(schema) == expected_schema