Skip to content

Commit

Permalink
fix(client): query chaining then catch finally
Browse files Browse the repository at this point in the history
  • Loading branch information
millsp committed Feb 9, 2022
1 parent 3a25d0b commit 5d1dd5e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 8 deletions.
44 changes: 43 additions & 1 deletion packages/client/src/__tests__/integration/happy/chaining/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('chaining', () => {
`)
})

test('repeated calls to then', async () => {
test('repeated calls to .then', async () => {
const createPromise = prisma.user.create({
data: {
email: 'email@email.em',
Expand All @@ -136,6 +136,48 @@ describe('chaining', () => {
expect(createResult1).toStrictEqual(createResult2)
})

test('repeated calls to .catch', async () => {
const createPromise = prisma.user.create({
data: {
email: 'email@email.em',
},
})

// repeated calls to catch should not change the result
const createResult1 = await createPromise.catch()
const createResult2 = await createPromise.catch()

expect(createResult1).toStrictEqual(createResult2)
})

test('repeated calls to .finally', async () => {
const createPromise = prisma.user.create({
data: {
email: 'email@email.em',
},
})

// repeated calls to finally should not change the result
const createResult1 = await createPromise.finally()
const createResult2 = await createPromise.finally()

expect(createResult1).toStrictEqual(createResult2)
})

test('repeated mixed calls to .then, .catch, .finally', async () => {
const createPromise = prisma.user.create({
data: {
email: 'email@email.em',
},
})

// repeated calls to then & co should not change the result
const createResult1 = await createPromise.finally().then().catch()
const createResult2 = await createPromise.catch().finally().then()

expect(createResult1).toStrictEqual(createResult2)
})

beforeAll(async () => {
const PrismaClient = await getTestClient()
prisma = new PrismaClient()
Expand Down
12 changes: 5 additions & 7 deletions packages/client/src/runtime/core/request/createPrismaPromise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,21 @@ export function createPrismaPromise(
const otelCtx = context.active() // get the context at time of creation
// because otel isn't able to propagate context when inside of a promise

// we handle exceptions that happen in the scope as `Promise` rejections
let promise: PrismaPromise<unknown> | undefined
const _callback = (txId?: number, inTx?: boolean) => {
try {
return callback(txId, inTx, otelCtx)
// we allow the callback to be executed only one time
return (promise ??= callback(txId, inTx, otelCtx))
} catch (error) {
// if the callback throws, then we reject the promise
// and that is because exceptions are not always async
return Promise.reject(error) as PrismaPromise<unknown>
}
}

let promise: PrismaPromise<unknown> | undefined
return {
then(onFulfilled, onRejected, txId?: number) {
// we return same the result for repeated `then` calls
promise ??= _callback(txId, false)

return promise.then(onFulfilled, onRejected, txId)
return _callback(txId, false).then(onFulfilled, onRejected, txId)
},
catch(onRejected) {
return _callback().catch(onRejected)
Expand Down

0 comments on commit 5d1dd5e

Please sign in to comment.