i have schema that looks like:
schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
model User {
id String @id @default(cuid())
email String? @unique
stripeId String @unique
createdAt DateTime @default(now())
product Product?
@@map("users")
}
model Product {
id String @id @default(cuid())
totalSum Int @default(9700)
user User @relation(fields: [userId], references: [id])
userId String @unique
licenses License[]
@@map("products")
}
model License {
id String @id @default(cuid())
name String @unique
/// no. of licenses generated
total Int @default(1)
/// no. of licenses used
used Int @default(0)
/// stored in cents
product Product? @relation(fields: [productId], references: [id])
productId String?
createdAt DateTime @default(now())
@@map("licenses")
}
i want to access email
field while doing prisma.license.findMany()
. my db
file looks like:
db.ts
import { Prisma, License, User } from '@prisma/client'
import { prisma } from './context'
export const getLicenses = async (): Promise<
Array<License & Pick<User, 'email'>> | null | undefined
> => {
const userSelect = Prisma.validator<Prisma.ProductSelect>()({
user: {
select: {
email: true,
},
},
})
const productSelect = Prisma.validator<Prisma.LicenseSelect>()({
product: {
include: userSelect,
},
})
const licenses = await prisma.license.findMany({
orderBy: {
createdAt: 'desc',
},
include: productSelect,
})
const result = licenses.map((license) => {
const email = license.product?.user.email
if (email) {
return {
...license,
email,
}
}
})
return result
}
export const db = {
getLicenses,
}
the last line return result
gives this typescript error:
Type '({ email: string; id: string; name: string; total: number; used: number; productId: string | null; createdAt: Date; product: (Product & { user: { email: string | null; }; }) | null; } | undefined)[]' is not assignable to type '(License & Pick<User, "email">)[]'.
Type '{ email: string; id: string; name: string; total: number; used: number; productId: string | null; createdAt: Date; product: (Product & { user: { email: string | null; }; }) | null; } | undefined' is not assignable to type 'License & Pick<User, "email">'.
Type 'undefined' is not assignable to type 'License & Pick<User, "email">'.
Type 'undefined' is not assignable to type 'License'.ts(2322)
my schema file looks like:
schema.ts
import { db } from './db'
const Query = objectType({
name: 'Query',
definition(t) {
t.list.field('licenses', {
type: 'License',
resolve: async (_, __, ctx) => {
if (!ctx.admin.isLoggedIn) return null
const licenses = await db.getLicenses()
if (licenses) return licenses
return null
},
})
},
})
even this little query is causing me a lot of errors. it used to work when i wanted to query all of licenses using prisma.license.findMany()
but it started throwing errors as soon as i wanted email
field but in a flat file format so my output looks like:
{
id: string;
name: string;
total: number;
used: number;
productId: string | null;
createdAt: Date;
email: string;
}
i also don't want productId
to be sent. how can i solve this?
i've made a minimal repro → https://github.com/deadcoder0904/prisma-nested-query-email
CodePudding user response:
When you use Array.map, if you don't explicitly specify the return for every element, then undefined
will make its way into your array - which is what your TS error is indicating. If (!email), then map returns an undefined
element to the output array.
Essentially, what you want is to filter those licenses that have an associated user with an email, and THEN map it.
You can actually do this with reduce instead. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#replace_.filter.map_with_.reduce
You're trying to use Array.map LIKE this Array.reduce functionality (which can replace filter/map). But undefined can't sneak into the returned array if you implement with Array.reduce.
Here's a relevant CodeSandbox link. Note that eslint is complaining (expected to return a value at the end of arrow function). https://codesandbox.io/s/nifty-surf-s8vcg6?file=/src/index.ts
CodePudding user response:
I disabled TS on the db.ts
file & then checked results
array & figured out I needed to have email
as null
instead of undefined
.
One important note: I had to stop using nonNull
for email
in nexus
configuration of type License
to stop the error.
The working solution is posted in this commit. It works now :)