Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Question: Would this work with Microsoft DocumentDb IQueryable implementation? #42

Open
chrizy opened this issue Sep 25, 2016 · 9 comments

Comments

@chrizy
Copy link

chrizy commented Sep 25, 2016

Thanks
Chris

@chkimes
Copy link
Owner

chkimes commented Sep 25, 2016

Hey Chris,

I haven't had a chance to play with this library and DocumentDb yet, however the goal is for it to work with any IQueryable implementation. Some queryable providers require special handling for edge case situations, which I've been adding as I discover them, but in general there's nothing super complicated going on such that I wouldn't expect it to work for some given IQueryable implementation.

I don't have a DocumentDB instance to play with right now, so if you start using it with one let me know in this issue if it does or doesn't work.

@mcquiggd
Copy link

mcquiggd commented Apr 9, 2017

@ckimes89 Just as FYI, you can run a free DocumentDB emulator locally:

https://docs.microsoft.com/en-us/azure/documentdb/documentdb-nosql-local-emulator

It doesn't handle all scenarios, such as Partitioned Collections, but it would be a good start...

Thanks for the great project 👍

@benmccallum
Copy link
Contributor

benmccallum commented Dec 24, 2017

Has anyone given this a go? Will probably try doing a basic graphql-net to cosmos db (with the sql api) in the next few days to see if it plays nice.

@benmccallum
Copy link
Contributor

benmccallum commented Jan 15, 2018

Here's example of how the queries are built using the .NET SDK:
https://github.com/Azure/azure-documentdb-dotnet/blob/530c8d9cf7c99df7300246da05206c57ce654233/samples/code-samples/Queries/Program.cs

I've got setup with my own app and will now start looking at how graphql-net would interact with it. I'm guessing I need to figure out where the IQueryable is output and then hand that over to the CosmosDB API.

In EF you do .Set<User> but in CosmosDB you do client.CreateDocumentQuery<User>(userCollectionLink) then build up your query off that. The collection link is interesting in that you find it by creating and running a collection query, and then doing foundCollection.SelfLink. This link immutable and doesn't change once the collection is created but we may need a way to map collection links to models/entities, maybe with an attribute or something (whether it's given just the collection name and resolves then caches it at runtime or accepts a link straight up and the dev plugs it in).

Super early browsing but I'll see how I go tomorrow.

@benmccallum
Copy link
Contributor

I managed to get something kinda working, at least for a "user" field that just returns the list of users in my Cosmos DB collection. I'm not sure how best to setup and structure this thing though. It's not like mapping to an EF context where they're doing all the hard work behind the scenes. You need to manage grabbing your collections and so forth, and most of the operations are async so I don't know how best to handle that either.

I'm going to have to create a vanilla repo that has what I've done so far. Then if someone wants to have a look and help me out that'd be awesome. Eventually it can become an example project for this.

@benmccallum
Copy link
Contributor

Here's where I'll be putting the example I'm working on.
https://github.com/benmccallum/graphql-net/tree/master/examples/09-cosmos-db

@benmccallum
Copy link
Contributor

I've created the ASP.NET Core api implementation of the /graphql endpoint as a controller to spec as defined here: http://graphql.org/learn/serving-over-http/

Haven't handled errors to spec yet, but the types of requests (GET and POST of various types) and the response (JSON and structure) are there.

You can now hit the api like so:

  • GET localhost:53366/graphql?query={users{id,profile}}
  • POST localhost:53366/graphql?query={users{id,profile}}
  • POST localhost:53366/graphql with Content-Type: application/graphql and {users{id,profile}} in body
  • POST localhost:53366/graphql with Content-Type: application/json and below in body:
{
  "query": "{users{id,profile}}"
}

This query works fine but I know that some I'm going to start trying soon will fail. Nonetheless, progress!

@benmccallum
Copy link
Contributor

benmccallum commented Jan 17, 2018

I've added a set of test requests I'm running with Postman to my repo under folder Tests. You can see fairly quickly that basic queries are fine but I'm having issues right now with:

  • { users {id, profile { age } } } - specifying profile works, specifying just age in profile breaks. Null exception. Weird thing is this works: { user(id:\"84d2d957-8f94-45df-bbca-8a393c15a7ad\") { id, profile { age } } }. So it doesn't work on users field but does on user by id?
  • { totalUsers } - can't call a field I've defined myself at the top level. In the docs it does it off user type, which works but I can't imagine anyone would ever do.

Queries in the .json file of tests to import include tests marked with * to indicate they are the ones failing. And in their description is the exception stack trace. Both cases above are Null exceptions.

@ckimes89, any words of wisdom?

I'm probably going to start pointing my example csproj as the real graphql-net projects as dependencies so I can put breakpoints through it all and try and see what it's doing. For instance, I'd love to be able to see the IQueryable it generates and have that log somewhere or be viewable so I can try executing that straight to CosmosDb. Understand that an expression tree might be hard to log though...

@benmccallum
Copy link
Contributor

benmccallum commented Mar 7, 2018

Ran off the source and debugged some tests. Saw existing test NestedEntity which pulls back user and their linked account (foreign key). It's not quite the same as my failing query though, which uses nesting but from the same document. CosmosDb allows you to define a document (e.g. user) with nesting on the document itself. So my user looks like:

{
  id,
  profile {
    age,
    gender
  },
  settings: {
    ...
  }
},

Issue is that in GraphQL.Net.Executor::MapResults tries to source a Get property and dynamically invoke it, with type.GetProperty(field.Name).GetGetMethod().Invoke(queryObject, new object[] { }) but in my case type (of queryObject) is JProperty from Newtonsoft, so GetProperty(field.Name) is null. I can put a clause in that checks for this type and if so casts to a JProperty and returns the value straight out, but I'm not sure what happens if the nesting goes further. For instance, what if I have user's website comments in this doc too and need to dig more levels in? With that change I no longer have the exception, but the profile field comes back as an array with the the property name and value as object items, rather than just a straight object.

I'm really just scraping the surface of how this works so forgive me. Looks like the executor is operating on some kind of dynamic types, but that only goes one level down? Looking at DynamicTypeBuilder (which comment says it's not used but is, and yea I can see it iterates over a type's properties and does a CreateProperty, so maybe this needs to recurse down).

Will keep playing. Any help or direction would be greatly appreciated. I'm sure I'm not the only one who would love to see GraphQL on top of CosmosDB.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants