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

Resolving connections without relationships? #26

Open
sgwilym opened this issue Sep 27, 2017 · 2 comments
Open

Resolving connections without relationships? #26

sgwilym opened this issue Sep 27, 2017 · 2 comments

Comments

@sgwilym
Copy link
Contributor

sgwilym commented Sep 27, 2017

Hey! I'm in the process of making a simple, single user blog. I have a Post type, and I'd like to expose a PostsConnection from Session so that I can just grab however many posts I'd like to render a front page (using all the standard first/last/after/etc args). But because Session doesn't have a real presence in the DB, it seems weird to put a @relationship directive on Session — and even then, it doesn't work.

I'd still like to use the gestalt-provided way for resolving a connection, though, so how can I do this from the Session type?

Also, apropos of nothing, I'm floored by the level of care put into this repo, it's so well put together!

@charlieschwabacher
Copy link
Owner

Hey Sam - great point, making a relay connection of all of some type feels like a really common use case, and the way you would have to do it now is to define connection and edge types manually, and then define resolution either entirely manually or using graphql-relay-js helpers.

Something like:

type Session {
  posts(first: Number, before: String, last: Number, after: String): PostsConnection
}
type Post implements Node {
  id: ID!
  text: String
}
type PostsConnection {
  edges: [PostEdge]
  pageInfo: PageInfo
}
type PostEdge {
  node: Post
  cursor: String
}
import { connectionFromPromisedArray } from 'graphql-relay';

export default {
  posts: (obj, args, context) =>
     // maybe paginate in a more efficient way here :)
     connectionFromPromisedArray(context.db.query('SELECT * FROM posts')),
};

There are a few ways I can imagine supporting this.

The first is to add an @all field directive, which would generate connection and edge types and add resolution similarly to relationships.

type Session {
  posts: Post @all
}

This feels pretty clean to me, but it falls apart if you want to filter the results (ie: SELECT * FROM posts WHERE published = true) so it might require some kind of filtering to be added to the directive.

type Session {
  posts: Post @all(where: {published: true})
}

The other is to add connection resolution to the gestalt-graphql query helper - something like a connectionBy(table: string, conditions: Object, args: ConnectionArgs): Promise<Connection>. This has the drawback of leaving the syntax up to the database adapter, but keeps the directive API smaller which I think is valuable.

It could maybe be paired w/ auto creation of any referenced connection and edge types, giving us:

type Session {
  posts: PostsConnection
}
export default {
  posts: (obj, args, context) =>
    context.db.connectionBy('posts', { published: true }, args)),
};

What do you think? does one of those feel more friendly than the other? Or do you another idea about how it should work?

@sgwilym
Copy link
Contributor Author

sgwilym commented Oct 2, 2017

There's a couple of 'ideal' APIs I can imagine depending on how much you want. I think there are three scenarios you'd need to cover. The first two you've suggested above already.

  1. The simplest case is if you just need a straight Relay connection with no frills. The nicest way I think would be the closest to straight GraphQL definition:
type Session {
  posts: PostsConnection
}

And that's it.

  1. You want just a straight Relay connection, but want to constrain the returned results by some condition (eg. whether a post is published or not). That would be like your suggestion above:
type Session {
  posts: PostsConnection
}
export default {
  posts: (obj, args, context) =>
    context.db.connectionBy('posts', { published: true }, args)),
};
  1. You want all of the above and you want to add another argument (e.g. to get a post by which category it's in). There are two questions here which are 'how do I define the arguments?' and
type Session {
  posts(catgeory: String): PostConnection
}
export default {
  posts: (obj, args, context) =>
    context.db.connectionBy('posts', { published: true, category: args.category }, args)),
};

So yeah, thinking this through, it feels like your last suggestion combines the best of all worlds, from the simplest to the most complex case - while still giving a nice API for it.

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

2 participants