drizzle-team / drizzle-team/drizzle-orm

[BUG]: Select with left joins returning `null` for table with non-null results in reality

Open
#2,157 7 comments 11 reactions 0 assignees View on GitHub
bug priority qb/crud qb/joins
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

### What version of `drizzle-orm` are you using?

0.30.8

### What version of `drizzle-kit` are you using?

_No response_

### Describe the Bug

I have the following schema:
```typescript
export const patrons = pgTable(
"patron",
{
birthDate: date("birth_date", { mode: "string" }),
createdAt: timestamp("created_at", { mode: "date" }).notNull().defaultNow(),
email: text("email"),
firstName: text("first_name").notNull(),
gender: text("gender", { enum: ["FEMALE", "MALE"] }),
id: text("id").primaryKey().default(defaultUUID),
lastName: text("last_name").notNull(),
oneRosterSourcedId: text("one_roster_sourced_id"),
organizationId: text("organization_id").notNull(),
preferredName: text("preferred_name"),
},
(t) => ({
id_by_organization: uniqueIndex().on(t.id, t.organizationId),
one_roster_id_by_org: uniqueIndex().on(
t.oneRosterSourcedId,
t.organizationId,
),
}),
);

export const patronBarcodes = pgTable(
"patron_barcode",
{
barcode: text("barcode").notNull(),
createdAt: timestamp("created_at", { mode: "date" }).notNull().defaultNow(),
organizationId: text("organization_id").notNull(),
patronId: text("patron_id").notNull(),
pin: text("pin").notNull(),
},
(t) => ({
barcode_by_org: uniqueIndex().on(t.barcode, t.organizationId),
patron_by_org: uniqueIndex().on(t.patronId, t.organizationId),
patron_org: foreignKey({
columns: [t.patronId, t.organizationId],
foreignColumns: [patrons.id, patrons.organizationId],
}),
}),
);

export const patronGroups = pgTable(
"patron_group",
{
createdAt: timestamp("created_at", { mode: "date" }).notNull().defaultNow(),
id: text("id").primaryKey().default(defaultUUID),
name: text("name").notNull(),
oneRosterSourcedId: text("one_roster_sourced_id"),
organizationId: text("organization_id").notNull(),
},
(t) => ({
id_by_organization: uniqueIndex().on(t.id, t.organizationId),
name_by_organization: uniqueIndex().on(t.name, t.organizationId),
one_roster_id_by_org: uniqueIndex().on(
t.oneRosterSourcedId,
t.organizationId,
),
}),
);

export const patronGroupAssignments = pgTable(
"patron_group_assignment",
{
createdAt: timestamp("created_at", { mode: "date" }).notNull().defaultNow(),
groupId: text("group_id").notNull(),
oneRosterSourcedId: text("one_roster_sourced_id"),
organizationId: text("organization_id").notNull(),
patronId: text("patron_id").notNull(),
},
(t) => ({
one_roster_id_by_org: uniqueIndex().on(
t.oneRosterSourcedId,
t.organizationId,
),
org_group: foreignKey({
columns: [t.organizationId, t.groupId],
foreignColumns: [patronGroups.organizationId, patronGroups.id],
}),
org_patron: foreignKey({
columns: [t.organizationId, t.patronId],
foreignColumns: [patrons.organizationId, patrons.id],
}),
}),
);
```
And i have the following query:
```typescript
const results = await db
.select()
.from(schema.patronGroups)
.leftJoin(
schema.patronGroupAssignments,
eq(schema.patronGroups.id, schema.patronGroupAssignments.groupId),
)
.leftJoin(
schema.patrons,
eq(schema.patronGroupAssignments.patronId, schema.patrons.id),
)
.leftJoin(
schema.patronBarcodes,
eq(schema.patrons.id, schema.patronBarcodes.patronId),
)
.where(eq(schema.patronGroups.id, input.groupId));
```

The result of the query is:
```
[
{
patron_group: {
createdAt: 2024-04-13T00:16:26.921Z,
id: 'bd6b38ce-1fba-4d1b-a081-87c30c042cac',
name: '2nd',
oneRosterSourcedId: null,
organizationId: 'org_2edSQ9S2ztIBSWGxVJWno5NMJTq'
},
patron_group_assignment: {
createdAt: 2024-04-13T00:21:36.439Z,
groupId: 'bd6b38ce-1fba-4d1b-a081-87c30c042cac',
oneRosterSourcedId: null,
organizationId: 'org_2edSQ9S2ztIBSWGxVJWno5NMJTq',
patronId: '2981b284-55d6-4bf2-a07c-a1e210de8baf'
},
patron: null,
patron_barcode: {
barcode: '000000',
createdAt: 2024-04-10T00:06:28.378Z,
organizationId: 'org_2edSQ9S2ztIBSWGxVJWno5NMJTq',
patronId: '2981b284-55d6-4bf2-a07c-a1e210de8baf',
pin: '480078'
}
}
]
```
Note that `patron` is null despite the fact that `patron_barcode` is not null which is joined via `patron`.

### Expected behavior

`patron` in the query above should be populated.

If I capture the raw SQL and run that in another db client (Neon console), the `patron` table columns are populated as expected.

### Environment & setup

Local Node development using `drizzle-orm/neon-serverless`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.