Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class Name clashes with Member in generated code #54

Closed
jenschude opened this issue Jun 15, 2023 · 7 comments
Closed

Class Name clashes with Member in generated code #54

jenschude opened this issue Jun 15, 2023 · 7 comments
Labels
bug Something isn't working

Comments

@jenschude
Copy link
Contributor

Describe the bug

The generated schema stumbles across properties which have the same name as the type itself

How to Reproduce

schema {
  query: Query
}
  
type Query {
  perVariant: Limit!
}

type Limit {
  limit: Long
}

As it's not allowed to have Members with the same name as the class in CSharp: [CS0542] 'Limit': member names cannot be the same as their enclosing type

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "4.2.0.0" )]
    public class Limit
    {
        [ZeroQL.GraphQLFieldSelector("limit")]
        [JsonPropertyName("limit")]
        public long? Limit { get; set; }
    }

Expected behavior

The class or member may be pre-/suffixed to avoid these name clashes and be able to generate a compiling client

@jenschude jenschude added the bug Something isn't working label Jun 15, 2023
@byme8
Copy link
Owner

byme8 commented Jun 18, 2023

Checkout v5.0.0-preview.1
Now it will add a suffix to the class name in this case.

@jenschude
Copy link
Contributor Author

jenschude commented Jun 19, 2023

Thanks for the fast reply. It's not working completely. Generated code with the above schema produces this snippet:

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class Limit_ZeroQL
    {
        [ZeroQL.GraphQLFieldSelector("limit")]
        [JsonPropertyName("limit")]
        public long? Limit { get; set; }
    }

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class Query : global::ZeroQL.Internal.IQuery
    {
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("perVariant")]
        public Limit __PerVariant { get; set; }

        [ZeroQL.GraphQLFieldSelector("perVariant")]
        public T PerVariant<T>(Func<Limit, T> selector = default !)
        {
            return __PerVariant is null ? throw new NullReferenceException("PerVariant is null but it should not be null. Schema can be outdated.") : selector(__PerVariant);
        }
    }

The __PerVariant property references the wrong type. Maybe it makes sense to just suffix every generated type with something like Model or Type so you can easily generate the type name without looking it up or evaluating first.

@byme8
Copy link
Owner

byme8 commented Jun 19, 2023

My bad. The v5.0.0-preview.2 should definitely work.

@jenschude
Copy link
Contributor Author

jenschude commented Jun 20, 2023

Found a new edge case when referencing the type multiple times. The above schema was trying to reproduce it with minimum nesting. Rerun with our schema and still not all occurences have been replaced. An updated reproducer schema:

schema {
  query: Query
}
  
type Query {
  limits: ProjectCustomLimitsProjection!
}

type CategoryLimitsProjection {
  maxCategories: Limit!
}


type ProjectCustomLimitsProjection {
  products: ProductLimitsProjection!
  category: CategoryLimitsProjection!
}

type ProductLimitsProjection {
  pricesPerVariant: Limit!
  variants: Limit!
}

type Limit {
  limit: Long
}

The generated source:

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class CategoryLimitsProjection
    {
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("maxCategories")]
        public Limit __MaxCategories { get; set; }

        [ZeroQL.GraphQLFieldSelector("maxCategories")]
        public T MaxCategories<T>(Func<Limit, T> selector = default !)
        {
            return __MaxCategories is null ? throw new NullReferenceException("MaxCategories is null but it should not be null. Schema can be outdated.") : selector(__MaxCategories);
        }
    }

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class Limit_ReplacementType
    {
        [ZeroQL.GraphQLFieldSelector("limit")]
        [JsonPropertyName("limit")]
        public long? Limit { get; set; }
    }

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class ProductLimitsProjection
    {
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("pricesPerVariant")]
        public Limit_ReplacementType __PricesPerVariant { get; set; }

        [ZeroQL.GraphQLFieldSelector("pricesPerVariant")]
        public T PricesPerVariant<T>(Func<Limit_ReplacementType, T> selector = default !)
        {
            return __PricesPerVariant is null ? throw new NullReferenceException("PricesPerVariant is null but it should not be null. Schema can be outdated.") : selector(__PricesPerVariant);
        }

        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("variants")]
        public Limit_ReplacementType __Variants { get; set; }

        [ZeroQL.GraphQLFieldSelector("variants")]
        public T Variants<T>(Func<Limit_ReplacementType, T> selector = default !)
        {
            return __Variants is null ? throw new NullReferenceException("Variants is null but it should not be null. Schema can be outdated.") : selector(__Variants);
        }
    }

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class ProjectCustomLimitsProjection
    {
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("products")]
        public ProductLimitsProjection __Products { get; set; }

        [ZeroQL.GraphQLFieldSelector("products")]
        public T Products<T>(Func<ProductLimitsProjection, T> selector = default !)
        {
            return __Products is null ? throw new NullReferenceException("Products is null but it should not be null. Schema can be outdated.") : selector(__Products);
        }

        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("category")]
        public CategoryLimitsProjection __Category { get; set; }

        [ZeroQL.GraphQLFieldSelector("category")]
        public T Category<T>(Func<CategoryLimitsProjection, T> selector = default !)
        {
            return __Category is null ? throw new NullReferenceException("Category is null but it should not be null. Schema can be outdated.") : selector(__Category);
        }
    }

    [System.CodeDom.Compiler.GeneratedCode ( "ZeroQL" ,  "5.0.0.0" )]
    public class Query : global::ZeroQL.Internal.IQuery
    {
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("limits")]
        public ProjectCustomLimitsProjection __Limits { get; set; }

        [ZeroQL.GraphQLFieldSelector("limits")]
        public T Limits<T>(Func<ProjectCustomLimitsProjection, T> selector = default !)
        {
            return __Limits is null ? throw new NullReferenceException("Limits is null but it should not be null. Schema can be outdated.") : selector(__Limits);
        }
    }

@jenschude
Copy link
Contributor Author

Just saw that you released a new preview. Really appreciate it. Directly ran it against our schema again and found the next issue with the suffixes when such a clashing type is used in a List.

schema {
  query: Query
}
  
type Query {
  limits: ProjectCustomLimitsProjection!
  searchKeywords: [SearchKeywords!]!
}

type SearchKeywords {
  locale: Locale!
  searchKeywords: [SearchKeyword!]!
}

type SearchKeyword {
  text: String!
}

type CategoryLimitsProjection {
  maxCategories: Limit!
}


type ProjectCustomLimitsProjection {
  products: ProductLimitsProjection!
  category: CategoryLimitsProjection!
}

type ProductLimitsProjection {
  pricesPerVariant: Limit!
  variants: Limit!
}

type Limit {
  limit: Long
}

The relevant part here in the generated client code:

        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never), JsonPropertyName("searchKeywords")]
        public SearchKeywords[] __SearchKeywords { get; set; }

        [ZeroQL.GraphQLFieldSelector("searchKeywords")]
        public T[] SearchKeywords<T>(Func<SearchKeywordsZeroQL, T> selector = default !)
        {
            return __SearchKeywords is null ? throw new NullReferenceException("SearchKeywords is null but it should not be null. Schema can be outdated.") : __SearchKeywords.Select(o => o is null ? throw new NullReferenceException("SearchKeywords is null but it should not be null. Schema can be outdated.") : selector(o)).ToArray();
        }

@byme8
Copy link
Owner

byme8 commented Jun 24, 2023

Checkout v5.0.0-preview.4

@jenschude
Copy link
Contributor Author

🥳

It works now! Appreciating the effort.

Now I have to figure out what kind of interface incompatibility is in our schema.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants