drizzle-team / drizzle-team/drizzle-orm
[BUG]: Field Mapping Not Working in Prisma Extension
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Report hasn't been filed before.
- [x] I have verified that the bug I'm about to report hasn't been filed before.
### What version of `drizzle-orm` are you using?
0.44.7
### What version of `drizzle-kit` are you using?
N/A
### Other packages
"prisma": "^7.2.0"
### Describe the Bug
Note: I have used Claude to help me draft this bug report, but I have spent a few hours identifying the bug and working on the fix before drafting this.
## Description
The Prisma adapter for drizzle-orm (`drizzle-orm/prisma/pg`) does not respect field aliases in select queries. When using a column alias in a `.select()` query, the returned result uses the database column name instead of the specified alias.
## Environment
- **drizzle-orm version**: 0.44.7
- **@prisma/client version**: 7.2.0
- **Database**: PostgreSQL
- **Node.js version**: (as applicable)
## Expected Behavior
When selecting a column with an alias:
```typescript
const [result] = await prisma.$drizzle
.select({
id: schema.partners.partnerId,
})
.from(schema.partners)
.limit(1);
console.log(result);
// Expected: { id: '...' }
```
The result should have the key `id` as specified in the select object.
## Actual Behavior
The result uses the database column name instead:
```typescript
console.log(result);
// Actual: { partnerId: '...' }
```
The definition of the table and the column are irrelevant, as I have tested this with many tables/columns of different types.
## Reproduction
### Minimal Example
```typescript
import { PrismaPgDatabase } from 'drizzle-orm/prisma/pg';
import { pgTable, text } from 'drizzle-orm/pg-core';
// Define schema with a column that has a different name than the alias
const partners = pgTable('Partner', {
partnerId: text('partnerId').primaryKey(),
name: text('name'),
});
// Create drizzle instance
const db = new PrismaPgDatabase(prismaClient, undefined);
// Query with alias
const [result] = await db
.select({
id: partners.partnerId, // Alias 'id' for column 'partnerId'
})
.from(partners)
.limit(1);
// Bug: result has { partnerId: '...' } instead of { id: '...' }
expect(result).toHaveProperty('id'); // ❌ Fails
expect(result).toHaveProperty('partnerId'); // ✅ Passes (unexpected)
```
### Test Case
```typescript
test('field mapping should work with aliases', async () => {
const [result] = await prisma.$drizzle
.select({
id: schema.partners.partnerId,
})
.from(schema.partners)
.limit(1);
expect(result).toHaveProperty('id'); // Currently fails
});
```
## Root Cause
The issue is in `drizzle-orm/prisma/pg/session.js`. The `PrismaPgSession.prepareQuery()` method doesn't accept or pass the `fields` parameter that contains the field mapping information. This causes the `PrismaPgPreparedQuery` to not have access to the alias mappings.
When Prisma executes `$queryRawUnsafe()`, it returns results with the actual database column names. Without the field mapping information, drizzle cannot transform these column names to the user-specified aliases.
## Proposed Fix
The fix involves three changes to `drizzle-orm/prisma/pg/session.js`:
### 1. Update `PrismaPgPreparedQuery` constructor to accept field mapping parameters
```javascript
class PrismaPgPreparedQuery extends PgPreparedQuery {
constructor(prisma, query, logger, fields, name, isResponseInArrayMode, customResultMapper, queryMetadata, cacheConfig) {
super(query, void 0, queryMetadata, cacheConfig);
this.prisma = prisma;
this.logger = logger;
this.fields = fields;
this._isResponseInArrayMode = isResponseInArrayMode;
this.customResultMapper = customResultMapper;
}
// ...
}
```
### 2. Add field mapping logic in the `execute` method
```javascript
execute(placeholderValues) {
const params = fillPlaceholders(this.query.params, placeholderValues ?? {});
this.logger.logQuery(this.query.sql, params);
return this.prisma.$queryRawUnsafe(this.query.sql, ...params).then(rawResult => {
// Map database column names to the aliased field names
if (this.fields && Array.isArray(rawResult)) {
return rawResult.map(row => {
const mappedRow = {};
for (const field of this.fields) {
// field.field.name is the actual database column name
// field.path is the alias (the key the user wants in the result)
const dbColumnName = field.field.name;
const aliasName = field.path[0];
if (row.hasOwnProperty(dbColumnName)) {
mappedRow[aliasName] = row[dbColumnName];
}
}
return Object.keys(mappedRow).length > 0 ? mappedRow : row;
});
}
return rawResult;
});
}
```
### 3. Update `PrismaPgSession.prepareQuery()` to accept and pass the parameters
```javascript
prepareQuery(query, fields, name, isResponseInArrayMode, customResultMapper, queryMetadata, cacheConfig) {
return new PrismaPgPreparedQuery(
this.prisma,
query,
this.logger,
fields,
name,
isResponseInArrayMode,
customResultMapper,
queryMetadata,
cacheConfig
);
}
```
### 4. Update `isResponseInArrayMode()` to use the parameter
```javascript
isResponseInArrayMode() {
return this._isResponseInArrayMode;
}
```
## Additional Context
This issue affects any query using the Prisma adapter where field aliases are specified. The problem is that the Prisma adapter implementation doesn't follow the same pattern as other drizzle drivers (like `node-postgres`), which properly handle the `fields` parameter for mapping.
The `fields` array contains objects with:
- `field.field.name`: The actual database column name
- `field.path`: An array where the first element is the user-specified alias
## Verification
After applying the fix, the test passes:
```typescript
test('field mapping works', async () => {
const [result] = await prisma.$drizzle
.select({
id: schema.partners.partnerId,
})
.from(schema.partners)
.limit(1);
expect(result).toHaveProperty('id'); // ✅ Now passes
});
```
## References
- Similar implementation in node-postgres adapter: `drizzle-orm/node-postgres/session.js`
Contributor guide
Assessment
This issue has not been assessed yet.