DEV Community

Mehrad Rousta
Mehrad Rousta

Posted on

8 1

Nested Queries in Prisma Client

These days I'm working on a new project in the workplace which is the first project I work on that is built on Prisma and Yoga. I worked with Prisma before on the days that the only way to access Prisma was Prisma Bindings. but at this new project, we were using Prisma Client.

Imagine this project we have here is a social media app with these models:

type User {
  id: ID! @id
  email: String! @unique
  password: String!
  username: String @unique
  fullName: String!
  role: [UserRole]!
  settings: UserSetting @relation(name: "UserSettings" link: INLINE)
  following: [User] @relation(name: "UserFollowings" link: INLINE)
  createdAt: DateTime! @createdAt
  updatedAt: DateTime! @updatedAt
}

As it's mentioned here and here, with Prisma Bindings we could use something like this for our queries to get all the nested queries we wanted:

// Prisma Bindings
me(parent, args, { prisma, request }, info) {
  const userId = getUserId(request)
  return prisma.query.user({
    where: {
      id: userId
    },
    info
  });
}

which by passing info, the Prisma query would notice what fields it must fetch from the database.

but when I was looking in my code, my Prisma query only had one parameter which was the filter/sort object. so I handled it this way:

// Prisma Client
 async user(_, __, ctx: IContext) {
    const user = await ctx.db.user({ id: ctx.user.id });
    // Getting userSettings because apparently `ctx.db.user` won't give it
    const [userSettings] = await ctx.db.userSettings({ where: { user: { id: ctx.user.id } } });
    return { ...user, settings: userSettings };
  },

But there is a problem, this method is ok on single queries but won't work on list queries:

  async users(_, __, ctx: IContext) {
    return await ctx.db.query.users();
  },

In my front-end, when I was using this users query, I wasn't getting for example user.following relational data.

the workaround for this is $fragment API explained in Prisma docs:

Instead of querying all scalar fields of a record (which is the default behavior), you can specify which fields you'd like to retrieve by using the $fragment API. This is useful to exclude large unneeded fields (like BLOB values or huge strings). It also lets you fetch arbitrary relations.

so the code would be rewritten like this:

async users(_, __, ctx: IContext) {
  const fragment = `
    fragment UserWithFollowings on User {
      id
      fullName
      email
      following {
        id
        email
      }
    }
  `;
  return await ctx.db.query.users().$fragment(fragment);
},

The docs is saying there will be a next version of the Prisma client API that has an improved and type-safe API to select fields but I couldn't find more information about it. if you have any information about it and want to share, i would be very happy!

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (2)

Collapse
 
dannytlake profile image
dannytlake

I'm curious on how you'd use a fragment combined with a filter? I am new and reading the docs, but it seems to me that with the Prisma client you can either use a filter, or a fragment, but not both at the same time?

Collapse
 
sturmenta profile image
sturmenta

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay