Server returning different data to client when using nested Prisma 'take' (Relations/Resolver issue)

Hey team,

Trying to wrap my head around some interesting behaviour when attempting to use prisma’s “take” within nested queries. Seems like a resolver issue with GraphQL or some generated type that’s going on under the hood.

What I am trying to do is receive the most recent price from a nested field by using prisma’s ‘orderBy’ and ‘take’.

Long story short, what I see in the console logs on the server, isn’t what is being returned to the client.

The logs in the server are showing me one price (which is the latest) in an array of ‘productPrice’, but when returned to the client or through postman, I get all of the prices in an array and not in desc ‘createdAt’ order.

I have tried removing the relation resolvers from product and then the client will receive only one price , as if the take and orderBy have worked successfully (intended behaviour). When removed, my other query - shopQuery will return products, but productPrice will be null. If I reintroduce the resolver, it will then return all the prices meaning the take and orderBy have not worked.

Another test I tried was to create a new type for ‘Product’ (eg - ‘ProductWithPrice’) with all the same fields and then use that as the return type for the Query in the SDL. The client would then receive only one price, but again trying to do ‘shopQuery’ (one more nesting) seems to refer back to the ‘Product’ type and then returns all the prices.

Has anyone had similar behaviour to this or any advice on customising resolvers that Redwood generates so that I can use this kind of logic. It would be very nice to use the take and orderBy through the application as it’s a clean way of returning the most current price.

Appreciate any help, if you need anymore information let me know.

(Also, I have modified the table names/services for this question, I am confident it’s a background resolver thing, so if you see some odd syntax it may just be a refactor error on my part, apologies)

Services

export const productsWithLatestPrice: QueryResolvers['productsWithLatestPrice'] =
  async () => {
     const products = await db.product.findMany({
      include: {
        productPrice: {
          orderBy: { createdAt: 'desc' },
          take: 1,
        },
      },
    })
    console.log('products', JSON.stringify(products, null, 2))

    return products
  }
  export const shopQuery: QueryResolvers['shopQuery'] = async ({ id }) => {
    const shop = await db.shop.findUnique({
      where: { id },
      include: {
        products: {
          include: {
            productPrice: {
              orderBy: { createdAt: 'desc' },
              take: 1,
            },
          },
        },
      },
    })
    console.log('dimSeason', JSON.stringify(shop, null, 2))
    
    return shop
  }

RelationResolvers

export const Product: ProductRelationResolvers = {
  productPrice: (_obj, { root }) => {
    return db.Product.findUnique({ where: { id: root?.id } }).productPrice()
  },
}

Prisma Schema:

model Shop {
  id              Int                   @id @default(autoincrement())
  name            String
  createdAt       DateTime              @default(now())
  updatedAt       DateTime              @updatedAt
  deletedAt       DateTime?
  products        Product[]
}

model Product {
  id              Int                   @id @default(autoincrement())
  name            String
  createdAt       DateTime              @default(now())
  updatedAt       DateTime              @updatedAt
  deletedAt       DateTime?
  shopId          Int?
  shop          Shop?            @relation(fields: [shopId], references: [id])
  productPrice    ProductPrice[]
}

model ProductPrice {
  id            Int         @id @default(autoincrement())
  productId     Int?
  product       DimProduct? @relation(fields: [productId], references: [id])
  price         Float?
  createdAt     DateTime    @default(now())
}

SDL

// note - these are in their relevant sdl files

type Shop {
  id: Int!
  name: String!
  createdAt: DateTime
  deletedAt: DateTime
  updatedAt: DateTime
  products: [Product]
}

type Product {
  id: Int!
  name: String!
  shopId: Int
  shop: Shop
  createdAt: DateTime
  deletedAt: DateTime
  updatedAt: DateTime
  productPrice: [ProductPrice]
}

type ProductPrice {
  id: Int!
  productId: Int
  product: DimProduct
  price: Float
  createdAt: DateTime!
}

  type Query {
    productsWithLatestPrice: [Product!]! @requireAuth
  }

  type Query {
     shopQuery:[Shop]! @requireAuth
  }

Hi @adomaa I wrote up some info on how relation resolvers work in comparison to the regular query resolvers here: Why each GraphQL Object type has both "Resolver" and "RelationResolver" types?

Might that help here?

Thanks @dthyresson , that was exactly what I was searching for. Not sure how I missed your post in my search.

Appreciate it