Skip to content

Commit 839f215

Browse files
authored
refactor: extract reusable parts of the client engine into a new package (#26330)
`@prisma/client-engine-runtime` being built by `@prisma/client`'s build script meant that we still needed to include the client package and all of its transitive dependencies into the workspace in `libs/driver-adapters` in the `prisma-engines` repo, which was causing some issues. This commit properly extracts the reusable parts of the client engine into a package for real. This is also important to make Accelerate work with the query compiler. Additionally, `@prisma/debug` is changed to be ESM compatible. This is because `@prisma/client-engine-runtime` needs to be ESM compatible and depends on `@prisma/debug`.
1 parent 16be4b0 commit 839f215

27 files changed

+351
-251
lines changed
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
// this package is actually built by `@prisma/client`
1+
import { build } from '../../../helpers/compile/build'
2+
import { adapterConfig } from '../../../helpers/compile/configs'
3+
4+
void build(adapterConfig)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
preset: '../../helpers/test/presets/default.js',
3+
}

packages/client-engine-runtime/package.json

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,42 @@
22
"name": "@prisma/client-engine-runtime",
33
"version": "0.0.0",
44
"description": "This package is intended for Prisma's internal use",
5-
"type": "module",
65
"main": "dist/index.js",
6+
"module": "dist/index.mjs",
77
"types": "dist/index.d.ts",
8+
"exports": {
9+
".": {
10+
"require": {
11+
"types": "./dist/index.d.ts",
12+
"default": "./dist/index.js"
13+
},
14+
"import": {
15+
"types": "./dist/index.d.mts",
16+
"default": "./dist/index.mjs"
17+
}
18+
}
19+
},
820
"repository": {
921
"type": "git",
1022
"url": "https://github.com/prisma/prisma.git",
1123
"directory": "packages/accelerate-contract"
1224
},
1325
"license": "Apache-2.0",
14-
"dependencies": {},
26+
"dependencies": {
27+
"@prisma/debug": "workspace:*",
28+
"@prisma/driver-adapter-utils": "workspace:*"
29+
},
30+
"devDependencies": {
31+
"@types/jest": "29.5.14",
32+
"@types/node": "18.19.31",
33+
"jest": "29.7.0",
34+
"jest-junit": "16.0.0"
35+
},
1536
"scripts": {
1637
"dev": "DEV=true tsx helpers/build.ts",
1738
"build": "tsx helpers/build.ts",
18-
"prepublishOnly": "pnpm run build"
39+
"prepublishOnly": "pnpm run build",
40+
"test": "jest"
1941
},
2042
"files": [
2143
"dist"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type QueryEvent = {
2+
timestamp: Date
3+
query: string
4+
params: unknown[]
5+
duration: number
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export type { QueryEvent } from './events'
2+
export { QueryInterpreter, type QueryInterpreterOptions } from './interpreter/QueryInterpreter'
3+
export * from './QueryPlan'
4+
export {
5+
IsolationLevel,
6+
type TransactionInfo,
7+
type Options as TransactionOptions,
8+
} from './transactionManager/Transaction'
9+
export { TransactionManager } from './transactionManager/TransactionManager'
10+
export { TransactionManagerError } from './transactionManager/TransactionManagerErrors'

packages/client/src/runtime/core/engines/client/interpreter/QueryInterpreter.ts renamed to packages/client-engine-runtime/src/interpreter/QueryInterpreter.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Query, Queryable } from '@prisma/driver-adapter-utils'
22

3-
import { QueryEvent } from '../../common/types/Events'
3+
import { QueryEvent } from '../events'
44
import { JoinExpression, QueryPlanNode } from '../QueryPlan'
55
import { renderQuery } from './renderQuery'
66
import { PrismaObject, ScopeBindings, Value } from './scope'
7-
import { serialize } from './serializer'
7+
import { serialize } from './serialize'
88

99
export type QueryInterpreterOptions = {
1010
queryable: Queryable
@@ -158,16 +158,7 @@ export class QueryInterpreter {
158158
timestamp,
159159
duration: endInstant - startInstant,
160160
query: query.sql,
161-
// TODO: we should probably change the interface to contain a proper array in the next major version.
162-
params: JSON.stringify(query.args),
163-
// TODO: this field only exists for historical reasons as we grandfathered it from the time
164-
// when we emitted `tracing` events to stdout in the engine unchanged, and then described
165-
// them in the public API as TS types. Thus this field used to contain the name of the Rust
166-
// module in which an event originated. When using library engine, which uses a different
167-
// mechanism with a JavaScript callback for logs, it's normally just an empty string instead.
168-
// This field is definitely not useful and should be removed from the public types (but it's
169-
// technically a breaking change, even if a tiny and inconsequential one).
170-
target: 'QueryInterpreter',
161+
params: query.args,
171162
})
172163

173164
return result

packages/client/src/__tests__/runtime/engines/client/serialize.test.ts renamed to packages/client-engine-runtime/src/interpreter/serialize.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ColumnTypeEnum } from '@prisma/driver-adapter-utils'
22

3-
import { serialize } from '../../../../runtime/core/engines/client/interpreter/serializer'
3+
import { serialize } from './serialize'
44

55
test('should serialize empty rows', () => {
66
const result = serialize({

packages/client/src/runtime/core/engines/client/interpreter/serializer.ts renamed to packages/client-engine-runtime/src/interpreter/serialize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ResultSet } from '@prisma/driver-adapter-utils'
1+
import type { ResultSet } from '@prisma/driver-adapter-utils'
22

33
export function serialize(resultSet: ResultSet): Record<string, unknown>[] {
44
return resultSet.rows.map((row) =>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export const enum IsolationLevel {
2+
ReadUncommitted = 'ReadUncommitted',
3+
ReadCommitted = 'ReadCommitted',
4+
RepeatableRead = 'RepeatableRead',
5+
Snapshot = 'Snapshot',
6+
Serializable = 'Serializable',
7+
}
8+
9+
export type Options = {
10+
maxWait?: number
11+
timeout?: number
12+
isolationLevel?: IsolationLevel
13+
}
14+
15+
export type TransactionInfo = {
16+
id: string
17+
}
Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import type {
99
} from '@prisma/driver-adapter-utils'
1010
import { ok } from '@prisma/driver-adapter-utils'
1111

12-
import { PrismaClientKnownRequestError } from '../../../errors/PrismaClientKnownRequestError'
13-
import type * as Tx from '../../common/types/Transaction'
14-
import { IsolationLevel } from '../../common/types/Transaction'
12+
import { IsolationLevel, Options } from './Transaction'
1513
import { TransactionManager } from './TransactionManager'
1614
import {
1715
InvalidTransactionIsolationLevelError,
@@ -83,7 +81,7 @@ class MockDriverAdapter implements DriverAdapter {
8381
}
8482
}
8583

86-
async function startTransaction(transactionManager: TransactionManager, options: Partial<Tx.Options> = {}) {
84+
async function startTransaction(transactionManager: TransactionManager, options: Partial<Options> = {}) {
8785
const [{ id }] = await Promise.all([
8886
transactionManager.startTransaction({
8987
timeout: TRANSACTION_EXECUTION_TIMEOUT,
@@ -97,7 +95,7 @@ async function startTransaction(transactionManager: TransactionManager, options:
9795

9896
test('transaction executes normally', async () => {
9997
const driverAdapter = new MockDriverAdapter()
100-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
98+
const transactionManager = new TransactionManager({ driverAdapter })
10199

102100
const id = await startTransaction(transactionManager)
103101

@@ -115,7 +113,7 @@ test('transaction executes normally', async () => {
115113

116114
test('transaction is rolled back', async () => {
117115
const driverAdapter = new MockDriverAdapter()
118-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
116+
const transactionManager = new TransactionManager({ driverAdapter })
119117

120118
const id = await startTransaction(transactionManager)
121119

@@ -133,7 +131,7 @@ test('transaction is rolled back', async () => {
133131

134132
test('transactions are rolled back when shutting down', async () => {
135133
const driverAdapter = new MockDriverAdapter()
136-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
134+
const transactionManager = new TransactionManager({ driverAdapter })
137135

138136
const id1 = await startTransaction(transactionManager)
139137
const id2 = await startTransaction(transactionManager)
@@ -156,7 +154,7 @@ test('transactions are rolled back when shutting down', async () => {
156154

157155
test('when driver adapter requires phantom queries does not execute transaction statements', async () => {
158156
const driverAdapter = new MockDriverAdapter({ usePhantomQuery: true })
159-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
157+
const transactionManager = new TransactionManager({ driverAdapter })
160158

161159
const id = await startTransaction(transactionManager)
162160

@@ -172,7 +170,7 @@ test('when driver adapter requires phantom queries does not execute transaction
172170

173171
test('with explicit isolation level', async () => {
174172
const driverAdapter = new MockDriverAdapter()
175-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
173+
const transactionManager = new TransactionManager({ driverAdapter })
176174

177175
const id = await startTransaction(transactionManager, { isolationLevel: IsolationLevel.Serializable })
178176

@@ -191,7 +189,7 @@ test('with explicit isolation level', async () => {
191189

192190
test('for MySQL with explicit isolation level requires isolation level set before BEGIN', async () => {
193191
const driverAdapter = new MockDriverAdapter({ provider: 'mysql' })
194-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
192+
const transactionManager = new TransactionManager({ driverAdapter })
195193

196194
const id = await startTransaction(transactionManager, { isolationLevel: IsolationLevel.Serializable })
197195

@@ -203,7 +201,7 @@ test('for MySQL with explicit isolation level requires isolation level set befor
203201

204202
test('for SQLite with unsupported isolation level', async () => {
205203
const driverAdapter = new MockDriverAdapter({ provider: 'sqlite' })
206-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
204+
const transactionManager = new TransactionManager({ driverAdapter })
207205

208206
await expect(
209207
startTransaction(transactionManager, { isolationLevel: IsolationLevel.RepeatableRead }),
@@ -212,7 +210,7 @@ test('for SQLite with unsupported isolation level', async () => {
212210

213211
test('with isolation level only supported in MS SQL Server, "snapshot"', async () => {
214212
const driverAdapter = new MockDriverAdapter()
215-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
213+
const transactionManager = new TransactionManager({ driverAdapter })
216214

217215
await expect(
218216
startTransaction(transactionManager, { isolationLevel: IsolationLevel.Snapshot }),
@@ -221,7 +219,7 @@ test('with isolation level only supported in MS SQL Server, "snapshot"', async (
221219

222220
test('transaction times out during starting', async () => {
223221
const driverAdapter = new MockDriverAdapter()
224-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
222+
const transactionManager = new TransactionManager({ driverAdapter })
225223

226224
await expect(startTransaction(transactionManager, { maxWait: START_TRANSACTION_TIME / 2 })).rejects.toBeInstanceOf(
227225
TransactionStartTimoutError,
@@ -230,7 +228,7 @@ test('transaction times out during starting', async () => {
230228

231229
test('transaction times out during execution', async () => {
232230
const driverAdapter = new MockDriverAdapter()
233-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
231+
const transactionManager = new TransactionManager({ driverAdapter })
234232

235233
const id = await startTransaction(transactionManager)
236234

@@ -242,7 +240,7 @@ test('transaction times out during execution', async () => {
242240

243241
test('trying to commit or rollback invalid transaction id fails with TransactionNotFoundError', async () => {
244242
const driverAdapter = new MockDriverAdapter()
245-
const transactionManager = new TransactionManager({ driverAdapter, clientVersion: '1.0.0' })
243+
const transactionManager = new TransactionManager({ driverAdapter })
246244

247245
await expect(transactionManager.commitTransaction('invalid-tx-id')).rejects.toBeInstanceOf(TransactionNotFoundError)
248246
await expect(transactionManager.rollbackTransaction('invalid-tx-id')).rejects.toBeInstanceOf(TransactionNotFoundError)
@@ -252,12 +250,10 @@ test('trying to commit or rollback invalid transaction id fails with Transaction
252250
expect(driverAdapter.rollbackMock).not.toHaveBeenCalled()
253251
})
254252

255-
test('TransactionManagerErrors are PrismaClientKnownRequestError', () => {
256-
const error = new TransactionManagerError('test message', { clientVersion: '1.0.0', meta: { foo: 'bar' } })
253+
test('TransactionManagerErrors have common structure', () => {
254+
const error = new TransactionManagerError('test message', { foo: 'bar' })
257255

258-
expect(error).toBeInstanceOf(PrismaClientKnownRequestError)
259256
expect(error.code).toEqual('P2028')
260257
expect(error.message).toEqual('Transaction API error: test message')
261-
expect(error.clientVersion).toEqual('1.0.0')
262258
expect(error.meta).toEqual({ foo: 'bar' })
263259
})

0 commit comments

Comments
 (0)