-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue with prisma.$kysely transaction #71
Comments
Which version of the extension are you using? I'll dive in and investigate once I know! |
I'm using the last version: 2.1.0
To a simpler way:
No errors occurs during the transaction. We had an issue of transaction that were rollbacked but not those specific data which are the one where I use the extension to update. I've checked the code and I'm not a pro of prisma extension but it seems that is is taking the prisma client in the constructor and executing query with it. EDIT: after a few investigation, I've been trying to get an object id for what is used and it in fact uses the transaction client as expected, but I always have this error: 'Transaction API error: Transaction already closed: A query cannot be executed on a committed transaction.', I don't have this error if I'm using the tx.$queryRawUnsafe myself and I have a normal constraint failure. |
Thanks for the additional info! Can you create a repo with a minimal reproducible example of the issue so I can dig in and see what I can do? |
Here you go: |
I maybe got an idea of what the problem could be. Is it possible that in case I have two transactions in parrallel, the wrong client is used for making queries ? Because I have an unique Prisma client extended but I can have multiple transaction at the same time. Is the driver attaching to each transaction client the good prisma client. I'll try to do test looking for this particular issue. |
After investigation, I can definitely reproduce this issue with a simple example: here two kysely get that I parametrized with parameters I know. I've added a function to get an unique id for an object and you see that the first two get are corrects, but after this, the two gets are using the same transaction client.
|
Hi, this is a really handy extension, thank you. Unfortunately, I can confirm. Wrong transaction or no transaction is effectively used. You can repro this by setting some constraints like CHECK/UNIQUE on the column and seed the DB so the next update/insert would violate the constraint. This can be done with a query before the tx. Then create 2 queries inside the transaction:
If you do it all in Prisma or Kysely alone - all good. If you run the first query with Prisma and the second with Kysely, then Kysely does not see the results from the first query and will report a constraint violation. So seems like Kysely sees different snapshot of the DB and is either in a different explicit transaction than Prisma query or none at all. I advise to not mix the clients for single transaction here until it is resolved. |
I ended up doing my functions and not using this prisma-extension-kysely at all for this
|
Hello guys, ✅ Working exampleIn conclusion, the following code should work as intended. const prisma = new Prisma();
const xprisma = prisma.$extends( /* with kyselyExtension */ );
await xprisma.$transaction(async (tx) => {
// Insert by Prisma
await tx.model.create({ data: { name: "Jhon" } });
// Select by Kysely -> You can find Jhon
await tx.$kysely.selectFrom("model").selectAll().execute();
}); 🤷♂️ Not working exampleIn my case, it did not work because I had implemented the following: // I was use prisma-extension-kysely with PrismaService via NestJS
class PrismaService extends PrismaClient {
constructor() {
super();
}
get $kysely() {
return this
.$extends( /* with kyselyExtension */ )
.$kysely;
}
}
const prisma = new PrismaService();
await prisma.$transaction(async (tx) => {
// Insert by Prisma
await tx.model.create({ data: { name: "Jhon" } });
// Select by Kysely -> ❗ You CAN NOT find Jhon
await tx.$kysely.selectFrom("model").selectAll().execute();
}); In this case, In other words, $extends should be called only once in a process. |
As a side note, I'll write a more concrete implementation in NestJS I would be happy If it helps you. 👍 ✅ Minimum PrismaService example@Injectable()
export class PrismaService extends PrismaClient {
private constructor(config: ConfigService) {
super();
// init with config
}
/**
* @see https://github.com/eoin-obrien/prisma-extension-kysely
* @see https://github.com/eoin-obrien/prisma-extension-kysely/issues/71
*/
static withKysely(config: ConfigService) {
return new PrismaService(config).$extends(
kyselyExtension({
kysely: (driver) => {
return new Kysely<DB>({
dialect: {
createDriver: () => driver,
createAdapter: () => new PostgresAdapter(),
createIntrospector: (db) => new PostgresIntrospector(db),
createQueryCompiler: () => new PostgresQueryCompiler(),
},
});
},
})
) as unknown as PrismaService;
}
/** Don't forget it */
declare $kysely: Kysely<DB>;
} ✅ PrismaModule example@Module({
imports: [ConfigModule],
providers: [
{
provide: PrismaService,
inject: [ConfigService],
useFactory: (config: ConfigService) => {
return PrismaService.withKysely(config);
},
},
],
exports: [PrismaService],
})
export class PrismaModule {} |
Hi,
I am not sure but after a few weeks using your extension, It don't seems that it support prisma transaction, is this the case ?
I am expecting that when I do an interactive transaction it use the transaction that prisma created but it doesn't seems to work...
Is this not supported ?
The text was updated successfully, but these errors were encountered: