Skip to content

Commit ebfd94e

Browse files
committed
Return an object when there is any non-null values during a grouped left/right join
When doing a grouped left/right join, the entire object is incorrectly defined as null if the first value returned is null. Further entries are checked for a non-null values, and ensures the returned object is defined if any value was not null
1 parent 273c780 commit ebfd94e

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

drizzle-orm/src/utils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export function mapResultRow<TResult>(
1919
): TResult {
2020
// Key -> nested object key, value -> table name if all fields in the nested object are from the same table, false otherwise
2121
const nullifyMap: Record<string, string | false> = {};
22-
2322
const result = columns.reduce<Record<string, any>>(
2423
(result, { path, field }, columnIndex) => {
2524
let decoder: DriverValueDecoder<unknown, unknown>;
@@ -51,6 +50,10 @@ export function mapResultRow<TResult>(
5150
typeof nullifyMap[objectName] === 'string' && nullifyMap[objectName] !== getTableName(field.table)
5251
) {
5352
nullifyMap[objectName] = false;
53+
} else if (value !== null) {
54+
// The initial value for an object may have been null, but subsquent values are not-null
55+
// Prevents the entire object being define as null when the join has values
56+
nullifyMap[objectName] = false;
5457
}
5558
}
5659
}

integration-tests/tests/pg/pg-common.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,53 @@ export function tests() {
17411741
]);
17421742
});
17431743

1744+
test('left join (grouped join null first column)', async (ctx) => {
1745+
const { db } = ctx.pg;
1746+
1747+
const rows = await db
1748+
.insert(citiesTable)
1749+
.values([{ name: 'Austin', state: "TX" }, { name: 'London' }])
1750+
.returning({ id: citiesTable.id });
1751+
1752+
expect(rows).toHaveLength(2)
1753+
const [{id: austinId}, {id: londonId}] = rows as any as [{id: number}, {id: number}];
1754+
1755+
await db.insert(users2Table).values([{ name: 'John', cityId: austinId }, { name: 'Jane', cityId: londonId }]);
1756+
1757+
const res = await db
1758+
.select(
1759+
{
1760+
id: users2Table.id,
1761+
user: {
1762+
name: users2Table.name,
1763+
nameUpper: sql<string>`upper(${users2Table.name})`,
1764+
},
1765+
city: {
1766+
// Being a nullable column, being first caused the entire object to return null
1767+
state: citiesTable.state,
1768+
id: citiesTable.id,
1769+
name: citiesTable.name,
1770+
nameUpper: sql<string>`upper(${citiesTable.name})`,
1771+
},
1772+
}
1773+
)
1774+
.from(users2Table)
1775+
.leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id));
1776+
1777+
expect(res).toEqual([
1778+
{
1779+
id: 1,
1780+
user: { name: 'John', nameUpper: 'JOHN' },
1781+
city: { state: 'TX', id: austinId, name: 'Austin', nameUpper: 'AUSTIN' },
1782+
},
1783+
{
1784+
id: 2,
1785+
user: { name: 'Jane', nameUpper: 'JANE' },
1786+
city: { state: null, id: londonId, name: 'London', nameUpper: 'LONDON' },
1787+
},
1788+
]);
1789+
});
1790+
17441791
test('select from a many subquery', async (ctx) => {
17451792
const { db } = ctx.pg;
17461793

0 commit comments

Comments
 (0)