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
}