Comments (30)
Well, when it comes to automatically syncing the actual relationships between the sequelize models and the graphql types, yeah.
But I think connections can be used to query fields that aren't necessarily associations so that pagination information is provided.
from graphql-sequelize.
See discussion here: #30
Root level node connections are not supported AFAIK, you need to implement an explicit viewer field on root and then connections under that.
from graphql-sequelize.
@aweary Knows more about this than me, hopefully he can shed some light on a practical implementation.
from graphql-sequelize.
@bsr203 Are you on the absolute latest version? We fixed something in regards to this and published a new version last night.
from graphql-sequelize.
HI @mickhansen
thanks for the response. I just updated to the latest release and didn't solve it. You are right that I should not be using connection at root level. I have done it wrong above, but I was doing it correct in my app. see the schema below. so I have the viewer
node where all the types are attached to as fields.
my viewer looks like this
'use strict';
import { GraphQLObjectType } from 'graphql';
import { globalIdField } from 'graphql-relay';
import * as queryFields from '../rootQueryFields';
function attachFields(refs, fields) {
return Object.keys(fields)
.reduce((acc, key) => {
if (typeof fields[key] === 'function') {
acc[key] = fields[key](refs);
}
return acc;
}, {});
}
export default (refs) => new GraphQLObjectType({
name: 'Viewer',
fields: () => ({
id: globalIdField('Viewer'),
...attachFields(refs, queryFields),
}),
interfaces: [refs.nodeInterface],
});
attachFields adds all the queries to viewer
. you can see this pattern here
please let me know anything has to be done at the viewer definition so that graphql-sequelize
knows the connection. I checked the source here https://github.com/mickhansen/graphql-sequelize/blob/master/src/resolver.js#L28
and as far I see it doesn't see my definition of viewer field as an association
. May be I need to define it in sequelize
schema, which I don't do anything for viewer
. I don't want viewer in the database so I didn't define it. The connections under users
work. so, may be I need to define a model for viewer
but need a way to not treat it as a database entity. Am I on the right direction? How should my schema for viewer
looks like ?
thanks again for the package and helping me out. Cheers.
from graphql-sequelize.
It doesn't look like you are using the relay helpers from graphql-sequelize?
Please take a look at the relay tests: https://github.com/mickhansen/graphql-sequelize/blob/master/test/relay.test.js
Specifically https://github.com/mickhansen/graphql-sequelize/blob/master/test/relay.test.js#L158 which shows how to use the sequelize node type mapper with custom types ('viewer' => viewerType).
from graphql-sequelize.
I was using type mapper, but wasn't using it for viewer
. I added that now.
nodeTypeMapper.mapTypes({
[User.name]: refs.user,
'Viewer': refs.viewer
});
but the result is same. For this query from graphiql
{
viewer {
users {
edges {node {email}}
}
}
}
I see this log in my terminal
POST http://localhost:3002/graphql 200 142.504 ms - 33802
Executing (default): SELECT `id`, `email` FROM `users` AS `User` LIMIT 1;
and this is the response
{
"data": {
"viewer": {
"users": {
"edges": null
}
}
}
}
so it is a request for single node.
In the test you pointed out, I am not sure the schema reflect my situation.
The discussion about how to define viewer
field and the reason is here . facebook/relay#112
so, in the test schema, there should only one field viewer
of type viewerType
and viewerType
will have query fields like user
, users
,.. which could be list, connection etc. Do you think so too, then we can try it out ?
In other words, how I can I make
users: {
type: new GraphQLList(userType),
args: {
https://github.com/mickhansen/graphql-sequelize/blob/master/test/relay.test.js#L183
to
users: {
type: userConnection.connectionType,
args: {
since it is a list, I can't paginate. so, I guess it needs to be a connection field of viewer
from graphql-sequelize.
Take a look at https://github.com/mickhansen/graphql-sequelize/blob/master/test/relay.test.js#L115
Can you post your entire setup in a gist so we can take a look? But i don't really have any practical experience with relay yet so we need to see what @aweary says.
from graphql-sequelize.
thanks.. I will get a repo in an hour.
from graphql-sequelize.
On my way to the office, will review once I get there!
from graphql-sequelize.
Hi @mickhansen
you can see the changes here https://github.com/bsr203/graphql-sequelize/branches
sorry, I am not an expert user of github so my changes are in two branches.
1 . test-connection-viewer
In this the query users
is on root and we agree this doesn't work with relay at the moment.
2 . test-connection-viewer-2
In this, I tried to add a query field users
to viewer
. In my view, viewer
is the current user (could be anonymous or a logged in). I need paginated (connection) queries on viewer which may allow access to all the models within the system. say all/paginated User
, Task
etc.
so, we may have to define an association for Viewer
.
sequelize.define('Viewer' ...
Viewer.Users = Viewer.hasMany(User, {as: 'users'});
I tried it though, but didn't work. Also we probably don't need the viewer in database?
from graphql-sequelize.
If you want it to work magically, viewer should return a sequelize instance that has associations.
viewer
is not a sequelize object you'll have to do more work and play around with it a little bit (you probably can't use sequelize resolvers as is, likely have to wrap them).
This project is still experimental so you'll have to play around with it and debug the code as you code along :)
from graphql-sequelize.
thanks. Yup, I may have to make viewer a sequelize instance with all the associations and not having it in the database. Will explore it. Hope @aweary will have some pointers. Thanks again.
from graphql-sequelize.
What is your viewer? In my app i just return models.User.build({id: jwt.userId}, {isNewRecord: false})
from graphql-sequelize.
You shouldn't have to make a model for viewer
, that was the point of #31. I'll have to look at the resolver
function and whether the isConnection
and handleConnection
helpers are correctly identifying/handling a connection from a pure GraphQL type.
We've personally moved towards using a userType
for our viewer
which sidesteps this, but we should still be able to to resolve these connections.
from graphql-sequelize.
We've personally moved towards using a userType for our viewer which sidesteps this, but we should still be able to to resolve these connections.
does that mean userType
will have associations to all the models in the system . say I want to list all the users in the system, so will user type has a query field users
? How do we handle anonymous user, which may not have a user instance?
from graphql-sequelize.
resolver
works with the source, if possible, so if you want magic association handles it needs to be an instance, otherwise you can plug into the resolvers to work with your custom viewer type.
from graphql-sequelize.
does that mean userType will have associations to all the models in the system . say I want to list all the users in the system, so will user type has a query field users ? How do we handle anonymous user, which may not have a user instance?
Yes, the user is considered the viewer
and will have fields for all the other types it is allowed to query. We use the rootValue
to pass in our authentication information and if no information is provided we resolve a null user who represents anonymous users.
Anyways, I'm looking at the resolve
function now, I'll see what I can do.
if (association && source.get(association.as) !== undefined) {
if (isConnection(info.returnType)) {
return handleConnection(source[info.fieldName], args);
}
return source.get(association.as);
}
At a glance it looks like it will only check for connections if its passed an association in the resolver
function.
from graphql-sequelize.
@aweary connections really only makes sense as an association does it not? Otherwise it's not really a connection.
Atleast from the point of view of automatic handling.
from graphql-sequelize.
@aweary Definitely, and i suppose when relay will support root connections Sequelize should aswell, i was simply thinking in the context of a viewer.
from graphql-sequelize.
In case of use with relay
, we may need a virtual model like Viewer
which is not in DB but has associations to all the model (so we may need to define the model and associations Viewer.Users = Viewer.hasMany(User, {as: 'users'});
, ..). So, when a query arrives for the root node and association, it gives a sequelize instance and carry on with the associations. So, I have to think what to return for viewer
What is your viewer? In my app i just return models.User.build({id: jwt.userId}, {isNewRecord: false})
@mickhansen you asked about it. I was doing
resolve: (root) => root,
Viewer
not really an instance of User as I may store some info specific to the viewer (logged in user / anonymous)
from graphql-sequelize.
@bsr203 Well not sure how you expect graphql-sequelize to handle it. If the connections need to be scoped to the viewer then we need to know the relationship.
The library could attempt to query for anonymous viewers but i think that should be explicit (security/leak concerns if implicit imo).
from graphql-sequelize.
In my case, sequelize resolver
is only called once the authorization check is done. the middleware checks the token and all the resolve
and root query node is wrapped in authorization check.
from graphql-sequelize.
I'm not entirely sure how we'd support this. Currently the process for resolving a connection looks like
resolver = function (source, args, info) {
if (association && source.get(association.as) !== undefined) {
if (isConnection(info.returnType)) {
return handleConnection(source[info.fieldName], args);
}
return source.get(association.as);
}
It returns source[info.fieldName]
to handleConnection
. So for the users connection it would pass source['users']
which is passed to connectionFromArray
which iterates through the items and returns pagination information.
The problem is that the source
for viewer
is resolved to:
{ name: 'Viewer!', id: 1 }
Which, of course, has no users
information to pass to connectionFromArray
. We need to change how it resolves the viewer
or resolve the users list beforehand somewhere and have it available in the source
.
from graphql-sequelize.
Ya, I am fine defining a model for Viewer
(not not to persist)
Viewer = sequelize.define('Viewer', {
name: {
type: Sequelize.STRING
}
}, {
timestamps: false
});
Viewer.Users = Viewer.hasMany(User, {as: 'users'});
...
schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
viewer: {
type: viewerType,
//resolve: (root) => (root)
resolve: () => Viewer.build()
},
It didn't work for me, and still digging in.
from graphql-sequelize.
It is working
Viewer = sequelize.define('Viewer', {
name: {
type: Sequelize.STRING
}
}, {
timestamps: false
});
Viewer.Users = Viewer.hasMany(User, {as: 'users'});
viewerType = new GraphQLObjectType({
name: 'Viewer',
description: 'root viewer for queries',
fields: () => ({
id: globalIdField('Viewer'),
name: {
type: GraphQLString,
resolve: () => 'Viewer!'
},
users: {
type: userConnection.connectionType,
args: connectionArgs,
resolve: resolver(Viewer.Users)
}
}),
interfaces: [nodeInterface]
});
it.only('should resolve an array of objects containing connections', function () {
var users = this.users;
return graphql(schema, `
{
viewer {
users {
edges {
node {
name
}
}
}
}
}
`).then(function (result) {
if (result.errors) throw new Error(result.errors[0].stack);
expect(result.data.viewer.users.edges.length).to.equal(users.length);
result.data.viewer.users.edges.forEach(function (edge, k) {
expect(edge.node.name).to.equal(users[k].name);
//expect(edge.node.tasks.edges).to.have.length.above(0);
});
});
});
I guess I did resolve: resolver(Viewer.User)
instead of resolve: resolver(Viewer.Users)
earlier I tried the same by defining model for Viewer.
from graphql-sequelize.
Hi,
A quick question
If I define the Viewer
model as below, it works. but, If I do with classMethods -> associate it doesn't work. It is like defining the association through classMethods
adds a foreign key, but not in the below case. That can't be true but can't explain why it work in one and not in the other case. Any help appreciated. thanks.
Viewer = sequelize.define('Viewer', {
name: {
type: Sequelize.STRING
}
}, {
// classMethods: {
// associate: function (models) {
// Viewer.Users = Viewer.hasMany(models.User, { as: 'users' });
// }
// },
timestamps: false
});
Viewer.Users = Viewer.hasMany(User, {as: 'users'});
update:
uses the same code as here to build the association dynamically
http://sequelize.readthedocs.org/en/1.7.0/articles/express/
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
db[modelName].associate(db);
}
});
@aweary when you use userType
for viewer, does it create a foreign key UserId
in all the associations. then what would you set for that field, as if there are many users in the system it can't bound to a single user id !!!
from graphql-sequelize.
@bsr203 make sure the associate method is actually called, it's likely not at that point in time.
@bsr203 i suggest you set your resolvers to not use associations and just do regular finds if that is your intention, i have no idea what you're actually looking to do here (ignore viewer?)
from graphql-sequelize.
thanks @mickhansen. I will go with your suggestion than expecting the magic :-)
the viewer is just a workaround for relay doesn't support connection at root level. Also, I may use VIewer to hold any information useful to the client if the viewer is authenticated.
Using this library, I was expecting to make use of pagination support, but I will look at how it's done.
from graphql-sequelize.
Pagination support is not fully implemented yet, currently relay will fetch all records and then do processing.
It's on our list to improve that of course :)
But graphql, relay and the combination here with Sequelize are all highly new and experimental so expect to get your hands dirty :)
from graphql-sequelize.
Related Issues (20)
- Combining multiple associations HOT 5
- Problem integrating connection types and dataloader for paginated (cursor) queries HOT 1
- When using `JSONType` I get `Error: One of the provided types for building the Schema is missing a name.` HOT 2
- Can we use `attributeFields` with graphql SDL? HOT 2
- How to express two way relationship HOT 2
- Change the default name of Date scalar HOT 3
- Relay Connections with Dataloader HOT 4
- Is this working with GraphQL 15? HOT 2
- sequelize model comment => graphql field description HOT 4
- CITEXT throws an issue in the latest version HOT 7
- Unable to convert geometry to graphql type HOT 1
- Are filtering operators supported? HOT 2
- OrderBy can conflicts with Attributes HOT 1
- Passing `where:` in-place, without query variable HOT 2
- Fix order type in defaultListArgs HOT 6
- Compatibility with GraphQL v17 HOT 1
- Peer dependency support for graphql 16 HOT 2
- OrderBy doesn't pass multiple to the query HOT 1
- Changing relay edges to be nonNull causes a node error HOT 3
- Use graphql-sequelize with dataloader-sequelize HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-sequelize.