How to declare optional one-to-one relationship

I have 2 tables that relate to each other in an inverse manner:
export const users = createTable('users', {
id: text('id').primaryKey(),
email: text('email').notNull().unique(),
})

export const profiles = createTable('profiles', {
userId: text('user_id')
.notNull()
.primaryKey()
.references(() => users.id),
firstName: text('first_name').notNull(),
lastName: text('last_name').notNull(),
})

export const usersRelations = relations(users, ({ one }) => ({
profile: one(profiles, {
fields: [users.id],
references: [profiles.userId],
}),
}))

export const profilesRelations = relations(profiles, ({ one }) => ({
user: one(users, {
fields: [profiles.userId],
references: [users.id]
}),
}))
export const users = createTable('users', {
id: text('id').primaryKey(),
email: text('email').notNull().unique(),
})

export const profiles = createTable('profiles', {
userId: text('user_id')
.notNull()
.primaryKey()
.references(() => users.id),
firstName: text('first_name').notNull(),
lastName: text('last_name').notNull(),
})

export const usersRelations = relations(users, ({ one }) => ({
profile: one(profiles, {
fields: [users.id],
references: [profiles.userId],
}),
}))

export const profilesRelations = relations(profiles, ({ one }) => ({
user: one(users, {
fields: [profiles.userId],
references: [users.id]
}),
}))
If I go ahead and create a user without a profile in Studio, no error is shown. However, when I run the following script during runtime, unexpected errors may appear.
const user = await db.query.users.findFirst({
with: {
profile: {
columns: { firstName: true }
}
},
})

user //? { id: string; email: string; profile: { firstName: string } } | undefined

console.log(user?.profile.firstName) // No TypeScript error appears because it assumes profile always exists

// Runtime error: null is not an object (evaluating 'user?.profile.firstName')
const user = await db.query.users.findFirst({
with: {
profile: {
columns: { firstName: true }
}
},
})

user //? { id: string; email: string; profile: { firstName: string } } | undefined

console.log(user?.profile.firstName) // No TypeScript error appears because it assumes profile always exists

// Runtime error: null is not an object (evaluating 'user?.profile.firstName')
I understand that I could fix this by updating my schema relationships and linking a profile ID in the users table but, given that I have many tables that relate to individual users where table information may or may not exist (e.g. profile, KYC data, KYB data, etc.), I thought this would be the best way to design it.
1 Reply
Marcel
MarcelOP2mo ago
UPDATE: Just realized that if I omit the field information from usersRelations, it will infer profile relationship correctly to Profile | null.
// new relations variables
export const usersRelations = relations(users, ({ one }) => ({
profile: one(profiles),
}))

export const profilesRelations = relations(profiles, ({ one }) => ({
user: one(users, {
fields: [profiles.userId],
references: [users.id]
}),
}))
// new relations variables
export const usersRelations = relations(users, ({ one }) => ({
profile: one(profiles),
}))

export const profilesRelations = relations(profiles, ({ one }) => ({
user: one(users, {
fields: [profiles.userId],
references: [users.id]
}),
}))
Please let me know if I should close this
Want results from more Discord servers?
Add your server