From e1fb18af8fc1c3e630be148348b6c3594ecf1b11 Mon Sep 17 00:00:00 2001 From: Gen Tamura Date: Sun, 26 Oct 2025 14:13:17 +0900 Subject: [PATCH 1/3] Add FK constraint for profile default category --- .../auth/src/account/provision-account.ts | 47 +++++++++++++++---- packages/db/src/schema/index.ts | 5 +- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/auth/src/account/provision-account.ts b/packages/auth/src/account/provision-account.ts index 8c3d7ca..ec1f32b 100644 --- a/packages/auth/src/account/provision-account.ts +++ b/packages/auth/src/account/provision-account.ts @@ -5,6 +5,7 @@ import type { SupabaseToken, } from "@listee/db"; import { + and, categories, createRlsClient, DEFAULT_CATEGORY_KIND, @@ -73,15 +74,7 @@ export function createAccountProvisioner( const email = resolveEmail(params.email ?? null, params.userId); await client.rls(async (tx: RlsTransaction) => { - await tx - .insert(profiles) - .values({ - id: params.userId, - email, - }) - .onConflictDoNothing(); - - await tx + const insertedCategories = await tx .insert(categories) .values({ name: defaultCategoryName, @@ -92,6 +85,42 @@ export function createAccountProvisioner( .onConflictDoNothing({ target: [categories.createdBy, categories.name], where: eq(categories.kind, defaultCategoryKind), + }) + .returning({ categoryId: categories.id }); + + const categoryRecord = + insertedCategories[0] ?? + (await tx + .select({ categoryId: categories.id }) + .from(categories) + .where( + and( + eq(categories.createdBy, params.userId), + eq(categories.name, defaultCategoryName), + eq(categories.kind, defaultCategoryKind), + ), + ) + .limit(1))[0]; + + if (categoryRecord === undefined) { + throw new Error("Failed to resolve default category for profile"); + } + + const defaultCategoryId = categoryRecord.categoryId; + + await tx + .insert(profiles) + .values({ + id: params.userId, + email, + defaultCategoryId, + }) + .onConflictDoUpdate({ + target: profiles.id, + set: { + email, + defaultCategoryId, + }, }); }); } diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index 8c76996..6bcda48 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -28,7 +28,10 @@ export const profiles = pgTable( id: uuid("id").primaryKey(), email: text("email").notNull().unique(), name: text("name"), - defaultCategoryId: uuid("default_category_id"), + defaultCategoryId: uuid("default_category_id").references( + (): AnyPgColumn => categories.id, + { onDelete: "restrict" }, + ), ...timestamps, }, (table) => { From f42b105304f7c607f08e8764f4f60405b5573e51 Mon Sep 17 00:00:00 2001 From: Gen Tamura Date: Sun, 26 Oct 2025 15:41:04 +0900 Subject: [PATCH 2/3] Upsert profile before seeding default category --- .../auth/src/account/provision-account.ts | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/packages/auth/src/account/provision-account.ts b/packages/auth/src/account/provision-account.ts index ec1f32b..0561f21 100644 --- a/packages/auth/src/account/provision-account.ts +++ b/packages/auth/src/account/provision-account.ts @@ -74,6 +74,19 @@ export function createAccountProvisioner( const email = resolveEmail(params.email ?? null, params.userId); await client.rls(async (tx: RlsTransaction) => { + await tx + .insert(profiles) + .values({ + id: params.userId, + email, + }) + .onConflictDoUpdate({ + target: profiles.id, + set: { + email, + }, + }); + const insertedCategories = await tx .insert(categories) .values({ @@ -108,20 +121,18 @@ export function createAccountProvisioner( const defaultCategoryId = categoryRecord.categoryId; - await tx - .insert(profiles) - .values({ - id: params.userId, - email, + const shouldUpdateProfile = await tx + .update(profiles) + .set({ defaultCategoryId, + email, }) - .onConflictDoUpdate({ - target: profiles.id, - set: { - email, - defaultCategoryId, - }, - }); + .where(eq(profiles.id, params.userId)) + .returning({ id: profiles.id }); + + if (shouldUpdateProfile.length === 0) { + throw new Error("Failed to update profile with default category"); + } }); } From 21975011b7cc6ff5a559a16abf5047b60bbc9db1 Mon Sep 17 00:00:00 2001 From: Gen Tamura Date: Sun, 26 Oct 2025 15:59:15 +0900 Subject: [PATCH 3/3] fix: biome format --- .../auth/src/account/provision-account.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/auth/src/account/provision-account.ts b/packages/auth/src/account/provision-account.ts index 0561f21..2686dc4 100644 --- a/packages/auth/src/account/provision-account.ts +++ b/packages/auth/src/account/provision-account.ts @@ -103,17 +103,19 @@ export function createAccountProvisioner( const categoryRecord = insertedCategories[0] ?? - (await tx - .select({ categoryId: categories.id }) - .from(categories) - .where( - and( - eq(categories.createdBy, params.userId), - eq(categories.name, defaultCategoryName), - eq(categories.kind, defaultCategoryKind), - ), - ) - .limit(1))[0]; + ( + await tx + .select({ categoryId: categories.id }) + .from(categories) + .where( + and( + eq(categories.createdBy, params.userId), + eq(categories.name, defaultCategoryName), + eq(categories.kind, defaultCategoryKind), + ), + ) + .limit(1) + )[0]; if (categoryRecord === undefined) { throw new Error("Failed to resolve default category for profile");