47ng / prisma-field-encryption

Transparent field-level encryption at rest for Prisma
https://github.com/franky47/prisma-field-encryption-sandbox
MIT License
239 stars 28 forks source link

`Argument of type '() => Promise<void>' is not assignable to parameter of type 'PrismaPromise<any>[]'.` when using `prisma.$transaction` after extending client #116

Closed tuarrep closed 1 month ago

tuarrep commented 1 month ago

The client is initialized like this:

const client = new PrismaClient({
    log: ["query"],
  })
.$extends(fieldEncryptionExtension());

Next, we use interactive transactions :

await prisma.$transaction(async () => {
    await prisma.beneficiary.update({
      where},
      data,
    });

    await prisma.invitation.update({
      where,
      data,
    });
  });

No problem before extending client with fieldEncryptionExtension() and this error after:

- error TS2345: Argument of type '() => Promise<void>' is not assignable to parameter of type 'PrismaPromise<any>[]'.

98   await prisma.$transaction(async () => {
                               ~~~~~~~~~~~~~

    at createTSError (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:859:12)
    at reportTSError (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:863:19)
    at getOutput (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:1077:36)
    at Object.compile (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:1433:41)
    at Module.m._compile (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:1617:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1551:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/nicolas/Dev/xxx/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1282:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1098:12)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14) {
  diagnosticCodes: [ 2345 ]
}

Versions:

franky47 commented 1 month ago

What happens if you use the first argument of your transaction callback as the Prisma client? This is the way I've always seen it done in the docs and examples:

await prisma.$transaction(async (tx) => {
    await tx.beneficiary.update({
      where},
      data,
    });

    await tx.invitation.update({
      where,
      data,
    });
  });
tuarrep commented 1 month ago

Thanks for pointing this out.

Unfortunately, it causes the same Typescript error.

Even when trying to type tx as PrismaClient

franky47 commented 1 month ago

I just realised I had had this issue before, and opened one upstream on Prisma: https://github.com/prisma/prisma/issues/20326.

In the mean time, I fixed it internally by casting the extended client type back to the original one. Since prisma-field-encryption acts transparently with regards to queries and mutations, the type annotation is safe just for this extension (ie: if you do an extension chain, you might want to tweak the type you are casting to, or use an intermediate variable).

https://github.com/47ng/prisma-field-encryption/blob/8e4769abbb015bb224623bbde09361f822adbeea/src/tests/prismaClient.ts#L21

Edit: also relevant discussion for additional context: https://github.com/47ng/prisma-field-encryption/issues/63#issuecomment-1641069357

tuarrep commented 1 month ago

Thanks, François, casting after extending has resolved the problem!

I think we may close this issue?