-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add output columnTypes to SqlQuery for reliable type handling in Driver Adapters #28891
Description
Feature Summary
Add an optional columnTypes field to the SqlQuery interface in @prisma/driver-adapter-utils, allowing the Query Engine to pass expected output column types to Driver Adapters for correct type conversion.
Use Cases & Problem Description
I'm the author of prisma-adapter-bun-sqlite, a community Driver Adapter for Bun's native SQLite. While investigating an issue, I discovered a fundamental limitation in the Driver Adapter interface that causes #28890.
The problem: Adapters receive type information for input parameters (argTypes) but not for output columns. They must infer output columnTypes from database metadata.
This breaks when the database storage type differs from the Prisma schema type:
model Post {
id Int @id
createdAt DateTime @default(now())
}With timestampFormat: "unixepoch-ms", SQLite stores DateTime as INTEGER:
CREATE TABLE Post (
id INTEGER PRIMARY KEY,
createdAt INTEGER NOT NULL -- Unix epoch ms
)When querying:
- The Query Engine knows
createdAtshould beDateTime(from the schema) - The adapter sees SQLite declared type
INTEGER - The adapter returns
ColumnTypeEnum.Int32instead ofDateTime - Result:
Invalid Datefor all DateTime operations
The legacy Rust query engine had full schema context. The Driver Adapter interface is more decoupled, but this decoupling breaks type handling.
Proposed Solution
Add an optional columnTypes field to SqlQuery:
export type SqlQuery = {
sql: string
args: Array<unknown>
argTypes: Array<ArgType>
/**
* Expected output column types for this query, when known from the Prisma schema.
* Adapters can use these hints to correctly convert result values, especially
* when the database storage type differs from the Prisma field type.
*/
columnTypes?: Array<ColumnType | null>
}This field would:
- Be optional: adapters can ignore it and use existing inference logic
- Use the same
ColumnTypeenum already used inSqlResultSet - Allow
nullfor dynamic columns where the engine doesn't know the type
Implementation scope:
@prisma/driver-adapter-utils: AddcolumnTypestoSqlQuerytype- Query Engine (WASM): Populate
columnTypeswhen building queries - Official adapters: Use
columnTypeswhen available, fall back to inference - Community adapters: Can adopt at their own pace
I'd be happy to contribute a PR for the type change if the approach looks reasonable.
Alternative Solutions
1. Heuristic detection in adapters:
Detect INTEGER values in timestamp range and convert to DateTime when unixepoch-ms is set. However, this risks converting actual integer columns incorrectly.
2. Schema file parsing:
Adapters could parse the Prisma schema file to understand column types. This adds complexity, requires file access, and duplicates Query Engine work.
3. Adapter-specific configuration:
Users manually specify which columns are DateTime. This is error-prone and defeats the purpose of schema-driven development.
None of these alternatives are reliable. Only the Query Engine has authoritative schema information, it should pass it to adapters.
Potential Considerations
- Backward compatibility: The field is optional, so existing adapters continue to work unchanged
- Query Engine changes: The WASM engine needs to populate the field (separate PR in
prisma-engines) - Performance: Minimal; the Query Engine already has this information during query planning
- Dynamic queries:
$queryRawmay not have schema context;nullvalues handle this case
Prisma Version
7.1.0
What part of Prisma does this affect?
Prisma Client
Additional Context
Evidence from prisma-engines:
In prisma-engines/libs/driver-adapters/src/types.rs, the Query struct sent to adapters:
pub struct Query {
pub sql: String,
pub args: Vec<JSArg>,
pub arg_types: Vec<JSArgType>, // Input types only
}The engine builds typed queries via quaint::ast::Query with full schema context, but this type information is discarded when serializing to the adapter interface.
Benefits:
- Fixes
unixepoch-ms: DateTime fields stored as INTEGER work correctly - Fixes aggregate functions:
_min,_maxon DateTime fields return valid dates - Non-breaking: Existing adapters continue unchanged
- Benefits all databases: MySQL, PostgreSQL, SQLite all have similar type mapping challenges
- Aligns with Rust engine: Native connectors have this context; adapters should too
Related:
- Bug report:
@prisma/adapter-better-sqlite3DateTime fields returnInvalid DatewithtimestampFormat: "unixepoch-ms"#28890 (@prisma/adapter-better-sqlite3DateTime broken withunixepoch-ms) - Original discovery: docs: document aggregate DateTime limitation with unixepoch-ms mmvsk/prisma-adapter-bun-sqlite#2
- Community adapter: https://github.com/mmvsk/prisma-adapter-bun-sqlite
Pre-Submission Checklist
- I have searched existing issues to make sure this is not a duplicate
- I have checked the Prisma roadmap to see if this is already planned
- I have described why this belongs in Prisma Core rather than a solution in application code