Giter Club home page Giter Club logo

octokit.graphql.net's Introduction

Octokit.GraphQL

Build status codecov NuGet

Note: This software is currently beta. There are few things left, and there might be bugs - be warned!

Octokit.GraphQL gives you access to the GitHub GraphQL API from .NET. It exposes the GitHub GraphQL API as a strongly-typed LINQ-like API, aiming to follow the GraphQL query syntax as closely as possible, which giving the benefits of strong typing in your favorite .NET language.

Documentation

You can find our documentation here.

Installing from Nuget

Install-Package Octokit.GraphQL -IncludePrerelease

Usage Example

using Octokit.GraphQL;
using static Octokit.GraphQL.Variable;

var productInformation = new ProductHeaderValue("YOUR_PRODUCT_NAME", "YOUR_PRODUCT_VERSION");
var connection = new Connection(productInformation, YOUR_OAUTH_TOKEN);

var query = new Query()
    .RepositoryOwner(Var("owner"))
    .Repository(Var("name"))
    .Select(repo => new
    {
        repo.Id,
        repo.Name,
        repo.Owner.Login,
        repo.IsFork,
        repo.IsPrivate,
    }).Compile();

var vars = new Dictionary<string, object>
{
    { "owner", "octokit" },
    { "name", "octokit.graphql.net" },
};

var result =  await connection.Run(query, vars);

Console.WriteLine(result.Login + " & " + result.Name + " Rocks!");
using Octokit.GraphQL;
using Octokit.GraphQL.Model;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Octokit
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var productInformation = new ProductHeaderValue("ExampleCode", "1.0");

            // Personal Access Token - needs a scope of 'read:user'
            var connection = new Connection(productInformation, "LOGGED_IN_GITHUB_USER_TOKEN");

            // A query to list out who you are actively sponsoring
            // That auto pages through all sponsors
            var query = new Query()
                .Viewer
                .SponsorshipsAsSponsor()
                .AllPages()
                .Select(sponsoring => new
                {
                    User = sponsoring.Sponsorable
                            .Cast<User>()
                            .Select(x => new {
                                x.Login,
                                x.Name,
                                x.Id
                            })
                            .Single()
                })
                .Compile();

            var result = await connection.Run(query);

            // Sponsoring 'warrenbuckley' ?
            var activeSponsor = result.SingleOrDefault(x => x.User.Login.ToLowerInvariant() == "warrenbuckley");
            if(activeSponsor != null)
            {
                Console.WriteLine("Thanks for sponsoring Warren");
            }
        }
    }
}

octokit.graphql.net's People

Contributors

0x5bfa avatar 0xced avatar brphelps avatar dependabot[bot] avatar gimenete avatar gr2m avatar grokys avatar grvillic avatar jcansdale avatar jmarkp avatar joeltankam avatar jongio avatar kfcampbell avatar lordjz avatar martincostello avatar michaeldenwood avatar nickfloyd avatar nul800sebastiaan avatar octokitbot avatar stanleygoldman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

octokit.graphql.net's Issues

Cannot access child value on Newtonsoft.Json.Linq.JValue

The following fails with an exception:

var query = new Query().Repository("jcansdale", "TestDriven.Net-Issues").Issues(first: 60).Nodes.Select(
   i => new { i.Title, i.State, Milestone = i.Milestone.Title}).Where(i => i.Note != null);
	System.InvalidOperationException: Cannot access child value on Newtonsoft.Json.Linq.JValue.
	at Newtonsoft.Json.Linq.JToken.get_Item(Object key)
	at lambda_method(Closure , JToken )
	at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
	at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()

But this works:

var query = new Query().Repository("jcansdale", "TestDriven.Net-Issues").Issues(first: 60).Nodes.Select(
  i => new { i.Title, i.State, Milestone = i.Milestone.Select(m => m.Title)}).Where(i => i.Note != null);

Support GitHub Apps

I am using GitHub Apps instead of OAuth for my application.

I get a UnAuthorized exception when I try it.

It doesn't seem like OAuth apps on GitHub have webhooks like GitHub apps do (which I need to update my own database to keep up to date with GitHubs) so I don't think I can switch to OAuth unless someone wants to tell me you can use webhooks with OAuth?

var productInformation = new ProductHeaderValue(Env.GetString("APP_NAME"));
var path = $"{_env.WebRootPath}/{Env.GetString("APP_NAME")}.pem";
var appIntegrationId = Env.GetInt("GITHUB_APP_ID");
var generator = new GitHubJwt.GitHubJwtFactory(
    new GitHubJwt.FilePrivateKeySource(path),
    new GitHubJwt.GitHubJwtFactoryOptions
    {
        AppIntegrationId = appIntegrationId,
        ExpirationSeconds = 600
    });

var jwtToken = generator.CreateEncodedJwtToken();
var connection = new Connection(productInformation, jwtToken);

var query = new Query()
    .RepositoryOwner(Var("owner"))
    .Repository(Var("name"))
    .Compile();

var vars = new Dictionary<string, object>
{
    { "owner", "octokit" },
    { "name", "octokit.graphql.net" },
};

var result = await connection.Run(query, vars);

Parse error on "." (error)

Hey,

I just got flowing exception with this:

            var openState = new IssueState?[] { IssueState.Open }.AsQueryable();
            var query = new Query().Repository("jcansdale", "TestDriven.Net-Issues").Issues(first: 30, states: openState).Nodes.Select(i => i.Title);
            var result = await connection.Run(query);
	Octokit.GraphQL.Core.GraphQLQueryException: Parse error on "." (error) at [1, 86]
	at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](GraphQLQuery`1 query, JObject data)
	at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](GraphQLQuery`1 query, String data)
	at Octokit.GraphQL.Core.Connection.<Run>d__6`1.MoveNext()

Octokit.GraphQL 0.1 ๐Ÿ˜‰

Move entities to a separate namespace.

Because entities are rarely interacted with by name in queries, move them to a separate namespace so that Octokit.GraphQL contains only the top level objects such as Connection and Query. This should help guide users into the pit of success.

Sample does not rock

I installed into a console project using NuGet. I created an OAuth token as in Forming Calls with GraphQL and Creating a personal access token for the command line. The following is my code.

using Octokit.GraphQL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Octokit.GraphQL.Variable;

namespace ConsoleGitHubGraphQL
{
    class Program
    {
        static void Main(string[] args)
        {
            AsyncMethodAsync();
        }

        static async void AsyncMethodAsync()
        {
            // The product name is either the product, the GitHub
            // Organization, or the GitHub username.
            var productInformation = new ProductHeaderValue("SimpleSamples" /*, "YOUR_PRODUCT_VERSION"*/);
            var connection = new Connection(productInformation, "myOAuthtoken");

            var query = new Query()
                .RepositoryOwner(Var("owner"))
                .Repository(Var("name"))
                .Select(repo => new
                {
                    repo.Id,
                    repo.Name,
                    repo.Owner.Login,
                    repo.IsFork,
                    repo.IsPrivate,
                }).Compile();

            var vars = new Dictionary<string, object>
                {
                    { "owner", "SimpleSamples" },
                    { "name", "SimpleSamples.Repos" },
                };

            try
            {
                var result = await connection.Run(query, vars);
                Console.WriteLine(result.Login + " & " + result.Name + " Rocks!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
            }

        }
    }
}

It works up to the call to connection.Run, then quits. It just ends. When I single-step using the debugger it still ends at that line, no diagnostic information or anything.

I apologize if this is a C# problem or a problem resulting from me not reading the documentation well enough. Is it? Or should it at least give me an exception?

Support automatically getting rate limit information during a query

When I was doing GitHub GraphQL queries manually, I would almost always write them like this:

query {
  rateLimit {
    cost
    remaining
    resetAt
  }
  // The rest of my query ...
}

That way, I could load the rate limit information directly without having to make separate queries to get it. Plus, every query would include the cost so that I could track that in my application. As far as I can tell, this is not possible in Octokit.GraphQL.Net. I think it would be a very valuable addition.

Ideally, I'd be able to add some configuration option in my query to indicate I want rate limit data (a boolean constructor arg on Query or an extension method of some kind) and the return value of the query would be augmented to be something like QueryResult<T> which exposes T as a property, as well as the rate limit data:

var query = new Query()
    .WithRateLimit(/* options like which rate limit fields to include */)
    .Repository(...)
    // The rest of my query...

var results = await _connection.Run(query);
Console.WriteLine($"Rate Limit cost: {results.RateLimit.Cost}");
Console.WriteLine($"Results: {results.Data}"); // <-- The actual data returned by the query

As far as I can tell, without a feature like this, it's not really possible to get the "cost" of a GraphQL query, since that field only really works when attached to a query. I can only make separate queries for my remaining rate limit and the reset time.

Support casts to enums in `Select` statements.

If a select has a cast to an enum in it, currently an exception gets thrown, e.g.:

var expression = new TestQuery()
    .Simple("foo")
    .Select(x => new
    {
        Float = (DayOfWeek)x.Number
    });

throws

System.InvalidOperationException: No coercion operator is defined between types 'Newtonsoft.Json.Linq.JToken' and 'System.DayOfWeek'.

How to express arguments?

We're currently passing arguments using standard C# parameters, but this has a couple of problems:

  1. Since #166, the arguments are now sorted by name. This means if an argument is added to the schema, it could show up in the middle of existing arguments breaking our API.
  2. In theory we can use named arguments (which would also solve 1) but in reality we often can't because C# expressions don't support named arguments, leading to some horrible null, null, null, null business. And because of this, adding an argument to the schema is a breaking change.

@StanleyGoldman suggested doing something like this instead:

Repository(x => x.Owner("Owner").Name("Name"))

Pros:

  1. Additions to schema no longer break our API
  2. Will no longer see null, null, null, null in expressions

Cons:

  1. Will need to generate a lot more code
  2. Moves us further away from looking like "just C#" code

I was originally against this idea because of the cons above, but I'm starting to think the pros outweigh the cons, especially given that it looks like C#'s expression support isn't going to be improved anytime soon (despite some proposals).

Tests fail due to line ending differences.

We need to ignore line ending differences when comparing test result strings. Currently on Windows e.g. QueryBuilderTests.Field_Aliases fails because the test was written on I assume a Mac (am I right @StanleyGoldman?) and the expected strings therefore have \n line endings whereas the serialized string has \r\n line endings.

Auto-paging doesn't work in mutations.

Trying to use auto-paging in the select part of a mutation fails:

var mutation = new Mutation()
                .AddPullRequestReview(addReview)
                .Select(review => new PullRequestReviewModel
                {
                    Id = review.PullRequestReview.Id.Value,
                    Body = body,
                    CommitId = review.PullRequestReview.Commit.Oid,
                    Comments = review.PullRequestReview.Comments(100, null, null, null).AllPages().Select(comment => new CommentAdapter
                    {
                        Id = comment.Id.Value,
                        Author = new ActorModel
                        {
                            Login = comment.Author.Login,
                            AvatarUrl = comment.Author.AvatarUrl(null),
                        },
                        Body = comment.Body,
                        CommitSha = comment.Commit.Oid,
                        CreatedAt = comment.CreatedAt,
                        DiffHunk = comment.DiffHunk,
                        OriginalCommitId = comment.OriginalCommit.Oid,
                        OriginalPosition = comment.OriginalPosition,
                        Path = comment.Path,
                        Position = comment.Position,
                        ReplyTo = comment.ReplyTo.Id.Value,
                    }).ToList(),
                    State = (GitHub.Models.PullRequestReviewState)review.PullRequestReview.State,
                    Author = new ActorModel
                    {
                        Login = review.PullRequestReview.Author.Login,
                        AvatarUrl = review.PullRequestReview.Author.AvatarUrl(null),
                    },
                });
System.InvalidOperationException occurred
  HResult=-2146233079
  Message=No method 'Node' exists on type 'Octokit.GraphQL.Mutation'.
  Source=System.Core
  StackTrace:
       at System.Linq.Expressions.Expression.FindMethod(Type type, String methodName, Type[] typeArgs, Expression[] args, BindingFlags flags)
       at System.Linq.Expressions.Expression.Call(Expression instance, String methodName, Type[] typeArguments, Expression[] arguments)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.CreateNodeQuery(MethodCallExpression expression, MethodCallExpression selector)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.AddSubquery(MethodCallExpression expression, MethodCallExpression selector, Expression pageInfoSelector)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.RewriteListExtension(MethodCallExpression expression)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node)
       at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.RewriteListExtension(MethodCallExpression expression)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node)
       at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.BookmarkAndVisit(Expression left)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMemberAssignment(MemberAssignment node)
       at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
       at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
       at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
       at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitLambda[T](Expression`1 node)
       at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.RewriteValueExtension(MethodCallExpression expression)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node)
       at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at Octokit.GraphQL.Core.Builders.QueryBuilder.Build[TResult](IQueryableValue`1 query)
       at Octokit.GraphQL.QueryableValueExtensions.Compile[T](IQueryableValue`1 expression)
       at Octokit.GraphQL.ConnectionExtensions.Run[T](IConnection connection, IQueryableValue`1 expression)
       at GitHub.InlineReviews.Services.PullRequestSessionService.<PostStandaloneReviewComment>d__33.MoveNext() in D:\projects\VisualStudio\src\GitHub.InlineReviews\Services\PullRequestSessionService.cs:line 728
  InnerException: 

Add support for variables.

Currently each time one wants to send a query with a different value, the query expression needs to be re-parsed. It would be good to capture closures and use Variables to send these values.

Consider outlawing Where in queries.

GraphQL can only filter on certain criteria, defined by the schema. When a user writes a Where clause they may well expect that filter to be executed by the server, where in reality it cannot be. Consider outlawing Where in queries and requiring that they be executed on the serialized result using Linq-to-Objects.

[Question] use as a generic client

Hello there.

I really like the way this project is going.
Will it be possible to use this client for any schema / endpoint or will it be just dedicated to github?

AllPages combined with multiple members may generate invalid queries

var compiledQuery = new Query()
    .Repository("foo", "bar")
    .Select(repository => new
    {
        Something = repository
            .Issues(null, null, null, null, null)
            .AllPages()
            .Select(issue => issue.Number)
            .ToList()
    }).Compile();

Should generate

query {
  repository(owner: ""foo"", name: ""bar"") {
    id
    something: issues(first: 100) {
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        number
      }
    }
  }
}

It is actually generating:

query {
  repository(owner: ""foo"", name: ""bar"") {
    id
    issues(first: 100) {
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        number
      }
    }
  }
}

Make Queryable*.ToString() return GraphQL query

When learning the framework it would be handy to have an easy way to show the compiled GraphQL query for a particular expression.

At the moment:

var query = new Query()
    .Repository("github", "VisualStudio")
    .PullRequests(first: 10, states: new[] { PullRequestState.Open })
    .Nodes
    .Select(x => x.Title);

Console.WriteLine(query);

Outputs:

Octokit.GraphQL.Core.QueryableList`1[System.String]

It would be nice if this would output:

query {
  repository(owner: "github", name: "VisualStudio") {
    pullRequests(first: 10, states: [OPEN]) {
      nodes {
        title
      }
    }
  }
}

Viewer_By_GraphyQL_Matches_Api fails due to localization.

Running the Viewer_By_GraphyQL_Matches_Api integration test on my machine results in:

Xunit.Sdk.EqualException: Assert.Equal() Failure
Expected: 2016-05-04T23:20:55.0000000+00:00
Actual:   2016-04-06T01:20:55.0000000+02:00
   at Xunit.Assert.Equal[T](T expected, T actual, IEqualityComparer`1 comparer)
   at Xunit.Assert.Equal[T](T expected, T actual)
   at Octokit.GraphQL.IntegrationTests.Queries.ViewerTests.Viewer_By_GraphyQL_Matches_Api() in D:\projects\LinqToGraphQL\Octokit.GraphQL.IntegrationTests\Queries\ViewerTests.cs:line 57

I assume due to localization issues.

What is the best way to use this with my own Github App?

I want to access github data which this repository will let me do but I also want to store my own custom variables in a database with the data.

Is it best to fill out my own database with the queries returned by this GraphQL endpoint in the setup callback from Github APPs and then update my database in the webhooks (what I am doing at the moment with the REST API of Octokit).

Or is it better to query what I need dynamically?

What's the difference in using this library instead of my frontend just querying the GraphQL API v4 directly?

Also what's the benefit of using this over the Github Rest API, is it just that you can fetch what you want and reduce requests?

Thanks.

Support non-constant field arguments.

The following query in Octokit.Core.UnitTests:

var expression = new TestQuery()
	.QueryItems
	.Select(x => new
	{
		x.Id,
		Items = x.NestedItems.Select(i => i.Name).ToList(),
	});

fails with

System.NotSupportedException: Non-constant field arguments not yet supported.

Can't new up arrays in Select

For example, the following:

.Nodes.Select(r => string.Join(";", new string[] { r.Owner.Login, r.Name }))

Blows up with:

	System.InvalidOperationException: An expression of type 'Newtonsoft.Json.Linq.JToken' cannot be used to initialize an array of type 'System.String'
	at System.Linq.Expressions.Expression.NewArrayInit(Type type, IEnumerable`1 initializers)
	at System.Linq.Expressions.NewArrayExpression.Update(IEnumerable`1 expressions)
	at System.Linq.Expressions.ExpressionVisitor.VisitNewArray(NewArrayExpression node)
	at System.Linq.Expressions.NewArrayExpression.Accept(ExpressionVisitor visitor)
	at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
	at Octokit.GraphQL.Core.Builders.QueryBuilder.<VisitMethodArguments>d__15.MoveNext()

"Must be reducible node" exception with AllPages().

The following query:

new Query()
    .Viewer
    .Select(viewer => new ViewerRepositoriesModel
    {
        Repositories = viewer.Repositories(null, null, null, null, null, order, null, null, null)
            .AllPages()
            .Select(repo => new RepositoryListItemModel
            {
                IsFork = repo.IsFork,
                IsPrivate = repo.IsPrivate,
                Name = repo.Name,
                Owner = repo.Owner.Login,
                Url = new Uri(repo.Url),
            }).ToList(),
        OrganizationRepositories = viewer.Organizations(null, null, null, null).AllPages().Select(org => new
        {
            org.Login,
            Repositories = org.Repositories(null, null, null, null, null, order, null, null, null)
                .AllPages()
                .Select(repo => new RepositoryListItemModel
                {
                    IsFork = repo.IsFork,
                    IsPrivate = repo.IsPrivate,
                    Name = repo.Name,
                    Owner = repo.Owner.Login,
                    Url = new Uri(repo.Url),
                }).ToList()
        }).ToDictionary(x => x.Login, x => (IReadOnlyList<RepositoryListItemModel>)x.Repositories),
    }).Compile();

Throws an exception:

System.ArgumentException
  HResult=0x80070057
  Message=must be reducible node
  Source=System.Core
  StackTrace:
   at System.Linq.Expressions.Expression.ReduceAndCheck()
   at System.Linq.Expressions.Expression.ReduceExtensions()
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExtensionExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression node)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteUnaryExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.MemberAssignmentRewriter..ctor(MemberAssignment binding, StackSpiller spiller, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.BindingRewriter.Create(MemberBinding binding, StackSpiller spiller, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteMemberInitExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
   at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression node)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
   at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
   at System.Linq.Expressions.Expression`1.Compile()
   at Octokit.GraphQL.Core.Builders.ExpressionCompiler.Compile[T](Expression`1 expression)
   at Octokit.GraphQL.Core.SimpleQuery`1..ctor(OperationDefinition operationDefinition, Expression`1 resultBuilder)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.Build[TResult](IQueryableValue`1 query)
   at Octokit.GraphQL.QueryableValueExtensions.Compile[T](IQueryableValue`1 expression)
   at GitHub.Services.RepositoryCloneService.<ReadViewerRepositories>d__8.MoveNext() in D:\projects\github\VisualStudio\src\GitHub.App\Services\RepositoryCloneService.cs:line 68

It seems to be caused by the AllPages() call on Organizations.

Variable of enumerable type produces invalid query

The following query:

var expression = new Query()
    .Repository("foo", "bar")
    .Issues(labels: Var("var1"))
    .Select(x => x.TotalCount);

Produces an invalid query:

query($var1: IEnumerable`1) {
  repository(owner: "foo", name: "bar") {
    issues(labels: $var1) {
      totalCount
    }
  }
}

Note the variable declaration is wrong. It should be $var1: [string!].

How to get current authorized organizations.

I am trying this:

var expression = query.Viewer.Organizations(2).Compile().

I authorise one of my organisations to be allowed but not the other. In this case the above code throws the exception:

"message":"GraphQL.ExecutionError: Error trying to resolve setupCallback. ---> Octokit.GraphQL.Core.Deserializers.ResponseDeserializerException: Although you appear to have the correct authorization credentials,\nthe jplayer organization has enabled OAuth App access restrictions, meaning that data\naccess to third-parties is limited.

I don't want to give jplayer organisation access but I want to give my other organisation access.

How do I get the current authorised organisations that the user has authorised instead of all of them?

Question: Retrieving Repository Listings Efficiently

I'm working on a project where we need to read the contents of a repository to effectively build an index from the content in a repository so that the content can be presented in different ways.

Thanks to help in another issue I figured out how I can use the GraphQL API to retrieve single level content easily via code. I wrote some helper code that loops through the folder structure one folder at a time:

        /// <summary>
        /// Retrieves all files in a given Github branch/path. Optionally
        /// allows recursively retrieving all content in child folders/trees.
        ///
        /// Note: child folders are lazy loaded so recursive action can  
        /// result in a lot of separate HTTP requests made to the server
        /// </summary>
        /// <param name="path">Branch and path to to start parsing on using `branch:path` syntax:
        /// Example: `master:` or `master:subpath\subpath2`</param>
        /// <param name="recursive">If true recurses any subpaths</param>
        /// <returns>List of Items optionally with child items</returns>
        public async Task<List<GithubFolderItem>> GetFolder(string path = "master:", bool recursive = true)
        {
            var productInformation = new ProductHeaderValue(ApiName, ApiVersion);

            var connection = new Connection(productInformation, _token);
            var query = new Query()
                .Repository(name: _repository, owner: _owner)
                .Object(expression: path)
                .Cast<Tree>()
                .Entries.Select(x => new GithubFolderItem
                {
                    Name = x.Name,
                    Type = x.Type,
                })
                .Compile();

            var entries = await connection.Run(query);


            foreach (var entry in entries)
            {
                entry.FullPath = path + entry.Name;

                if (!recursive || entry.Type != "tree")
                    continue;

                entry.Items = await GetFolder(entry.FullPath + "/");
            }

            return entries.ToList();
        }

full code

This works fine functionally wise but it's very slow and seems very inefficient. On even moderately sized repos this can take several minutes to process because each directory is a new request. I can probably optimize this a bit by running all same level folders simultaneously but that doesn't help with the overall request load.

From what I've read it appears that GraphQL doesn't support recursive requests so I wonder if it might be useful for some high level custom api to be available that can return just the file/folder info data for a repository. It would seem to me that that might be a common thing that people need to do and having to run so many individual requests is causing a ton of overhead both on Github and clients that have to serve that data.

I've seen quite a few requests for this sort of thing while searching (although with more specific search options).

Has any thought been given to provide some custom endpoint to provide file info for the entire repository even if the actual data returned is just Id, name, and path so that the detail can be pulled later...

GraphQL INTERFACE TypeKind support in fragments

Hi & Congrats! The API will be awesome & usefull!

But at this time does not support to use of fragments, if the target GraphQL side TypeKind is an INTERFACE in the definition of fragment.

For an simple example, i wrote this:

var fragment = new Fragment<IRepositoryOwner, OwnerModel>("OwnerFragment", o =>
                            new OwnerModel()
                            {
                                Login = o.Login,
                                AvatarUrl = o.AvatarUrl(100),
                                Url = o.Url,
                            });
var query = new Query().Select(q => new
                {
                    repoOwner = q.Repository("octokit", "octokit.net")
                                    .Owner.Select(fragment).SingleOrDefault()
                }).Compile();
var result = connection.Run(query).Result;

Where the 'OwnerModel' is:

public class OwnerModel
{
    public string Login { get; set; }
    public string Url { get; set; }
    public string AvatarUrl { get; set; }
}

(or similar simple class)

When the 'connection.Run' (last line of the code above) is executed, an exception occured with this message:'No such type IRepositoryOwner, so it can't be a fragment condition'
This is a correct GraphQL endpoint side error, because the generated GraphQL query string output is:

query {
  repoOwner: repository(owner: "octokit", name: "octokit.net") {
    owner {
      avatarUrl(size: 100)
      ...OwnerFragment
    }
  }
}
fragment OwnerFragment on IRepositoryOwner {
  login
  url
}

Where the 'IRepositoryOwner' is a bad name. There is 'RepositoryOwner' correctly.
The direct source of error is here:

private string ToTypeName(Type type) => type.Name;

Because this uses simply .Net type name (System.Type.Name)here, that is: 'IRepositoryOwner'.

The type that implement this interface (StubIRepositoryOwner) is internal in the Generated modell in RepositoryOwner.cs. (And its name is different to GraphQL side type too...) So i can't use thats in the fragment's definition.

There is need an mapping betwen generated type name & GraphQL side name at this point... Or general support for type name mapping between .Net & GraphQL side? There is for general supporting all other potential naming convention differences such as different letter case or frequent word separation character (like underscore). Maybe is the use of an Attribute in generated type a good choise?

But there is an another problem around here, because i would expect that as full correct GrapQL query string output:

query {
  repoOwner: repository(owner: "octokit", name: "octokit.net") {
    owner {    
      ...OwnerFragment
    }
  }
}
fragment OwnerFragment on RepositoryOwner {
  login
  url
  avatarUrl(size: 100)
}

Support an official way to pass a Raw JSON String Query

I'm trying to use the GraphQL API to retrieve content from a specific repository item via the GraphQL API.

I can enter a graphQL query into the explorer and it works:

image

I've been trying to figure out how to duplicate this behavior using the OctoKit GraphQL API to accomplish the same thing. I've not figured out a way to get the LINQ syntax to represent that query, but it appears that I can also send the text directly to connection.Run(lcJson).

[TestMethod]
        public async Task RawJsonTest()
        {
            var productInformation = new ProductHeaderValue("GraphQLTest", "0.1");
            var connection = new Connection(productInformation, token);

            string rawJson = @"query {
  repository(name: ""MarkdownMonster"", owner: ""RickStrahl"") {
    object(expression: ""master:README.md"") {
      ... on Blob {
        text
      }
    }
 }
}";

            var result = await connection.Run(rawJson);

            Assert.IsNotNull(result);
            Assert.IsTrue(result.Contains("\"text\": "));
        }

However this returns 400 Bad Request. Checking the request trace I can see the raw JSON is going out to the server and it all looks correct.

I would have expected that to work.

I turns out the query syntax needs to be more formal and require top level {query, variables } object to make this work so I can get it to work.

This actually works to retrieve the raw JSON:

       [TestMethod]
        public async Task RawJsonWithTestQueryTest()
        {
            var productInformation = new ProductHeaderValue("GraphQLTest", "0.1");
            var connection = new Connection(productInformation, token);


            string rawJson = @"
query {
  repository(name: ""MarkdownMonster"", owner: ""RickStrahl"") {
    object(expression: ""master:README.md"") {
      ... on Blob {
        text
      }
    }
 }
}";
            var query = new TextQuery(rawJson);
            string result = await connection.Run(query.ToString());

            Console.WriteLine(result);

            Assert.IsNotNull(result);
            Assert.IsTrue(result.Contains("\"text\":"));
        }
    }

but it's not exactly intuitive.

Ideally I would like to see the API syntax provide the strongly typed equivalent of the raw JSON, but I can't find any examples that work to perform the ... on syntax. I can drill into the object and get the Id but that's where it ends.

In the meantime it might be nice to provide some explicit support for raw Text in the API so as to make it obvious that can be provided and automatically handle at least wrapping up the query and variables.

Something like this perhaps:

     [TestMethod]
        public async Task RawJsonWithTestQueryTest()
        {
            var productInformation = new ProductHeaderValue("GraphQLTest", "0.1");
            var connection = new Connection(productInformation, token);


            string rawJson = @"
query {
  repository(name: ""MarkdownMonster"", owner: ""RickStrahl"") {
    object(expression: ""master:README.md"") {
      ... on Blob {
        text
      }
    }
 }
}";
            // Official object for raw Text Queries
            var query = new TextQuery(rawJson);

            // direct overload  w/o .ToString() requirement would be nice
            var result = await connection.Run(query.ToString());  

            Console.WriteLine(result);

            Assert.IsNotNull(result);
            Assert.IsTrue(result.Contains("\"text\":"));
        }
    }


    public class TextQuery 
    {
        private readonly string _queryText;
        private readonly Dictionary<string, object> _variables;

        public TextQuery(string queryText, Dictionary<string, object> variables = null)
        {
            _queryText = queryText;
            _variables = variables;
        }

        public override string ToString()
        {
            var query = new
            {
                query = _queryText,
                _variables = _variables
            };

            var json = JsonConvert.SerializeObject(query);
            return json;
        }

    }

Don't use <inheritdoc/> on constructors.

In various places such as here we've applied the /// <inheritdoc/> XML documentation tag to constructors.

This makes no sense, constructors don't implement interface or abstract members so don't have anywhere to inherit their documentation from.

Complex query duplicates parameter...

Incorrect form

var expression = new Query()
    .Select(q => new
    {
        repo1 = q.Repository("foo", "bar").Name.Single(),
        repo2 = q.Repository("foo", "bar").Name.Single()
    });

results in:

query {
  repository(owner: "foo", name: "bar", owner: "foo", name: "bar") {
    name
  }
}

Correct form

var expression = new Query()
    .Select(q => new
    {
        repo1 = q.Repository("foo", "bar").Select(repository => new { repository.Name }).Single(),
        repo2 = q.Repository("foo", "bar").Select(repository => new { repository.Name }).Single()
    });

results in:

query {
  repo1: repository(owner: ""foo"", name: ""bar"") {
    name
  }
  repo2: repository(owner: ""foo"", name: ""bar"") {
    name
  }
}

Explanation

This feels similar to tests Cannot_Select_QueryableValue and Cannot_Select_QueryableList.
We should be capturing this case somehow and throwing an exception.

Cannot retrieve IGitObject which is a Union in correct object type

Summary

Depending how a GitHub Release is created, a Release.Tag.Target can either refer to a Commit object or to a Tag object. To retrieve the target Sha1 of the Release, inline fragments are required in a GraphQL query.

It doesn't currently seem possible to reproduce this using the Octokit.GraphQL library as the Switch<> syntax is not available on Target's object type (which is IGitObject), nor on it's parent Tag's object type (which is Ref ... just in case there was syntactic sugar going on somewhere).

Relevant information

Here's some GraphQL that reproduces this:

query releases {
  repository(owner:"MyOrg", name:"MyRepo") {
    releases(
      first:2
      orderBy:{field: CREATED_AT, direction:DESC}){
        nodes{        
      	name
        createdAt,
        publishedAt
        tag{
          name
          target{
            ... on Commit{
              oid
              }
          }
          target {            
            ... on Tag {
              target {
		... on Commit {
                  oid
                }
              }
            }
          }
        }    
      }
    }    
  }  
}

Please note that I am unable to provide you with a public example of this in the real world as I'm using GitHub Enterprise. However here is a (redacted) version of the results when this is run against my server:

{
  "data": {
    "repository": {
      "releases": {
        "nodes": [
          {
            "name": "DB-10.222.0.65",
            "createdAt": "2018-10-11T20:58:59Z",
            "publishedAt": "2018-10-11T22:09:32Z",
            "tag": {
              "name": "XDB-10.222.0.65",
              "target": {
                "oid": "1b15628099a241d2d1d345aa112222027e120948"
              }
            }
          },
          {
            "name": "DB-10.221.3.79",
            "createdAt": "2018-10-11T03:51:49Z",
            "publishedAt": "2018-10-11T03:52:39Z",
            "tag": {
              "name": "0.0.95",
              "target": {
                "target": {
                  "oid": "4ea68920cf2d3d4f3771edae512c10f87922c4e7"
                }
              }
            }
          }
        ]
      }
    }
  }
}

Based on your documentation, this is some pseudo code of what I would expect to be able to do:

var query = new Query()
	.Repository(name: "MyOrg", owner: "MyRepo")
	.Releases(first: 2, orderBy: new ReleaseOrder() { Direction = OrderDirection.Desc, Field = ReleaseOrderField.CreatedAt })
	.Nodes
	.Select(release => new 
	{
		CreatedAt = release.CreatedAt,
		Name = release.Name,
		PublishedAt = release.PublishedAt,
		Url = release.Url,
		Sha1 = release.Tag.Target.Select(target => target.Switch<TargetModel>(when =>
			when.Commit(commit => commit.Oid)
			.Tag(tag => tag.Target.Cast<Commit>().Oid)
	});

I've had a look through the library code and as far as I can tell it's isn't supported. However, feel free to let me know if it's a PEBKAC error!

Thanks for reading.

Conditional with interface fails.

The following query fails:

var query = new Query()
    .Repository("octokit", "octokit.net")
    .PullRequest(1)
    .Select(pr => pr.BaseRef != null ? pr.BaseRef.Repository.Owner.Login : null);

With:

JsonSerializationException: Could not create an instance of type Octokit.GraphQL.Model.IRepositoryOwner. Type is an interface or abstract class and cannot be instantiated.

Selecting a null GraphQL element throws an unfriendly exception

For example, the following:

var query =
    from x in new Query().Repository(owner: "grokys", name: "PullRequestSandbox")
    select new { x.Name, x.Description, ForkedFrom = x.Parent.NameWithOwner };
var result = await Connection.Run(query);

will throw:

System.InvalidOperationException: Cannot access child value on Newtonsoft.Json.Linq.JValue.
	at Newtonsoft.Json.Linq.JToken.get_Item(Object key)
	at x => new <>f__AnonymousType3`3(Name = x.Name, Description = x.Description, ForkedFrom = x.Parent.NameWithOwner)(Closure , JToken )
	at Octokit.GraphQL.Core.Builders.Rewritten.Value.Select[TResult](JToken source, Func`2 selector)
	at lambda_method(Closure , JObject )
	at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](Func`2 deserialize, JObject data)
	at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](Func`2 deserialize, String data)
	at Octokit.GraphQL.Core.SimpleQuery`1.Runner.<RunPage>d__10.MoveNext()

Unfortunately ?. operators aren't currently supported in expressions trees:

image

So the user would need to do the following to get the expected result:

var query =
    from x in new Query().Repository(owner: "grokys", name: "PullRequestSandbox")
    select new { x.Name, x.Description, ForkedFrom = x.Parent != null ? x.Parent.NameWithOwner : null };
var result = await Connection.Run(query);
Console.WriteLine(result);
{ Name = PullRequestSandbox, Description = , ForkedFrom =  }

Problems with current situation

  1. It isn't obvious from the exception that the issue is with x.Parent.NameWithOwner
  2. The obvious x.Parent?.NameWithOwner fix isn't supported
  3. After seeing the compile error, it wasn't obvious that x.Parent != null ? ... would be supported
  4. I didn't see the exception immediately because by first queries didn't return any null elements

Possible solutions

Might it be possible to expose nullable elements as a custom nullable type (similar to nullable value types)? This could support .Value and .GetValueOrDefault(...) like the existing Nullable type.

This nullable type could also support a .SelectOrDefault(x => x....) method, for when a user wants to continue the Select` operation.

It would then be possible to do this:

var query =
    from x in new Query().Repository(owner: "grokys", name: "PullRequestSandbox")
    select new { x.Name, x.Description, ForkedFrom = x.Parent.SelectOrDefault(y => y.NameWithOwner) };

This would make it easy to discover and handle nullable elements and avoid surprises when an element comes back null.

Conditional in query fails.

The following query:

var query = new Query()
    .Repository("octokit", "octokit.net")
    .PullRequest(1)
    .Select(pr => pr.BaseRef != null ? pr.BaseRef.Name : null);

Fails with:

ArgumentException: Argument types do not match

Where clause throws exception

Code I tried:

            var issues = new Query().Repository("GitHub", "VisualStudio")
                .Issues(first: 30)
                .Nodes
                .Where(x => x.Title.Contains("Git"))
                .Select(y => y.Title);

Stack Trace:

   at System.Linq.Expressions.Expression.ValidateCallInstanceType(Type instanceType, MethodInfo method)
   at System.Linq.Expressions.Expression.ValidateStaticOrInstanceMethod(Expression instance, MethodInfo method)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
   at System.Linq.Expressions.MethodCallExpression.Update(Expression object, IEnumerable`1 arguments)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 228
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 89
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitLambda[T](Expression`1 node) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 65
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitUnary(UnaryExpression node) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 150
   at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.<VisitMethodArguments>d__15.MoveNext() in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 203
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source, Int32& length)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable`1 enumerable)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
   at System.Linq.Expressions.MethodCallExpression.Update(Expression object, IEnumerable`1 arguments)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 228
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 89
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitSelect(Expression source, Expression selectExpression) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 268
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node, MemberInfo alias) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 211
   at Octokit.GraphQL.Core.Builders.QueryBuilder.VisitMethodCall(MethodCallExpression node) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 89
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Octokit.GraphQL.Core.Builders.QueryBuilder.Build[TResult](IQueryable`1 query) in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Builders\QueryBuilder.cs:line 27
   at Octokit.GraphQL.Core.Connection.<Run>d__6`1.MoveNext() in C:\Users\paladique\Source\Repos\Octokit.GraphQL\Octokit.GraphQL.Core\Connection.cs:line 32
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at DoSomething.Program.<GetIssues>d__2.MoveNext() in C:\Users\paladique\Source\Repos\Octokit.GraphQL\DoSomething\Program.cs:line 38
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at DoSomething.Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\Users\paladique\Source\Repos\Octokit.GraphQL\DoSomething\Program.cs:line 13

Support injection of HttpClient instances

The Connection class should be extensible enough to allow for interoperability with the HttpClientFactory in .NET Core 2.1.

This would allow users to use the out-of-the-box GraphQL client in their applications easily while applying cross-cutting concerns like retries, handler pooling, centralised configurability etc. without having to implement IConnection themselves to remove the HttpClient instance created privately per Connection instance.

Move mutation to root namespace.

All models but Query were moved to the Octokit.GraphQL namespace; Mutation should have stayed there too as it's a root query.

Argument types do not match

The following query fails:

class ActorModel
{
    public string Login { get; set; }
    public string AvatarUrl { get; set; }
}

var query = new Query()
                .Repository("octokit", "octokit.net")
                .Issues(first: 100, after: Var("after"))
                .Select(connection => new
                {
                    connection.PageInfo.EndCursor,
                    connection.PageInfo.HasNextPage,
                    connection.TotalCount,
                    Items = connection.Nodes.Select(issue => new
                    {
                        NodeId = issue.Id,
                        Number = issue.Number,
                        Title = issue.Title,
                        Author = new ActorModel
                        {
                            AvatarUrl = issue.Author.AvatarUrl(null),
                            Login = issue.Author.Login,
                        },
                        UpdatedAt = issue.UpdatedAt.Value,
                    }).ToList(),
                }).Compile();
Argument types do not match

Nullability mismatch on variables

The following query doesn't work:

new Query()
    .Repository(Var("name"), Var("owner"))
    .Select(repository => repository.Name);
"Nullability mismatch on variable $name and argument owner (String / String!)"
"Nullability mismatch on variable $owner and argument name (String / String!)"

The variables created don't match the argument's nullability.

Unable to get repository after rename

Issue

If a repository is renamed, using the old name throws an exception with the message
"Could not resolve to a Repository with the name 'old name here'."

Desired Result

It should be able to give you the information for the renamed repository. For example
{ test2:repository(owner: "benjaminwinokur" name:"test2"){ name } test:repository(owner: "benjaminwinokur" name:"test"){ name } }
returns
{ "data": { "test2": { "name": "test2" }, "test": { "name": "test2" } } }

Octokit.GraphQL.Net Version

0.1.3.0

Stack Trace

at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](Func2 deserialize, JObject data) at Octokit.GraphQL.Core.Deserializers.ResponseDeserializer.Deserialize[TResult](Func2 deserialize, String data)
at Octokit.GraphQL.Core.SimpleQuery1.Runner.<RunPage>d__10.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Octokit.GraphQL.ConnectionExtensions.<Run>d__21.MoveNext()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.