Validating handwritten info objects in Prisma Bindings

prisma

#1

Hey!

I’m wondering if there is any way to validate handwritten queries passed instead of info in Prisma resolvers against the Prisma DB schema? In the following example, I have a User model that has a reference to a UserCredentials model. In the login resolver, I will find the UserCredential by the passed email, and find the relevant User 's ID from a handwritten query:

resolve: async (parent, { email, password }, ctx, info) => {
    const userCredentials = await ctx.db.query.userCredential({ where: { email } }, `{id password user {id}}`);
    ...
}

I would like to check queries like that against the db schema - how would I do that? :smiley:


#2

Hi @jhalborg

This was one of the reasons why we introduced the prisma client as you can’t really type the info object.

The real solution would be to use the client but I guess you like schema delegation very much so you are using bindings right now.

In the future, we will release prisma nexus which will introduce a new API which will give you a more powerful way to expose stuff compared to prisma bindings. https://github.com/prisma/nexus-prisma


#3

@pantharshit00 - Thanks for getting back to me :slight_smile:

We have a fairly large project already that uses bindings, and I find bindings to be one of the primary reasons for using Prisma in the first place - being able to pass the client’s info object, sometimes enhanced/modified, to Prisma is awesome! The client is cool if you just need one model, but often times, we needs data from multiple tables/models, which would require multiple Client queries - or using fragments:

We could continue to use bindings to return payloads to our users, but use the client for db access in resolvers where we just need to query the DB before returning anything. To continue with the example above where we’re trying to log in a user, it would be something like:

resolve: async (parent, { email, password }, ctx, info) => {
    // Do DB call using the Prisma Client
    const credentialFragment = `fragment UserCredentailInfo on UserCredential {id password user {id}}`
    const userCredentials = await ctx.prismaclient.userCredentials({ where: { email }}).$fragment(credentialFragment);

    // Validate credentials

    // Use bindings to return data to the user, using the client's info object
    return ctx.db.query.user({where:{id:userCredentials.user.id}}, info)
    ...
}

But that leads to the exact same problem, doesn’t it? Now I have an untyped fragment, just as I had to begin with.

In both cases, it seems to me that all the building blocks for validation are there. We have a query, and a schema to validate the query against - we must be able to do it somehow?


#4

@pantharshit00 - Do you have any advice/measurements/data regarding if it’s faster to resolve a Prisma generated query that hits, say, 4 models in one query, or performing four queries to fetch that data? ORMs are notorious for generating slow-to-resolve queries to databases once the queries gets just a little complex.

If four separate queries is faster, then the tradeoff would instead be that it requires more server code to match up the data.

Let’s say for example that I need to fetch

  • The user’s name from one model
  • The user’s credentials from another
  • The user’s posts from another
  • The user’s address from another

You could do that with bindings/client+fragment in one query, but that would be untyped. You could also have it statically typed, and perform four queries, but then you’d have to manually sync up those datasets to do logic on them.

Which path do you recommend?


#5

HI again @jhalborg

Sorry for the late reply. If you want a quicker reply please DM me over at slack as I am more active there.

But that leads to the exact same problem, doesn’t it? Now I have an untyped fragment , just as I had to begin with.

We are aware of this problem and we are going to have a new select API in prisma client v2 which will create dynamic type results. Here is the RFC for it: https://github.com/prisma/rfcs/blob/new-ts-client-rfc/text/0000-new-ts-client.md

You could do that with bindings/client+fragment in one query, but that would be untyped.

I think will get also solved by the new client as you will be able to select the required fields. But right now I will recommend to use fragment/bindings path as it will result into one single query document to the prisma server and prisma server will internally optimise sql queries for this type of data fetching.

Situation right now is a bit tricky but I expect this will get resolved soon. :slightly_smiling_face:


#6

Thanks again @pantharshit00 ,

So in client v2, I’d be able to fulfill the example above by doing something like:

  const userWithExtras: DynamicResult = await prisma.users.findOne({
    where: 'userid',
    select: {
      credentials: { select: { email: true } },
      posts: { ... },
      address: { ... },
    }
  })

and that would fetch the data from all those tables, fully typed, in one query? Because if that’s the case, then that is exactly what I’m hoping for :smiley: Is there any ETA for client v2?


#7

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.