Code Monkey home page Code Monkey logo

graphql-net's People

Contributors

alanprot avatar benmccallum avatar bzbetty avatar chkimes avatar kierenj avatar marianpalkus avatar markhepburn avatar rokondra avatar rspeele 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  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

graphql-net's Issues

Add a test project

ConsoleParser.csproj isn't cutting it anymore, let's use a real test project that can be hooked into automated testing. In addition to testing an Entity Framework context, we can also test vs. an in-memory context. This will be useful example for when we enable introspection later.

NHibernate sample

I really like your idea of converting GraphQL to IQueryable and have been trying to do a sample using NHibernate.

Do you know any reason why this wouldn't work with NHibernate.

I get following exception in Executor.cs. I am on .Net 4.5 using NHibernate 4

NHibernate.Exceptions.GenericADOException was unhandled HResult=-2146232832 Message=Could not execute query[SQL: SQL not available] Source=NHibernate SqlString=SQL not available StackTrace: at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results) at NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters) at NHibernate.Impl.AbstractQueryImpl2.List() at NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery) at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) at Remotion.Linq.QueryableBase1.GetEnumerator()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at GraphQL.Net.Executor1.Execute(TContext context, GraphQLField field, ExecSelection1 query) in C:\scratch\graphql-net\GraphQL.Net\Executor.cs:line 56 at GraphQL.Net.Executor1.Execute(GraphQLSchema1 schema, GraphQLField field, ExecSelection1 query) in C:\scratch\graphql-net\GraphQL.Net\Executor.cs:line 17
at GraphQL.Net.GraphQL1.ExecuteQuery(String queryStr) in C:\scratch\graphql-net\GraphQL.Net\GraphQL.cs:line 44 at QueryApi.Program.Program.Main(String[] args) in C:\scratch\QueryApi\QueryApi\Program\Program.cs:line 21 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() **InnerException: HResult=-2146233075 Message=Operation could destabilize the runtime. Source=Anonymously Hosted DynamicMethods Assembly StackTrace: at lambda_method(Closure , Object[] ) at NHibernate.Linq.ResultTransformer.TransformTuple(Object[] tuple, String[] aliases) at NHibernate.Hql.HolderInstantiator.Instantiate(Object[] row) at NHibernate.Loader.Hql.QueryLoader.GetResultList(IList results, IResultTransformer resultTransformer) at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet1 querySpaces, IType[] resultTypes)
at NHibernate.Loader.Hql.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results)
at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
InnerException:`**

Argument deserialization

I'm playing with graphql-net and I really like it.
One thing that I can't figure out is how args are deserialized.
It seems that camelCase/pascalCase conversion is not working for args.
Also, is it possible to get a plain JSON object (patch)?

patchUser(id: 1, patch: { displayName: "X" }) {
  id,
  displayName
}

A patch would be very useful as it includes information which fields should be updated. That's not available with strongly typed models.

Inline Fragments with type condition

Great project, thanks for your work ๐Ÿ‘

I am trying to implement inline fragments with type conditions analogous to the sample of the official graphql docs graphql docs.

Basically, there is an interface or base type (Character) and two concrete types (Human and Droid), the types are slightly modified for simplicity:

interface Character {
  id: ID!
  name: String!
}
type Human implements Character {
  id: ID!
  name: String!
  height: Float
}

type Droid implements Character {
  id: ID!
  name: String!
  primaryFunction: String
}

The query looks like this:

heros {
   __typename
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }

A result could look like this:

"heros": [
   {
     "__typename": "Human",
      "name": "Han Solo",
      "height": 5.6430448
    },
   {
     "__typename": "Droid",
      "name": "R2-D2",
      "primaryFunction": "Astromech"
    }
]

I extended the EntityFrameworkExecutionTests as follows:

  • Model classes
class Character
{
   public int Id { get; set; }
   public string Name { get; set; }
}

class Human : Character
{
   public double Height { get; set; }
}

class Droid : Character
{
   public string PrimaryFunction { get; set; }
}
  • Schema:
private static void InitializeCharacterSchema(GraphQLSchema<EfContext> schema)
{
    var character = schema.AddType<Character>();
    character.AddField(c => c.Id);
    character.AddField(c => c.Name);

    var human = schema.AddType<Human>();
    human.AddField(c => c.Id);
    human.AddField(c => c.Name);
    human.AddField(h => h.Height);

    var droid = schema.AddType<Droid>();
    droid.AddField(c => c.Id);
    droid.AddField(c => c.Name);
    droid.AddField(h => h.PrimaryFunction);

    schema.AddField("hero", new {id = 0}, (db, args) => db.Heros.SingleOrDefault(h => h.Id == args.id));
    schema.AddListField("heros", db => db.Heros);
}
  • Additional EfContext property:
public IDbSet<Character> Heros { get; set; }
  • Test data:
var human = new Human
{
    Id = 1,
    Name = "Han Solo",
    Height = 5.6430448
};
db.Heros.Add(human);
var droid = new Droid
{
    Id = 2,
    Name = "R2-D2",
    PrimaryFunction = "Astromech"
};
db.Heros.Add(droid);
  • Test Method 1:
[Test]
public void QueryInlineFragements()
{
    var schema = GraphQL<EfContext>.CreateDefaultSchema(() => new EfContext());
    InitializeCharacterSchema(schema);
    schema.Complete();

    var gql = new GraphQL<EfContext>(schema);
    var results = gql.ExecuteQuery("{ heros { name, __typename, ... on Human { height }, ... on Droid { primaryFunction } } }");
    Test.DeepEquals(results, "{ heros: [ { name: 'Han Solo', __typename: 'Human',  height: 5.6430448}, { name: 'R2-D2', __typename: 'Droid', primaryFunction: 'Astromech' } ] }");
}

This raises the following Exception:

GraphQL.Parser.SourceException : unknown fragment ``on''
at Microsoft.FSharp.Core.Operators.Raise[T](Exception exn)
at GraphQL.Parser.Utilities.failAt[a](SourceInfo pos, String msg) in C:\Projekte\graphql-net\GraphQL.Parser\Utilities.fs:line 49
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveFragmentSpreadSelection(FragmentSpread pspread, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 195 at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelection(Selection pselection, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 221
at [email protected](IEnumerable`1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 229
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
at GraphQL.Parser.SchemaResolver.Resolver`1.ResolveSelections(IEnumerable`1 pselections) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 227
at GraphQL.Parser.SchemaResolver.Resolver`1.ResolveFieldSelection(Field pfield, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 163
at GraphQL.Parser.SchemaResolver.Resolver`1.ResolveSelection(Selection pselection, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 218
at [email protected](IEnumerable`1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 229
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
at GraphQL.Parser.SchemaResolver.Resolver`1.ResolveSelections(IEnumerable`1 pselections) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 227
at GraphQL.Parser.SchemaResolver.Resolver`1.ResolveOperation(Operation poperation, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 234
at [email protected](IEnumerable`1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 282
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
at GraphQL.Parser.SchemaResolver.DocumentContext`1.ResolveOperations() in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 276
at GraphQL.Parser.GraphQLDocument`1.Parse(ISchema`1 schema, String source) in C:\Projekte\graphql-net\GraphQL.Parser\Integration\GraphQLDocument.fs:line 42
at GraphQL.Net.GraphQL`1.ExecuteQuery(String queryStr) in C:\Projekte\graphql-net\GraphQL.Net\GraphQL.cs:line 36
at Tests.EF.EntityFrameworkExecutionTests.QueryInlineFragements() in C:\Projekte\graphql-net\Tests.EF\EntityFrameworkExecutionTests.cs:line 222

  • Test Method 2
[Test]
public void QueryInlineFragements2()
{
    var schema = GraphQL<EfContext>.CreateDefaultSchema(() => new EfContext());
    InitializeCharacterSchema(schema);
    schema.Complete();

    var gql = new GraphQL<EfContext>(schema);
    var results = gql.ExecuteQuery("{ heros { name, __typename, ...human, ...droid } }, fragment human on Human { height }, fragment droid on Droid { primaryFunction }");
    Test.DeepEquals(results, "{ heros: [ { name: 'Han Solo', __typename: 'Human',  height: 5.6430448}, { name: 'R2-D2', __typename: 'Droid', primaryFunction: 'Astromech' } ] }");
}

This raises the following Exception:

GraphQL.Parser.SourceException : height'' is not a field of typeCharacter''
at Microsoft.FSharp.Core.Operators.Raise[T](Exception exn)
at GraphQL.Parser.Utilities.failAt[a](SourceInfo pos, String msg) in C:\Projekte\graphql-net\GraphQL.Parser\Utilities.fs:line 49
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveFieldSelection(Field pfield, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 148 at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelection(Selection pselection, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 218
at [email protected](IEnumerable1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 229 at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source) at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelections(IEnumerable1 pselections) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 227 at GraphQL.Parser.SchemaResolver.Resolver1.ResolveFragment(Fragment pfrag, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 184
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveFragmentSpreadSelection(FragmentSpread pspread, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 197 at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelection(Selection pselection, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 221
at [email protected](IEnumerable1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 229 at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source) at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelections(IEnumerable1 pselections) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 227 at GraphQL.Parser.SchemaResolver.Resolver1.ResolveFieldSelection(Field pfield, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 163
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelection(Selection pselection, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 218 at [email protected](IEnumerable1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 229
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source)
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveSelections(IEnumerable1 pselections) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 227
at GraphQL.Parser.SchemaResolver.Resolver1.ResolveOperation(Operation poperation, SourceInfo pos) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 234 at [email protected](IEnumerable1& next) in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 282
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source)
at GraphQL.Parser.SchemaResolver.DocumentContext1.ResolveOperations() in C:\Projekte\graphql-net\GraphQL.Parser\Schema\SchemaResolver.fs:line 276 at GraphQL.Parser.GraphQLDocument1.Parse(ISchema1 schema, String source) in C:\Projekte\graphql-net\GraphQL.Parser\Integration\GraphQLDocument.fs:line 42 at GraphQL.Net.GraphQL1.ExecuteQuery(String queryStr) in C:\Projekte\graphql-net\GraphQL.Net\GraphQL.cs:line 36
at Tests.EF.EntityFrameworkExecutionTests.QueryInlineFragements2() in C:\Projekte\graphql-net\Tests.EF\EntityFrameworkExecutionTests.cs:line 234

I'm not really sure, whether my schema definition is wrong or i misunderstood the inline fragments/type condtions of graph-ql.

Do you have a suggestion or hint how to implement it correctly?
Are type conditions already supported yet?

Thanks in advance :-)

docs

Hi Chad,
i think about setting up a more detailled documentation similiar to redux docs which uses gitbook.

Gitbook uses Markdown files which are stored in the git-repostiory (directory docs).

I tried it out on this fork: https://github.com/MarianPalkus/graphql-net/

The gitbook looks like this: https://www.gitbook.com/read/book/marianpalkus/graphql-net.

There are also some examples in the directory examples which are referenced in the docs.

What do you think of using gitbook? Do you think it is a good approach to store examples in the git-repo or should they live in their own git repo?

List return type should be List<>

Currently a query with multiple return is of type IEnumerable<T> (or some other incarnation like WhereSelectListIterator<T>) since the query that is built for lists does not include the ToList method. The returned type for lists should be List<T> where T is IDictionary<string, object>.

Support First and FirstOrDefault with expression

It's annoying to have to write:

schema.AddQuery("user", new { id = 0 }, (db, args) => db.Users.AsQueryable().Where(u => u.Id == args.id).FirstOrDefault());

when you could collapse the FirstOrDefault down to:

schema.AddQuery("user", new { id = 0 }, (db, args) => db.Users.AsQueryable().FirstOrDefault(u => u.Id == args.id));

especially when ReSharper nags you about it. This should just be a simple expression transformation to add a .Where.

Switch test frameworks for Travis CI

Travis CI doesn't support MSTest, presumably because it runs on a linux box and there's no command-line MSTest test runner that works with Mono. Either we can switch test frameworks to NUnit or XUnit, or we can find a different CI option that works with MSTest.

Support Guids?

Just started playing around and hit a roadblock, all of our ID fields are Guids.

Any idea what it might take to add Guid support? Is this a 10 minute fix, or something that would take considerable effort?

Support Optimistic Concurrency

Edit - removed pull request, updated issue here.

Hack MS SQL Test project again just to quickly show issue.

Attempting to support optimistic concurrency:

http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

Midway down the page - Add an Optimistic Concurrency Property to the Department Entity

The tldr, label one of your fields with [Timestamp] with the type of byte[] and SQL will ensure optimistic concurrency.

In the hacked ms sql test project I added

[Timestamp]
public byte[] ServerTimestamp { get; set; }
To User, and tried to run LookupSingleEntity(), test throws an exception trying to InitializeUserSchema when I add the ServerTimestamp field.

Stack trace:

System.IndexOutOfRangeException : Index was outside the bounds of the array.
at GraphQL.Net.GraphQLField.NewInternal[TArgs](GraphQLSchema schema, String name, Func2 exprFunc, Type fieldCLRType, Delegate mutationFunc) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLField.cs:line 72 at GraphQL.Net.GraphQLField.New[TContext,TArgs](GraphQLSchema schema, String name, Func2 exprFunc, Type fieldCLRType, Action2 mutationFunc) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLField.cs:line 65 at GraphQL.Net.GraphQLTypeBuilder2.AddFieldInternal[TArgs,TField](String name, Func2 exprFunc, Action2 mutation) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLTypeBuilder.cs:line 39
at GraphQL.Net.GraphQLTypeBuilder2.AddField[TArgs,TField](String name, Func2 exprFunc) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLTypeBuilder.cs:line 31
at GraphQL.Net.GraphQLTypeBuilder2.AddField[TArgs,TField](String name, TArgs shape, Func2 exprFunc) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLTypeBuilder.cs:line 22
at GraphQL.Net.GraphQLTypeBuilder2.AddField[TField](String name, Expression1 expr) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLTypeBuilder.cs:line 87
at GraphQL.Net.GraphQLTypeBuilder2.AddField[TField](Expression1 expr) in C:\Jobs\graphql-net\GraphQL.Net\GraphQLTypeBuilder.cs:line 72
at Tests.EF.EntityFrameworkMsSqlTests.InitializeUserSchema(GraphQLSchema`1 schema) in C:\Jobs\graphql-net\Tests.EF\EntityFrameworkMsSqlTests.cs:line 76
at Tests.EF.EntityFrameworkMsSqlTests.CreateDefaultContext() in C:\Jobs\graphql-net\Tests.EF\EntityFrameworkMsSqlTests.cs:line 61
at Tests.EF.EntityFrameworkMsSqlTests.LookupSingleEntity() in C:\Jobs\graphql-net\Tests.EF\EntityFrameworkMsSqlTests.cs:line 128

Use a FieldBuilder type to define fields

Right now fields are defined like:

typeBuilder.AddField("friends", u => u.Friends)

Or, with arguments, like:

typeBuilder
  .AddField("friends", new { friendId = 0 },
    args => (db, u) => u.Friends.Where(f => f.Id == args.friendId))

Adding a FieldBuilder would allow throwing more options on the fields without having a crazy method signature. Ideally, either of the current approaches would work to start the builder. Then users could add on other fluent calls to define security constraints, complexity, or additional optional arguments. Here's a hypothetical example of how a pretend astronaut in the distant future might use this:

typeBuilder
  .AddField("friends", u => u.Friends) // if you used args here, those args would be *required*
  .WithComplexity(10, 100) // we estimate a typical user will have between 10 and 100 friends
  .WithArguments(new { id = 0 }, // optional filtering argument
    args => (db, friends) => friends.Where(f => f.Id == args.id), 1) // modifies complexity to 1
  .WithArguments(new { name = "" }, // optional filtering argument
    args => (db, friends) => friends.Where(f => f.Name == args.name))
  .WithSecurityFilter((db, friends) => friends.Where(f => idk(db, friends)) // filter query
  .WithSecurityAssertion(fs => fs.All(SecurityManager.HasPermissionToView)) // in-memory predicate

Change query based on results of mutation

#39 made me realize that right now, there's no way to pass information from a mutation to the query that is run after a mutation. This should change so that we can support mutations that add a new entity and then immediately return that entity, or maybe return different values based on whether the mutation executed successfully or failed.

Example syntax:

schema.AddMutation("addUser",
    new {
        name = string.Empty,                   
        active = false
    },
    (db, args) =>
    {
        var newUser = new User
        {
            Name = args.name,
            Active = args.active
        };
        db.Users.Add(newUser);
        db.SaveChanges();
        return newUser.Id;   // return information from the mutation
    },
    (db, args, id) => db.Users.FirstOrDefault(u => u.Id == id)
               // pass information to query as a third parameter
);

Help debugging "Unsupported CLR type" exceptions

I've moved on to testing using a model from an existing project. This is a code-first model, originally reverse-engineered from the database, if that's relevant. I was able to successfully run queries if I manually added some fields (ie calling GraphQLTypeBuilder.AddField()), but given that we have a fair few models and they're quite large, this isn't ideal.

However, I've encountered issues running a basic example using AddAllFields():

var schema = GraphQL<EQContext>.CreateDefaultSchema(() => new EQContext());
schema.AddScalar(new { year = 0, month = 0, day = 0 }, ymd => new DateTime(ymd.year, ymd.month, ymd.day));
schema.AddType<EQ>().AddAllFields();
schema.AddField("eq", new { id = "" }, (db, args) => db.EQs.FirstOrDefault(e => e.EQ_ID == args.id));
schema.Complete();

Specifically, ExecuteQuery is throwing GraphQL.Parser.ValidationException: Unsupported CLR type EQ.

The EQ model is mostly string, decimal, and nullable DateTime fields, along with a bunch of references to other models. Any suggestions for what could be causing this, or how to debug it?

Things I've tried:

  • Adding recursive fields to models in the test suite (for example, in User I added a Supervisor/DirectReports many-one pair of fields), to test if that was an issue
  • Adding every other model referenced from the model in question (ie, everything in the context) to the schema
  • Ensuring that DateTime has been added via schema.AddScalar()

I'll move on now, but I'd like to add that this is a super promising project, and I'm happy to help out if I can.

Add PostResolved functions

Better name pending, but the idea here is that some fields don't need to be executed against the database (and in many cases can't be). Since we don't need to build an IQueryable here, the resolver function definition can just be a Func<> instead of Expression<Func>. These resolver functions would be executed after the database query completes.

I'm not sure yet if we want to allow access to the data returned from the database in the resolver function, since I think it would necessarily have to be in Dictionary<string, object> form. Maaaybe we could offer some overload that lets you define parameters for the function in terms of an "args" anonymous object that is built from a member initializer expression and then tack that onto the query, but that's getting pretty complex. However, it would be better than Dictionary access, since you have no idea what will be populated in the dictionary.

The immediate use case for this is introspection, since the schema is in memory and not queryable from the database.

Implement AddAllFields

This one shouldn't be too hard. Iterate through all the fields of a type, build a lambda expression for a selector, then pass each one to AddField on GraphQLTypeBuilder.

Add security filters and assertions to queries and fields

For GraphQL to be realistically useful it needs to be possible to integrate security restrictions into the schema.

These commonly take 2.5 forms:

  1. Filters that silently hide data from view - these should usually be able to happen at the IQueryable level. Maybe they have to also work in memory afterwards?
  2. Assertions that throw exceptions if a user tries to see something they shouldn't - for maximum flexibility these should happen in memory after the query runs.

This is a big issue that requires a lot of thought, and it depends on #17 . Consider this a long term. It may be best to implement #16 first so we understand how to implement the security requirements around mutations first.

Question - Mutation for adding values to the system?

If one wanted to add a new User from the test project, to the system would you do it via a mutation? Feels like I'm missing something fundamental and I'm not kicking anything up on Google.

Can one do:

schema.AddMutation("addUser",
               new
               {
                   name = string.Empty,                   
                   active = false
               },
               (db, args) => db.Users.AsQueryable(),
               (db, args) =>
               {
                   var newUser = new User()
                   {
                       Name = args.name,
                       Active = args.active
                   };
                   db.Users.Add(newUser);
                   db.SaveChanges();
               }
               );
 var gql = CreateDefaultContext();
 var results = gql.ExecuteQuery("mutation { addUser(name:\"Bob\", active: true) { id } }");

Stack trace

System.ArgumentException : Expression of type 'System.Linq.IQueryable`1[Tests.EF.EntityFrameworkMsSqlTests+User]' cannot be used for parameter of type 'Tests.EF.EntityFrameworkMsSqlTests+User'
   at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
   at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
   at System.Linq.Expressions.Expression.Invoke(Expression expression, IEnumerable`1 arguments)
   at GraphQL.Net.Executor`1.Execute(TContext context, GraphQLField field, ExecSelection`1 query) in C:\Jobs\graphql-net\GraphQL.Net\Executor.cs:line 70
   at GraphQL.Net.Executor`1.Execute(GraphQLSchema`1 schema, GraphQLField field, ExecSelection`1 query) in C:\Jobs\graphql-net\GraphQL.Net\Executor.cs:line 17
   at GraphQL.Net.GraphQL`1.ExecuteQuery(String queryStr) in C:\Jobs\graphql-net\GraphQL.Net\GraphQL.cs:line 44
   at Tests.EF.EntityFrameworkMsSqlTests.SimpleMutationAddUser() in C:\Jobs\graphql-net\Tests.EF\EntityFrameworkMsSqlTests.cs:line 211

Remove toCamelCase / allow customisation?

Submitting this as a question or discussion point, as much as an issue.

GraphQLTypeBuilder adds fields using ToCamelCase when the name isn't explicitly supplied. (The implementation just lowercases the first character).

What's the rationale behind this choice?

We're using code-first models reverse-engineered from a database where everything is uppercase; it means that to query a property we either have to explicitly add each one by name (user.AddField("USER_ID", u => u.USER_ID)), or our queries look a bit odd: "uSER_ID".

Add NuGet support

Once the library is "barely functional" we can release it on NuGet.

The call is ambiguous between the following methods or properties

Severity Code Description Project File Line Suppression State Error CS0121 The call is ambiguous between the following methods or properties: 'GraphQL.Net.InteropHelpers.OrDefault<T>(Microsoft.FSharp.Core.FSharpOption<T>)' and 'GraphQL.Net.InteropHelpers.OrDefault<T>(Microsoft.FSharp.Core.FSharpOption<T>)' GraphQL.Net C:\Users\9zllklkjflkjfljkfdsk\Desktop\graphql-net-master\GraphQL.Net\GraphQLSchema.cs 219 Active
Severity Code Description Project File Line Suppression State Error CS0121 The call is ambiguous between the following methods or properties: 'GraphQL.Net.StringExtensions.ToCamelCase(string)' and 'GraphQL.Net.StringExtensions.ToCamelCase(string)' GraphQL.Net C:\Users\9zllklkjflkjfljkfdsk\Desktop\graphql-net-master\GraphQL.Net\GraphQLTypeBuilder.cs 89 Active

Error in handling Integer/Long casting

Client's query
query AnotherQuery($someId: Int!) { GetUser(userid: $someId) { id, created_dt, username } }

Backend
long userId = context.Argument<long>("userid");

Argument parsing for long type throws exception when the given parameter can be fit with integer type eg. 10001.
The parsing is ok when $someId is passed with 1000000000000000001

Nuget package v. 0.3.0 missing API methods

The latest nuget version of GraphQL.Net is 0.3.0 which was published on 2016-11-11.

I assumed the API to be quite up-to-date in this version, however, i noticed missing API methods when defining a mutation.

The GraphQL.Net.SchemaExtensions in the DLL of the nuget version 0.3.0 looks like this:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace GraphQL.Net
{
    public static class SchemaExtensions
    {
        public static GraphQLFieldBuilder<TContext, TEntity> AddField<TContext, TEntity>(this GraphQLSchema<TContext> context, string name, Expression<Func<TContext, TEntity>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddField<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, TEntity>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListField<TContext, TEntity>(this GraphQLSchema<TContext> context, string name, Expression<Func<TContext, IEnumerable<TEntity>>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListField<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, IEnumerable<TEntity>>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, IEnumerable<TEntity>>> queryableGetter, Action<TContext, TArgs> mutation);
        public static GraphQLFieldBuilder<TContext, TEntity> AddMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, TEntity>> queryableGetter, Action<TContext, TArgs> mutation);
    }
}

Looking at the current master branch i would expect the GraphQL.Net.SchemaExtensions to look like this:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace GraphQL.Net
{
    public static class SchemaExtensions
    {
        public static GraphQLFieldBuilder<TContext, TEntity> AddField<TContext, TEntity>(this GraphQLSchema<TContext> context, string name, Expression<Func<TContext, TEntity>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddField<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, TEntity>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListField<TContext, TEntity>(this GraphQLSchema<TContext> context, string name, Expression<Func<TContext, IEnumerable<TEntity>>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListField<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, IEnumerable<TEntity>>> queryableGetter);
        [Obsolete]
        public static GraphQLFieldBuilder<TContext, TEntity> AddListMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, IEnumerable<TEntity>>> queryableGetter, Action<TContext, TArgs> mutation);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Action<TContext, TArgs> mutation, Expression<Func<TContext, TArgs, IEnumerable<TEntity>>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddListMutation<TContext, TArgs, TEntity, TMutReturn>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Func<TContext, TArgs, TMutReturn> mutation, Expression<Func<TContext, TArgs, TMutReturn, IEnumerable<TEntity>>> queryableGetter);
        [Obsolete]
        public static GraphQLFieldBuilder<TContext, TEntity> AddMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Expression<Func<TContext, TArgs, TEntity>> queryableGetter, Action<TContext, TArgs> mutation);
        public static GraphQLFieldBuilder<TContext, TEntity> AddMutation<TContext, TArgs, TEntity>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Action<TContext, TArgs> mutation, Expression<Func<TContext, TArgs, TEntity>> queryableGetter);
        public static GraphQLFieldBuilder<TContext, TEntity> AddMutation<TContext, TArgs, TEntity, TMutReturn>(this GraphQLSchema<TContext> context, string name, TArgs argObj, Func<TContext, TArgs, TMutReturn> mutation, Expression<Func<TContext, TArgs, TMutReturn, TEntity>> queryableGetter);
    }
}

Have those missing methods been added after the release of version 0.3.0 or is there another reason why they are not available?

Change AddLookup to AddQuery

AddLookup is required to differentiate from AddQuery if we want to have type constraints require that the expressions to be IQueryable<T>, but that only gives us compile-time safety during the creation of the model (which should happen on every application startup, and therefore fail quickly if you do something incorrectly). In exchange for that safety, it makes the API kind of janky in that you have to specify a different method for single return vs. multiple return.

To clarify, I want to change this:

schema.AddQuery("users", db => db.Users);
schema.AddLookup("user", new { id = 0 },
    (db, args) => db.Users.Where(u => u.Id == args.id));

into this:

schema.AddQuery("users", db => db.Users);
schema.AddQuery("user", new { id = 0 },
    (db, args) => db.Users.FirstOrDefault(u => u.Id == args.id));

This will require some more in-depth expression inspection and transformation, but I think the end result of a cleaner API will be worth it.

Implement List type for fields

Populating nested entities currently only works for a single entity, but not for lists. This is the last big thing that needs to be implemented before I would call the library even barely functional. Plenty of other stuff like introspection still needs to be done to match the spec, but this is necessary to support anything more than the most basic queries.

Support mutations

Hey guys!

Just started looking into GraphQL and your project looks great! I was wondering if there were short term plans for mutation support. I'm looking into creating a project that would do CQRS via GraphQL and this framework looks good but lacks mutation for now!

Null checks for in-memory queries

If, as currently, we translate:

  {
     user(id:1) { id, name, bestFriend { id, name } }
  }

To something like:

  db.Users.Select(u => new
    { id = u.Id
    , name = u.Name
    , bestFriend = new
      { id = u.BestFriend.Id
      , name = u.BestFriend.Name
      }
    })

This works in Entity Framework and probably most other ORMs but not in memory. If u.BestFriend is null, it will blow up with an NRE while executing the query. Inserting null checks can get really ugly and make the query expression incompatible with ORMs. What should happen?

Using GraphQL under Sharepoint ISAPI (WCF)

Hi guys,
By business request, I need host my WCF service (that uses GraphQL.net) under sharepoint (and it deploys to ISAPI folder).

Unfortunately, I get some strange error that related to graph.dll -
error CS0012: The type 'GraphQL<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'GraphQL.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

It occurs when I try to CreateDefaultContext. In case when it is hosted just under IIS it works fine.

Maybe u can give a hint why it happens.

Thx, D.

Add complexity annotations to fields and queries

Depends heavily on #17 .

It should be possible for me, when defining my schema, to plug my own numbers into the complexity estimate system.

For example, user.Commits may have a typical complexity of anywhere from 0 to 10000, while issue.Comments has a complexity more like 0 to 30.

Add a DeepEquals assertion

The tests are looking super goofy right now because of the lack of type information. Here's an example:

var user = (IDictionary<string, object>)gql.ExecuteQuery(
    "{ user(id:1) { id, account { id, name } } }")["user"];
Assert.AreEqual(user["id"], 1);
Assert.AreEqual(user.Keys.Count, 2);
Assert.IsTrue(user.ContainsKey("account"));
var account = (IDictionary<string, object>)user["account"];
Assert.AreEqual(account["id"], 1);
Assert.AreEqual(account["name"], "My Test Account");
Assert.AreEqual(account.Keys.Count, 2);

With a DeepEquals assert method, we can just pass JSON describing the expected output:

var results = gql.ExecuteQuery("{ user(id:1) { id, account { id, name } } }");
DeepEquals(results, @"{
    user: {
        id: 1,
        account: {
            id: 1,
            name: "My Test Account"
        }
    }
}");

This should make it a lot easier to understand what each test is doing.

Support .NET Standard

I appreciate this is probably tricky to address and not a priority, but floating it out there anyway.

We'd love to experiment with this, but our main projects still need to run on a net40 server.

I had a brief attempt; the fparsec dependencies were relatively easy to back-port, but there's more complications here (the read-only collections are an obvious issue, but even replacing those with the mutable interfaces still left a lot of errors).

Any thoughts on how feasible it should be?

Introspection and GraphiQL

I see that README states introspection is incompleted.

With a asp.net graphiql project, i can run the queries on http://graphql.org/learn/introspection/ however Kind values in result are not right.

Also, the default graphiql query fails with an exception.

Will this be hard to do for someone new to the codebase?

Add a license

If we're gonna be a big boy open source project then we'll need a license.

Handle (non-)nullability

At some point we'll need to support defining whether a field or argument is nullable or non-nullable. As for now, a decent starting point will just be forcing the nullability to match the CLR type's nullability. So nullable for classes, non-nullable for structs except Nullable<T>.

This isn't a long-term solution, since multiple ORMs support non-nullable relationships (e.g. Entity Framework with int SomethingId foreign keys). Also it would be nice to allow non-nullable arguments that map to a CLR class type.

Question: how to call type.AddListField with parameters

Is it possible to define a type field with parameters, like with schema? I'm not getting the syntax right.

Someting like the example below, but for GraphQLTypeBuilder:

GraphQLSchema<EfContext> schema;

schema.AddListField("accountsByGuid", new { guid = Guid.Empty }, (db, args) => db.Accounts.AsQueryable().Where(a => a.SomeGuid == args.guid));

Thanks in advance

Support passing variable values to queries with IExecContext

Currently GraphQL.cs always uses DefaultExecContext.Instance.

This context doesn't resolve any variable names. It screams and dies when a query contains variables.
We should support passing variables to queries. The most common way is certainly by a JSON blob like { variableName1: value1, variableName2: value2 }. Maybe XML is desirable too.

At minimum, we should support letting users pass their own IExecContext in.
Ideally, we should have some helpful standard implementations people can use.

Some options:

  • Separate NuGet packages supporting XML, JSON, with dependencies on the top libraries for the given format (e.g. Newtonsoft.Json).
  • Build in IExecContext implementations with those dependencies
  • Build in a JSON IExecContext implementation using our own JSON parser with FParsec

Support list fields in selections with type conditions (inline fragments)

Hi chad,
i noticed that list fields in selections with type conditions/inline fragments are not working yet.
Here is an example:

  • Data models:
    public class Character
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Human : Character
    {
        public double Height { get; set; }
        public ICollection<Vehicle> Vehicles { get; set; }
    }

    public class Stormtrooper : Human
    {
        public string Specialization { get; set; }
    }

    public class Droid : Character
    {
        public string PrimaryFunction { get; set; }
    }

    public class Vehicle
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int OwnerId { get; set; }
    }
  • Considering the following GraphQL query:
{ 
   heros {
      name
      __typename
      ... on Human { 
         height
         vehicles { name }
      }
      ... on Stormtrooper { 
         specialization 
      }
      ... on Droid { 
         primaryFunction 
      }
    }
}

...where we select the list field vehicles on heros of type Human.
The result may look like this:

{ 
  heros: [
    { name: 'Han Solo', __typename: 'Human',  height: 5.6430448, vehicles: [ {name: 'Millennium falcon'}] },
    { name: 'FN-2187', __typename: 'Stormtrooper',  height: 4.9, vehicles: [ {name: 'Speeder bike'}], specialization: 'Imperial Snowtrooper'},
    { name: 'R2-D2', __typename: 'Droid', primaryFunction: 'Astromech' } 
  ] 
}

When executing the query the following exception is thrown:

in \graphql-net\Tests\InMemoryExecutionTests.cs : line 36

....
in graphql-net\Tests\InMemoryExecutionTests.cs:line 36
Result Message:	System.ArgumentException : Argument types do not match

Looking at the GraphQl.Net/Executor.cs line 296ff:

            if (needsTypeCheck)
            {
                var typeCheck = Expression.TypeIs(baseBindingExpr, field.DefiningType.CLRType);
                var nullResult = Expression.Constant(null, toMember.PropertyType);

                // The expression type has to be nullable
                if (replacedBase.Type.IsValueType)
                {
                    replacedBase = Expression.Convert(replacedBase, typeof(Nullable<>).MakeGenericType(replacedBase.Type));
                }

                replacedBase = Expression.Condition(typeCheck, replacedBase, nullResult);
               }

The toMember is a list type, it has the type of the elements of the list (e.g. String if the list is of type ICollection<String>).

This can be fixed by using replacedBase.Type instead:

            if (needsTypeCheck)
            {
                // The expression type has to be nullable
                if (replacedBase.Type.IsValueType)
                {
                    replacedBase = Expression.Convert(replacedBase, typeof(Nullable<>).MakeGenericType(replacedBase.Type));
                }

                var typeCheck = Expression.TypeIs(baseBindingExpr, field.DefiningType.CLRType);
                var nullResult = Expression.Constant(null, replacedBase.Type);
                replacedBase = Expression.Condition(typeCheck, replacedBase, nullResult);
               }

This works fine for in-memory tests, however, for EF this results in the following error:

graphql-net\Tests.EF\EntityFrameworkExecutionTests.cs : line 235

...
at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory)
Result Message:	
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> System.Data.Entity.Core.EntityCommandCompilationException : An error occurred while preparing the command definition. See the inner exception for details.
  ----> System.NotSupportedException : The nested query is not supported. Operation1='Case' Operation2='Collect'

This seems to be a more complex issue.
I think the sql query has to be split up into more sql queries.. but i do not have an idea to do this in a nice way.

Here is a branch with related unit tests and a first approach to fix this issue:
https://github.com/MarianPalkus/graphql-net/tree/b-inline-fragments-with-list-field

Do you have any idea how to solve this?

Document schema.AddScalar(), AddEnum

I'd submit a PR but I'm unclear exactly how it's used, myself :)

GraphQLSchema defines a method AddScalar, which has something to do with validating and translating scalar types.

It's used in the tests to add a DateTime with year/month/day components, but I'm a bit unclear where these components come from, since the translation is only in one direction.

Without it, tests that query a model with a DateTime field will fail; for eg, comment out the AddScalar line in EntityFrameworkExecutionTests.CreateDefaultContext(), or alternatively in EntityFrameworkExecutionTests.AddAllFields() add a query on account (in this test Account is defined via AddAllFields(), but without the DateTime scalar added to the schema):

gql.ExecuteQuery("{ account(id:1) { id } }");

Quotes inside strings

Is there a way to escape single and double quotes inside strings?
The parser is throwing an error for strings with ' and "

I saw there is a treatment in the parser for especial chars but i don't read F# very well for digging into the issue.

Select which operation to run by name

Currently GraphQL.cs just runs the first operation in the given document.

It should take the operation name to run as an optional parameter. If the parameter is given, the operation must be defined in the document, or an exception is thrown. If the parameter is given, the document must define exactly one anonymous operation, or an exception is thrown.

This doesn't depend on anything.

Add in-memory support

Man this is gonna be a pain.

All the expression building currently works with Entity Framework, but it explodes when working in-memory with a scary sounding System.Security.VerificationException ("Operation could destabilize the runtime"... eesh). This is due to the expression not including a cast from whatever type to object when populating each field on GQLQueryObject20.

However, if you try to include the cast to object, then Entity Framework gets mad and won't populate the query. Database support is our primary goal with this project, so I'm not going to change it to support in-memory without being able to support both.

The best way that I can figure to do this is to create a dynamic type for each type in the schema. The fields for that type then won't require any cast when populating them, so EF will be happy and in-memory contexts won't explode. However, this means we should probably add a Finalize method on the context so we have a single time to generate all of the dynamic types. This would have been inevitable anyway since we want to add schema validation at some point.

Question: Does it possible to work not only with EF/NHibernate frameworks?

Hi guys,

I've run an example that based on EF and it works fine.

But, could you clarify me some question according to GraphQL:

according to EntityFrameworkExecutionTests.cs I found that you're using EFcontext (based on DbContext - which includes populating objects with data from a database, change tracking, and persisting data to the database):
var schema = GraphQL.CreateDefaultSchema(() => new EfContext());
It's mean, that we will have up-to-date data (let's assume that our EFContext is configured and working with MSSQLLocalDB).

It would be great if you clarify me (or just send me an example) how it works without EF (in case when we have to retrieve/update data from database like mysql or mssql)

Looking forward to your reply.
Thx, Dima.

Support enums

GraphQL enums are weird.

They're just identifiers that don't fit any of the other patterns - not variable names, not true, false, or null. We need to be able to distinguish between Color.Orange and Fruit.Orange. To avoid having to do some crazy inference thing where we leave the enum type unresolved until the point at which it's used, let's let people define a prefix with enums.

This could be something like: schema.AddEnum<Fruit>(prefix: "Fruit_")

Ideally it should work similarly to the general primitive type alias support, where if you've run that AddEnum call, you can use anonymous types with that CLR enum type in your field args without issue and with all the schema validation you'd expect.

Support defining custom primitive types

The whole ISchema<Info> deal supports aliasing GraphQL primitive types (e.g. a type called DateTime that's an alias for string and has its own validation function), but this is currently not used.

When defining a schema, it should be possible to set up your own aliases like so:

schema.AddStringPrimitive("DateTime", DateTime.Parse))

It would then be OK to define fields with args like new { time = default(DateTime) }, and the schema would go "oh, I support primitives of type System.DateTime - I know what GraphQL type they'll be represented by and how to go from that primitive to the CLR type".

The main change would be that in TypeHelpers.cs, all the argument-related calls would need to reference the schema to look up these aliases. I can do this one without interfering with the rest of the code too much.

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.