Skip to content

Commit

Permalink
Fix GraphQL entity names in subqueries (#299)
Browse files Browse the repository at this point in the history
* Regenerate model

* Add annotations to generated types

To make sure subqueries get generated with the correct GraphQL entity names

* Regenerate model with new attribute

* Add test and fix compilation

* Fix unit tests

---------

Co-authored-by: Keegan Campbell <[email protected]>
  • Loading branch information
jMarkP and kfcampbell committed Aug 10, 2023
1 parent 36708fa commit 63b4f6c
Show file tree
Hide file tree
Showing 100 changed files with 1,137 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class InterfaceGenerationTests : TestBase
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;
[GraphQLIdentifier(""Entity"")]
public interface IEntity : IQueryableValue<IEntity>, IQueryableInterface
{{
{0}
Expand All @@ -32,6 +33,7 @@ namespace Test.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;
[GraphQLIdentifier(""Entity"")]
internal class StubIEntity : QueryableValue<StubIEntity>, IEntity
{{
internal StubIEntity(Expression expression) : base(expression)
Expand Down
6 changes: 4 additions & 2 deletions Octokit.GraphQL.Core.Generation/EntityGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ public static string Generate(
string queryType,
string modifiers = "public ",
bool generateDocComments = true,
string entityNamespace = null)
string entityNamespace = null,
string graphQlModelType = null)
{
var className = TypeUtilities.GetClassName(type);
var pagingConnectionNodeType = GetPagingConnectionNodeType(type);
var annotations = TypeUtilities.GetGraphQlIdentifierAttribute(graphQlModelType);

return $@"namespace {rootNamespace}
{{
Expand All @@ -29,7 +31,7 @@ public static string Generate(
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;
{GenerateDocComments(type, generateDocComments)}{modifiers}class {className} : QueryableValue<{className}>{GenerateImplementedInterfaces(type, pagingConnectionNodeType)}
{GenerateDocComments(type, generateDocComments)}{annotations}{modifiers}class {className} : QueryableValue<{className}>{GenerateImplementedInterfaces(type, pagingConnectionNodeType)}
{{
internal {className}(Expression expression) : base(expression)
{{
Expand Down
5 changes: 3 additions & 2 deletions Octokit.GraphQL.Core.Generation/InterfaceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal static class InterfaceGenerator
public static string Generate(TypeModel type, string entityNamespace, string queryType)
{
var className = TypeUtilities.GetInterfaceName(type);
var annotations = TypeUtilities.GetGraphQlIdentifierAttribute(type.Name);

return $@"namespace {entityNamespace}
{{
Expand All @@ -22,7 +23,7 @@ public static string Generate(TypeModel type, string entityNamespace, string que
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;
{GenerateDocComments(type)}public interface {className} : IQueryableValue<{className}>, IQueryableInterface
{GenerateDocComments(type)}{annotations}public interface {className} : IQueryableValue<{className}>, IQueryableInterface
{{{GenerateFields(type)}
}}
}}
Expand Down Expand Up @@ -215,7 +216,7 @@ private static string GenerateStub(TypeModel type, string entityNamespace, strin
stubType.Name = "Stub" + TypeUtilities.GetInterfaceName(type);
stubType.Kind = TypeKind.Object;
stubType.Interfaces = new[] { type };
return EntityGenerator.Generate(stubType, entityNamespace + ".Internal", queryType, entityNamespace: entityNamespace, modifiers: "internal ", generateDocComments: false);
return EntityGenerator.Generate(stubType, entityNamespace + ".Internal", queryType, entityNamespace: entityNamespace, modifiers: "internal ", generateDocComments: false, graphQlModelType:type.Name);
}
}
}
10 changes: 10 additions & 0 deletions Octokit.GraphQL.Core.Generation/Utilities/TypeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ public static TypeModel ReduceType(TypeModel type)

return type;
}

public static string GetGraphQlIdentifierAttribute(string graphQlModelType)
{
if (graphQlModelType == null)
{
return "";
}

return $"[GraphQLIdentifier(\"{graphQlModelType}\")]\n ";
}

private static string GetCSharpType(TypeModel type, bool nullableType, bool returnType)
{
Expand Down
2 changes: 1 addition & 1 deletion Octokit.GraphQL.UnitTests/ExpressionRewiterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void Repository_Details_With_Viewer()
{
var query = new Query()
.Select(x => x.RepositoryOwner("foo")
.Repositories(30, null, null, null, null, null, null, null, null, null)
.Repositories(30, null, null, null, null, null, null, null, null, null, null)
.Edges
.Select(y => y.Node)
.Select(z => new
Expand Down
60 changes: 58 additions & 2 deletions Octokit.GraphQL.UnitTests/QueryBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Model;
using Xunit;

Expand Down Expand Up @@ -117,7 +120,7 @@ public void RepositoryOwner_Repositories_Query_Viewer()
var expression = new Query()
.Select(root => root
.RepositoryOwner("foo")
.Repositories(30, null, null, null, null, null, null, null, null, null)
.Repositories(30, null, null, null, null, null, null, null, null, null, null)
.Edges.Select(x => x.Node)
.Select(x => new
{
Expand Down Expand Up @@ -218,7 +221,7 @@ public void Repository_Details_With_Viewer()

var expression = new Query()
.Select(x => x.RepositoryOwner("foo")
.Repositories(30, null, null, null, null, null, null, null, null, null)
.Repositories(30, null, null, null, null, null, null, null, null, null, null)
.Edges
.Select(y => y.Node)
.Select(y => new
Expand Down Expand Up @@ -338,5 +341,58 @@ public void DateTimeOffsetVariable()

Assert.Equal(expected, query.ToString(), ignoreLineEndingDifferences: true);
}


[Fact]
public void TestAllPagesSubqueryUsesCorrectEntityName()
{
var expectedMasterQuery = @"query {
repositoryOwner(login: ""foo"") {
id
repositories(first: 100) {
pageInfo {
hasNextPage
endCursor
}
nodes {
name
}
}
}
}";

// The actual type that we map RepositoryOwner to is called StubIRepositoryOwner
// So make sure it gets serialized to the query correctly.
var expectedSubQuery = @"query($__id: ID!, $__after: String) {
node(id: $__id) {
__typename
... on RepositoryOwner {
repositories(first: 100, after: $__after) {
pageInfo {
hasNextPage
endCursor
}
nodes {
name
}
}
}
}
}";

var query = new Query()
.RepositoryOwner("foo")
.Repositories()
.AllPages(100)
.Select(x => x.Name)
.Compile();

var subQuery = (query as PagedQuery<IEnumerable<string>>).Subqueries.First();

Assert.Equal(expectedMasterQuery, query.ToString(), ignoreLineEndingDifferences: true);
Assert.Equal(expectedSubQuery, subQuery.ToString(), ignoreLineEndingDifferences: true);


}
}
}
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// Represents an object which can take actions on GitHub. Typically a User or Bot.
/// </summary>
[GraphQLIdentifier("Actor")]
public interface IActor : IQueryableValue<IActor>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -44,6 +45,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("Actor")]
internal class StubIActor : QueryableValue<StubIActor>, IActor
{
internal StubIActor(Expression expression) : base(expression)
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/AnnouncementBanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// Represents an announcement banner.
/// </summary>
[GraphQLIdentifier("AnnouncementBanner")]
public interface IAnnouncementBanner : IQueryableValue<IAnnouncementBanner>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -38,6 +39,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("AnnouncementBanner")]
internal class StubIAnnouncementBanner : QueryableValue<StubIAnnouncementBanner>, IAnnouncementBanner
{
internal StubIAnnouncementBanner(Expression expression) : base(expression)
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/Assignable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// An object that can have users assigned to it.
/// </summary>
[GraphQLIdentifier("Assignable")]
public interface IAssignable : IQueryableValue<IAssignable>, IQueryableInterface
{
/// <summary>
Expand All @@ -32,6 +33,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("Assignable")]
internal class StubIAssignable : QueryableValue<StubIAssignable>, IAssignable
{
internal StubIAssignable(Expression expression) : base(expression)
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/AuditEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// An entry in the audit log.
/// </summary>
[GraphQLIdentifier("AuditEntry")]
public interface IAuditEntry : IQueryableValue<IAuditEntry>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -88,6 +89,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("AuditEntry")]
internal class StubIAuditEntry : QueryableValue<StubIAuditEntry>, IAuditEntry
{
internal StubIAuditEntry(Expression expression) : base(expression)
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/Closable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// An object that can be closed
/// </summary>
[GraphQLIdentifier("Closable")]
public interface IClosable : IQueryableValue<IClosable>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -43,6 +44,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("Closable")]
internal class StubIClosable : QueryableValue<StubIClosable>, IClosable
{
internal StubIClosable(Expression expression) : base(expression)
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/Comment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// Represents a comment.
/// </summary>
[GraphQLIdentifier("Comment")]
public interface IComment : IQueryableValue<IComment>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -99,6 +100,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("Comment")]
internal class StubIComment : QueryableValue<StubIComment>, IComment
{
internal StubIComment(Expression expression) : base(expression)
Expand Down
2 changes: 1 addition & 1 deletion Octokit.GraphQL/Model/Commit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ internal Commit(Expression expression) : base(expression)
public Blame Blame(Arg<string> path) => this.CreateMethodCall(x => x.Blame(path), Octokit.GraphQL.Model.Blame.Create);

/// <summary>
/// We recommend using the `changedFielsIfAvailable` field instead of `changedFiles`, as `changedFiles` will cause your request to return an error if GitHub is unable to calculate the number of changed files.
/// We recommend using the `changedFilesIfAvailable` field instead of `changedFiles`, as `changedFiles` will cause your request to return an error if GitHub is unable to calculate the number of changed files.
/// </summary>
[Obsolete(@"`changedFiles` will be removed. Use `changedFilesIfAvailable` instead. Removal on 2023-01-01 UTC.")]
public int ChangedFiles { get; }
Expand Down
2 changes: 2 additions & 0 deletions Octokit.GraphQL/Model/Contribution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Octokit.GraphQL.Model
/// <summary>
/// Represents a contribution a user made on GitHub, such as opening an issue.
/// </summary>
[GraphQLIdentifier("Contribution")]
public interface IContribution : IQueryableValue<IContribution>, IQueryableInterface
{
/// <summary>
Expand Down Expand Up @@ -50,6 +51,7 @@ namespace Octokit.GraphQL.Model.Internal
using Octokit.GraphQL.Core;
using Octokit.GraphQL.Core.Builders;

[GraphQLIdentifier("Contribution")]
internal class StubIContribution : QueryableValue<StubIContribution>, IContribution
{
internal StubIContribution(Expression expression) : base(expression)
Expand Down
9 changes: 2 additions & 7 deletions Octokit.GraphQL/Model/CreateRepositoryRulesetInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,9 @@ public class CreateRepositoryRulesetInput
public RuleEnforcement Enforcement { get; set; }

/// <summary>
/// The bypass mode for this ruleset
/// A list of actors that are allowed to bypass rules in this ruleset.
/// </summary>
public RuleBypassMode? BypassMode { get; set; }

/// <summary>
/// A list of Team or App IDs allowed to bypass rules in this ruleset.
/// </summary>
public IEnumerable<ID> BypassActorIds { get; set; }
public IEnumerable<RepositoryRulesetBypassActorInput> BypassActors { get; set; }

/// <summary>
/// A unique identifier for the client performing the mutation.
Expand Down
12 changes: 9 additions & 3 deletions Octokit.GraphQL/Model/CreateTeamDiscussionCommentInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ namespace Octokit.GraphQL.Model
public class CreateTeamDiscussionCommentInput
{
/// <summary>
/// The ID of the discussion to which the comment belongs.
/// The ID of the discussion to which the comment belongs. This field is required.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `discussionId` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public ID DiscussionId { get; set; }
public ID? DiscussionId { get; set; }

/// <summary>
/// The content of the comment.
/// The content of the comment. This field is required.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `body` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public string Body { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ internal CreateTeamDiscussionCommentPayload(Expression expression) : base(expres
/// <summary>
/// The new comment.
/// </summary>
[Obsolete(@"The Team Discussions feature is deprecated in favor of Organization Discussions. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement. Removal on 2024-07-01 UTC.")]
public TeamDiscussionComment TeamDiscussionComment => this.CreateProperty(x => x.TeamDiscussionComment, Octokit.GraphQL.Model.TeamDiscussionComment.Create);

internal static CreateTeamDiscussionCommentPayload Create(Expression expression)
Expand Down
20 changes: 16 additions & 4 deletions Octokit.GraphQL/Model/CreateTeamDiscussionInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,34 @@ namespace Octokit.GraphQL.Model
public class CreateTeamDiscussionInput
{
/// <summary>
/// The ID of the team to which the discussion belongs.
/// The ID of the team to which the discussion belongs. This field is required.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `teamId` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public ID TeamId { get; set; }
public ID? TeamId { get; set; }

/// <summary>
/// The title of the discussion.
/// The title of the discussion. This field is required.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `title` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public string Title { get; set; }

/// <summary>
/// The content of the discussion.
/// The content of the discussion. This field is required.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `body` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public string Body { get; set; }

/// <summary>
/// If true, restricts the visibility of this discussion to team members and organization admins. If false or not specified, allows any organization member to view this discussion.
/// **Upcoming Change on 2024-07-01 UTC**
/// **Description:** `private` will be removed. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement.
/// **Reason:** The Team Discussions feature is deprecated in favor of Organization Discussions.
/// </summary>
public bool? Private { get; set; }

Expand Down
1 change: 1 addition & 0 deletions Octokit.GraphQL/Model/CreateTeamDiscussionPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ internal CreateTeamDiscussionPayload(Expression expression) : base(expression)
/// <summary>
/// The new discussion.
/// </summary>
[Obsolete(@"The Team Discussions feature is deprecated in favor of Organization Discussions. Follow the guide at https://github.blog/changelog/2023-02-08-sunset-notice-team-discussions/ to find a suitable replacement. Removal on 2024-07-01 UTC.")]
public TeamDiscussion TeamDiscussion => this.CreateProperty(x => x.TeamDiscussion, Octokit.GraphQL.Model.TeamDiscussion.Create);

internal static CreateTeamDiscussionPayload Create(Expression expression)
Expand Down
Loading

0 comments on commit 63b4f6c

Please sign in to comment.