P
Prisma4mo ago
Nik

[ADVANCED] Prisma Extensions - dynamic typing

I'm trying to create a $allModels extension with proper typing and have been struggling. This is what I was able to cobble together:
model: {
$allModels:{
async findOrCreate<T>(
this: T,
query: Prisma.Args<T, 'create'>['data']
):Promise< Prisma.Result<T, undefined, 'findFirstOrThrow'> >{
const ctx = Prisma.getExtensionContext(this);
let record = await (ctx as any).findFirst({where:query});
if(!record)
record = await (ctx as any).create({data:query});
return record;
},
}
}
model: {
$allModels:{
async findOrCreate<T>(
this: T,
query: Prisma.Args<T, 'create'>['data']
):Promise< Prisma.Result<T, undefined, 'findFirstOrThrow'> >{
const ctx = Prisma.getExtensionContext(this);
let record = await (ctx as any).findFirst({where:query});
if(!record)
record = await (ctx as any).create({data:query});
return record;
},
}
}
There are a few issues I want to resolve here: 1) There has to be some better typing for the ctx (or accessing the parent model). 2) I want to have an includes parameter, and return dynamic typing much like a regular .findFirst query. How can I achieve this? The only thing I can think of is that undefined Result generic which i can't seem to figure out what it does. Thanks
1 Reply
Nik
Nik4mo ago
Practically speaking, lets say I have
model A {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
b B?
}
model B {
id String @id @default(auto()) @map("_id") @db.ObjectId
a A @relation(fields: [a_id], references: [id])
a_id String @db.ObjectId @unique
}
model A {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
b B?
}
model B {
id String @id @default(auto()) @map("_id") @db.ObjectId
a A @relation(fields: [a_id], references: [id])
a_id String @db.ObjectId @unique
}
I want to be able to call prisma.a.findOrCreate({ data:{name:'hi'}, includes:{ b:true } }) solved 2)
async findOrCreate<T, A extends Prisma.Args<T, 'create'>>(
this: T,
queryArgs: Prisma.Args<T, 'findFirst'>,
createArgs: A
):Promise< Prisma.Result<T, A, 'create'> >{
const ctx = Prisma.getExtensionContext<T>(this);
let record = await (ctx as any).findFirst(queryArgs);
if(!record)
record = await (ctx as any).create(createArgs);
return record;
}
async findOrCreate<T, A extends Prisma.Args<T, 'create'>>(
this: T,
queryArgs: Prisma.Args<T, 'findFirst'>,
createArgs: A
):Promise< Prisma.Result<T, A, 'create'> >{
const ctx = Prisma.getExtensionContext<T>(this);
let record = await (ctx as any).findFirst(queryArgs);
if(!record)
record = await (ctx as any).create(createArgs);
return record;
}