I’ve read the article and all of the docs on Prism...
# orm-help
l
I’ve read the article and all of the docs on Prisma Client — I’m not understanding the value proposition over prisma-binding. It looks like the query/mutation type was chopped off and specific data can be fetched by chaining methods instead of the awkward
{ id users { id ...} }
string. Am I understanding it??
s
Good question @lawjolla! The general idea was to iterate based on our learnings from Prisma bindings which were: 1) People want to also use Prisma outside of the realm of building GraphQL servers -> we need to have something that’s “GraphQL agnostic” 2) The generation of bindings was too difficult -> Now you can used
prisma generate
3) You had to drop back to raw GraphQL to query related data. -> Now you can use the relational fluent API Does this make it clearer?
l
Thanks @schickling! It does. You raised those points in the article, but the rehash here was clear. I’m not seeing the value because 1. I don’t need GraphQL agnostic 2. I think the Prisma binding (and graphql binding in general) is straight forward 3. And that’s the value I saw. Reminds me a little of RethinkDB’s ReQL language. From the post, it seems like Bindings are first still class citizens and will be actively developed. So there’s no need for migration, correct?
s
Makes sense! I’d still encourage you to check it out. The relational fluent API is a huge improvement which unfortunately we cannot backport to bindings. We’ve also added
$delegate
support to the client, so it’s easy to migrate if you’d want. Would love to hear your feedback once you’ve tried it though!
l
Is this a good place for the feedback? Here's what I'm not getting... From the example, say that we expanded
User
with likes..
Copy code
type User {
  id: ID!
  email: String
  name: String!
  posts: [Post!]!
  likes: [Like!]!
}
With bindings, you could still use the
postsByUser
resolver with
info
and get
likes
returned...
Copy code
postsByUser(root, args, context, info) {
      return context.prisma.query.user({ where: {
        id: args.userId
      }}, info)
    }
But the new Prisma Client, that doesn't seem possible. I'd need to make type resolvers for practically everything. What am I missing?
m
Thank you for this question and explanation. The fluent API looks badass. Can this also be used with resolver forwarding, ie
posts: forwardTo('db')
?
@lawjolla I found an example here. https://github.com/nikolasburk/prisma-client-examples/blob/master/generated/prisma.ts From looking at that, it appears that your above example would be:
Copy code
postsByUser(root, args, context, info) {
      return context.prisma.delegate.query.user({ where: {
        id: args.userId
      }}, info)
    }
Basically,
prisma.delegate
is the old prisma-bindings API
l
Thanks, nice work @Mike! I set up a test project where Prisma Client and Bindings are both working and can confirm it returns the same thing.
But if you look at the resolvers for Prisma Client, they are much more complex. It feels like a big step backwards. It’s hard enough explaining type resolvers — now they’ll need to be everywhere. https://www.prisma.io/docs/get-started/03-build-graphql-servers-with-prisma-e001/
m
I’m not sure what you mean by the resolvers being more complex. If you’re talking about the resolvers in apollo-server/graphql-yoga, I think they’re the same as before
l
Look at the example and note all of the type resolvers that are now required
m
Oh, I see, you’re talking about the new resolvers for
User.posts
and
Posts.author
, right? I think those can be skipped just by doing this. Just like before.
Copy code
return context.prisma.$delegate.user({
  where: id: args.userId,
}, info);
The only reason they’re adding all those boilerplate resolvers is because the new fluent API only returns scalar fields by default, just like prisma-binding does when you don’t pass anything for the
info
prop. So because the root resolver returns an incomplete object, you need the secondary resolver to clean up its mess. All that nonsense can be avoided if you just stick to the old way of doing things with $delegate.
l
We’re on the same page. Totally right. So it feels like a step backwards. I’m trying to understand the benefit for this increased pain.
m
Oh, it reduces pain a lot in custom scripts or places where you don’t have an
info
prop. Because then I have to create a custom string to pass as info with something like this:
Copy code
const chatRooms = await prisma.query.chatRooms({
      where: {
        city: { users_some: usersInput },
        messages_some: {
          createdAt_gte: cutoffTime,
          sender: usersInput,
        },
      },
    }, `{
      id
      earliestMessage: messages(where: {
        sender: { id_in: ${JSON.stringify(cluster)} }
      }, orderBy: createdAt_ASC, first: 1) {
        createdAt
      }
    }`);
l
Ok, true, I have similar madness too.
m
That whole earliestMessage thing could be avoided by using the new fluent API
l
So is it made to work with
$delegate
because it feels like that’s just a bridge / escape hatch
I guess my question is why wouldn’t they use
$delegate
for the beginner example?
m
I think you’re right. It is the bridge/escape hatch for what they’re calling “advanced use cases”. I think it’s not actually that advanced
l
Agreed. To the contrary, when there are multiple nested fields per type, the type resolvers will be a mess. It seems like
$delegate
is the default and the “Client” (sans $delegate) is the exception for most CRUD apps
m
Agreed. The $delegate will remain my go-to option and the fluent API will be for my advanced use cases. They probably have enterprise customers who are looking for the fluent-style API because it’s easier to integrate into existing apps whereas schema delegation is better-suited to apps that are porting over from the Graphcool world.
l
Interesting. Thanks for your insight! I’m going to post on the forum to see if I can get some more voices.
m
Actually, I might just stick the $delegate onto my context in place of my existing
context.db
. That way I don’t have to change any existing code and I can add
context.prisma
for the new cases where I need that.
l
… that’s genius. I didn’t think of that.
I was going to run the binding and client together. Thanks for the better route.