( db: DrizzleDb, row: Pick<Organization, "id" | "name" | "workosUpdatedAt" | "deletedAt">, )
| 65 | * surfacing loudly beats a silently unslugged organization. |
| 66 | */ |
| 67 | export const insertOrganization = async ( |
| 68 | db: DrizzleDb, |
| 69 | row: Pick<Organization, "id" | "name" | "workosUpdatedAt" | "deletedAt">, |
| 70 | ): Promise<Organization> => { |
| 71 | const slugTaken = async (slug: string) => { |
| 72 | const rows = await db |
| 73 | .select({ id: organizations.id }) |
| 74 | .from(organizations) |
| 75 | .where(eq(organizations.slug, slug)); |
| 76 | return rows.length > 0; |
| 77 | }; |
| 78 | for (let attempt = 0; attempt < 4; attempt++) { |
| 79 | const slug = await generateOrgSlug(row.name, slugTaken); |
| 80 | const [inserted] = await db |
| 81 | .insert(organizations) |
| 82 | .values({ ...row, slug }) |
| 83 | .onConflictDoNothing() |
| 84 | .returning(); |
| 85 | if (inserted) return inserted; |
| 86 | // The insert was swallowed by a conflict. If the id now exists, a |
| 87 | // concurrent writer mirrored it — return that row. Otherwise the slug |
| 88 | // candidate collided; loop and mint a fresh one. |
| 89 | const held = await readOrganization(db, row.id); |
| 90 | if (held) return held; |
| 91 | } |
| 92 | // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: slug minting exhausted retries; surfacing loudly beats a silently unslugged org |
| 93 | throw new Error(`unable to mint a slug for organization ${row.id}`); |
| 94 | }; |
| 95 | |
| 96 | export const makeUserStore = (db: DrizzleDb) => { |
| 97 | const getOrganization = (id: string) => readOrganization(db, id); |
no test coverage detected