Prisma Driver Adapter Implementation

TopTinker Aug 13, 2026 New v1.0.0 942 installs Sec S+ Verified source
Claude Code Cursor
Free
Open verification
AI OverviewGenerated from SKILL.md
Core usage
This skill is a required reference for implementing or modifying Prisma ORM 7 SQL driver adapters. Use it when building SqlDriverAdapterFactory, SqlDriverAdapter, Transaction, savepoint support, result mapping, or DriverAdapterError behavior; follow the contract snapshot, map arguments with ArgType and array row mode, and validate the exact @prisma/driver-adapter-utils version. It also covers transaction lifecycle, shadow-database isolation, and verification via targeted tests.
Key advantages
It codifies the adapter protocol boundary and priority rules, preventing subtle issues like connection interleaving, duplicate commit/rollback, and silent value corruption. It includes current transaction and optional savepoint hooks, original database-error preservation, and explicit guidance on script execution and result metadata. This gives implementers a single reference for correctness-sensitive adapter behavior.
Limitations
It is version-sensitive and must be paired with the exact @prisma/driver-adapter-utils version installed by the target Prisma release. It does not provide a complete adapter implementation; it is a reference, and type-compatible code can still corrupt values, leak connections, or break transactions if the rules are not followed. Concrete database isolation-level support and native script facilities still need to be validated by the implementer.
Target audience
This is for developers and contributors implementing or modifying Prisma SQL driver adapters, adding new database drivers, or working on SqlDriverAdapter/Transaction/savepoint/error mapping code. It is also relevant for debugging P2039 errors, transaction leaks, shadow-database failures, and adapter-specific query behavior.
Risks & notes
Ignoring the critical priority rules can cause transaction interleaving, connection leaks, duplicate COMMIT/ROLLBACK, and unsafe shadow-database behavior. Naive SQL script splitting on semicolons can break functions, triggers, quoted strings, and dialect-specific blocks. Adapters should preserve original database errors, keep savepoints on Transaction, and dispose only resources they own to avoid shutting down caller-owned pools.
DescriptionWritten by the seller

# Prisma SQL Driver Adapter Implementation

Use this guide with the exact `@prisma/driver-adapter-utils` version installed by the target Prisma release. Driver adapters are a protocol boundary: type-compatible code can still corrupt values, leak connections, or break transactions.

## When to Apply

- Implementing `SqlDriverAdapterFactory`, `SqlMigrationAwareDriverAdapterFactory`, `SqlDriverAdapter`, or `Transaction`
- Adding nested-transaction/savepoint support
- Mapping driver values, column metadata, bind arguments, or database errors
- Debugging `P2039`, transaction leaks, shadow-database failures, or adapter-specific query behavior

## Contract snapshot

```typescript
interface SqlDriverAdapterFactory extends AdapterInfo {
connect(): Promise
}

interface SqlMigrationAwareDriverAdapterFactory extends SqlDriverAdapterFactory {
connectToShadowDb(): Promise
}

interface SqlDriverAdapter extends AdapterInfo {
queryRaw(query: SqlQuery): Promise
executeRaw(query: SqlQuery): Promise
executeScript(script: string): Promise
startTransaction(isolationLevel?: IsolationLevel): Promise
getConnectionInfo?(): ConnectionInfo
dispose(): Promise
}

interface Transaction extends AdapterInfo {
readonly options: { usePhantomQuery: boolean }
queryRaw(query: SqlQuery): Promise
executeRaw(query: SqlQuery): Promise
commit(): Promise
rollback(): Promise
createSavepoint?(name: string): Promise
rollbackToSavepoint?(name: string): Promise
releaseSavepoint?(name: string): Promise
}
```

`IsolationLevel` currently includes `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, `SNAPSHOT`, and `SERIALIZABLE`; validate what the concrete database supports.

## Priority rules

Priority Rule Impact
CRITICAL One dedicated connection per transaction Prevents interleaving and leaks
CRITICAL `commit`/`rollback` are lifecycle cleanup hooks Prevents duplicate COMMIT/ROLLBACK
CRITICAL Savepoints live on `Transaction`, not adapter-global depth Makes nested scopes connection-local
CRITICAL Preserve original database error code/message Enables useful `P2039` fallback
HIGH Map arguments and result metadata exactly Prevents silent value corruption
HIGH Shadow databases are isolated and always cleaned up Makes Migrate safe
HIGH Dispose only resources the adapter owns Prevents shutting down caller-owned pools

## Query implementation

`SqlQuery` contains `sql`, `args`, and parallel `argTypes`. Map each argument using both value and `ArgType`; do not discard type/arity information. Execute in the driver's array/tuple row mode so column order is stable.

```typescript
class ExampleQueryable {
readonly provider = 'postgres' as const
readonly adapterName = '@acme/adapter-example'

constructor(protected readonly connection: DriverConnection) {}

async queryRaw(query: SqlQuery): Promise {
try {
const result = await this.connection.query({
text: query.sql,
values: query.args.map((value, index) =>
mapArg(value, query.argTypes[index]),
),
rowMode: 'array',
})

return {
columnNames: result.fields.map((field) => field.name),
columnTypes: result.fields.map(mapColumnType),
rows: result.rows,
}
} catch (error) {
throwAdapterError(error)
}
}

async executeRaw(query: SqlQuery): Promise {
try {
const result = await this.connection.execute(
query.sql,
query.args.map((value, index) => mapArg(value, query.argTypes[index])),
)
return result.rowsAffected ?? 0
} catch (error) {
throwAdapterError(error)
}
}
}
```

### Result mapping

Return `columnNames`, `columnTypes`, and `rows` with identical lengths/order. Map driver metadata to `ColumnTypeEnum` deliberately:

- signed integer widths to `Int32`/`Int64`; preserve 64-bit values without JS number truncation
- decimal/numeric to `Numeric` using the representation expected by Prisma
- binary to `Uint8Array`/`Bytes`
- date-only, time-only, and timestamp to `Date`, `Time`, and `DateTime`
- UUID, JSON, enum, arrays, and provider-specific unknown values to their explicit types
- unsupported native types to `DriverAdapterError({ kind: 'UnsupportedNativeDataType', type })`

Test `null`, empty arrays, array element types, big integers, decimals, byte arrays, JSON, dates, and user-defined/unknown native types.

### Script execution

`executeScript` must execute a migration script as the provider expects. Prefer the driver's native multi-statement/script facility or a real SQL parser. Naively splitting on `;` breaks functions, triggers, quoted strings, and dialect-specific blocks.

## Transaction protocol

`startTransaction` must acquire one dedicated connection, start the database transaction, apply the requested isolation level, and return a `Transaction` bound to that same connection. If setup fails, release it immediately.

```typescript
async startTransaction(level?: IsolationLevel): Promise {
const connection = await this.pool.acquire()
try {
const tx = new ExampleTransaction(connection, () => connection.release())
await tx.executeRaw({ sql: 'BEGIN', args: [], argTypes: [] })
if (level) {
await tx.executeRaw({
sql: `SET TRANSACTION ISOLATION LEVEL ${validateLevel(level)}`,
args: [],
argTypes: [],
})
}
return tx
} catch (error) {
connection.release(error)
throwAdapterError(error)
}
}
```

### Commit and rollback

Prisma coordinates the SQL `COMMIT`/`ROLLBACK` through `executeRaw`. The transaction object's `commit()` and `rollback()` methods are lifecycle hooks: detach listeners and release the dedicated connection exactly once. They must not issue a second SQL commit/rollback.

```typescript
class ExampleTransaction extends ExampleQueryable implements Transaction {
readonly options = { usePhantomQuery: false }
#closed = false

constructor(connection: DriverConnection, private readonly release: () => void) {
super(connection)
}

async commit() { this.finish() }
async rollback() { this.finish() }

private finish() {
if (this.#closed) return
this.#closed = true
this.release()
}

async createSavepoint(name: string) {
await this.control(`SAVEPOINT ${safeSavepoint(name)}`)
}

async rollbackToSavepoint(name: string) {
await this.control(`ROLLBACK TO SAVEPOINT ${safeSavepoint(name)}`)
}

async releaseSavepoint(name: string) {
await this.control(`RELEASE SAVEPOINT ${safeSavepoint(name)}`)
}

private async control(sql: string) {
await this.executeRaw({ sql, args: [], argTypes: [] })
}
}
```

Implement the optional savepoint methods only where the provider supports them. Validate/quote savepoint identifiers. For providers whose savepoints are intentionally no-ops, document and test that limitation.

Never keep transaction depth on the shared adapter. Parallel transactions make adapter-global depth incorrect; nested state belongs to the returned transaction connection and Prisma's savepoint calls.

## Error mapping

Wrap recognized driver failures in `DriverAdapterError`. Map known conditions to `MappedError` kinds such as constraint violations, authentication/reachability, missing table/column/database, timeouts, closed transactions, invalid input, value range, and write conflicts.

For database errors, preserve `originalCode` and `originalMessage` even when falling back to the provider-specific raw variant:

```typescript
import {
DriverAdapterError,
type Error as DriverAdapterErrorObject,
type MappedError,
} from '@prisma/driver-adapter-utils'

function convertDriverError(error: DatabaseError): DriverAdapterErrorObject {
return {
originalCode: String(error.code),
originalMessage: error.message,
...mapKnownOrRaw(error),
}
}

function mapKnownOrRaw(error: DatabaseError): MappedError {
if (error.code === '23505') {
return { kind: 'UniqueConstraintViolation', constraint: parsedConstraint(error) }
}
return {
kind: 'postgres',
code: String(error.code ?? 'N/A'),
severity: error.severity ?? 'N/A',
message: error.message,
detail: error.detail,
column: error.column,
hint: error.hint,
}
}

function throwAdapterError(error: unknown): never {
if (!isDatabaseError(error)) throw error
throw new DriverAdapterError(convertDriverError(error))
}
```

Prisma uses preserved original details when an unmapped driver error becomes `P2039`. Do not replace every unknown exception with a fabricated `GenericJs` id; rethrow genuinely unexpected non-driver errors so programming bugs remain visible.

## Factory, ownership, and shadow database

- `connect()` returns a fresh usable adapter connection/pool wrapper.
- Track whether the factory created the pool. `dispose()` closes owned pools and only detaches listeners from caller-owned pools unless an explicit option transfers ownership.
- Implement `SqlMigrationAwareDriverAdapterFactory` only when `connectToShadowDb()` can create an isolated shadow database, connect to it, and drop it during disposal/failure cleanup.
- Never point the shadow adapter at the primary database. Quote generated identifiers and use cryptographically unique names.
- `getConnectionInfo()` should accurately report `schemaName`, `maxBindValues` when applicable, and `supportsRelationJoins`.

## Verification checklist

- [ ] Typecheck against the exact target `@prisma/driver-adapter-utils` version
- [ ] `queryRaw` preserves column order, types, nulls, and precision
- [ ] `executeRaw` reports affected rows correctly
- [ ] `executeScript` handles provider-specific multi-statement syntax
- [ ] Concurrent interactive transactions use distinct dedicated connections
- [ ] Success commits and releases once; failure rolls back and releases once
- [ ] Nested transaction tests exercise create/rollback/release savepoint hooks
- [ ] Unsupported isolation levels fail as `InvalidIsolationLevel`
- [ ] Known constraints map to structured errors
- [ ] Unmapped database errors retain original code/message and surface useful `P2039`
- [ ] Dispose ownership is tested for internal and external pools
- [ ] Shadow database creation, use, failure cleanup, and disposal are isolated
- [ ] Run Prisma Client integration/E2E tests, not only adapter unit tests

## Source references

- [Driver adapter interfaces](https://github.com/prisma/prisma/blob/v7/packages/driver-adapter-utils/src/types.ts)
- [PostgreSQL adapter transaction implementation](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/pg.ts)
- [PostgreSQL adapter error mapping](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/errors.ts)

Use caseInput → Output
Input
Implementing SqlDriverAdapterFactory, SqlMigrationAwareDriverAdapterFactory, SqlDriverAdapter, or Transaction; Adding nested-transaction/savepoint support; Mapping driver values, column metadata, bind arguments, or database errors; Debugging P2039, transaction leaks, shadow-database failures, or adapter-specific query behavior
Output
Verified guidance, commands and best practices for Prisma Driver Adapter Implementation, ready to paste into your agent
How it worksImport to your platform and run
Item details
Use case
AI Skills
Capability
Coding
Agents
Claude Code, Cursor
Version
1.0.0
First seen
Aug 13, 2026
Installs
942
License
Non-exclusive
Last update
Aug 13, 2026
InstallCompatible with agent skill ecosystem
npx skills add prisma/skills --skill prisma-driver-adapter-implementation
Source: prisma/skills
What you get
SKILL.md skill definitionCommand referenceInstallation instructionsPrisma Driver Adapter Implementation reference
Verified sourceOriginal project page — inspect before install
Open the original source project
Check the upstream repository, license and changelog before install
Open source
Security ScanS+Score 100/100 · 0 findings · 2026-08-15 21:35:11
Static analysis100
Dynamic behavior100
Dependencies100
Network100
Privacy100
Threat intel100
✓ 未发现安全问题,六维检测全部通过。
Security scan generated by TopTinker automated engine from SKILL.md static analysis, for pre-install reference only. Third-party skills carry their own runtime risk.
WeChat
Qizhuwang Source Code Trading Platform
2021-12-28开店时间
284商品数
认证
Guarantees
Escrow paymentOn
Platform holds funds until delivery is confirmed
Install verified
Free download - install & run before you pay
Source transparency
Original GitHub repo linked & verified
No refunds after download
Digital product - disputes arbitrated on evidence only
Enhanced protection
Trusted seller - priority arbitration within 48h, backed by platform bond
Free

Report this listing

This content is locked. Buy it once and use it forever - instant delivery after purchase.

one-time
Unlock now
Escrow payment · 7-day refund support