How to type an optional included relation?

I'd like to implement a function that given an email returns a user. The function also gets an optional includeContacts boolean. When true, all user contacts should be returned as well. Here is what I currently have:
async function getUserByEmail(email: string, options?: { includeContacts: true }) {
const includeContacts = options?.includeContacts ?? false;
const user = await db.query.usersTable.findFirst({
where: eq(usersTable.email, email),
with: includeContacts ? { contacts: true } : undefined,
});

return user ?? null;
}
async function getUserByEmail(email: string, options?: { includeContacts: true }) {
const includeContacts = options?.includeContacts ?? false;
const user = await db.query.usersTable.findFirst({
where: eq(usersTable.email, email),
with: includeContacts ? { contacts: true } : undefined,
});

return user ?? null;
}
The problem is that user contacts are not included in the returned type. Ideally, contacts will be a non-optional field in the returned type when includeContacts is true. Is this possible to achieve? Here is my schema:
export const usersTable = pgTable("users", {
email: text("email").notNull().unique().primaryKey(),
getHeadsUp: boolean("get_heads_up").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});

export const contactsTable = pgTable("contacts", {
id: text("id")
.primaryKey()
.$defaultFn(() => `ct_${crypto.randomUUID()}`),
userEmail: text("user_email").notNull(),
name: text("name").notNull(),
email: text("email").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});

export const usersRelations = relations(usersTable, ({ many }) => ({
contacts: many(contactsTable),
}));

export const contactsRelations = relations(contactsTable, ({ one }) => ({
user: one(usersTable, {
fields: [contactsTable.userEmail],
references: [usersTable.email],
}),
}));
export const usersTable = pgTable("users", {
email: text("email").notNull().unique().primaryKey(),
getHeadsUp: boolean("get_heads_up").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});

export const contactsTable = pgTable("contacts", {
id: text("id")
.primaryKey()
.$defaultFn(() => `ct_${crypto.randomUUID()}`),
userEmail: text("user_email").notNull(),
name: text("name").notNull(),
email: text("email").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});

export const usersRelations = relations(usersTable, ({ many }) => ({
contacts: many(contactsTable),
}));

export const contactsRelations = relations(contactsTable, ({ one }) => ({
user: one(usersTable, {
fields: [contactsTable.userEmail],
references: [usersTable.email],
}),
}));
1 Reply
Sillvva
Sillvva5mo ago
Not within the same query. As you said, the types get messed up. I've been pushing for them to add support for limit 0 for this reason https://github.com/drizzle-team/drizzle-orm/pull/2255 It would allow a one-to-many or many-to-many relationship to be made optional via limit (doesn't break types), rather than an optional with (breaks types). You can see my current workaround in my Mar 20 comment here. https://github.com/drizzle-team/drizzle-orm/issues/2011
Want results from more Discord servers?
Add your server