import { asc, eq } from "drizzle-orm"; import { ssoProviders, users } from "../db/schema.js"; import type { DatabaseContext } from "./database-context.js"; import { rowsAffected } from "./mutation-result.js"; import { insertReturning, updateReturning } from "./returning.js"; export type SsoProviderRecord = typeof ssoProviders.$inferSelect; export type NewSsoProviderRecord = typeof ssoProviders.$inferInsert; export type SsoProviderUpdate = Partial< Pick< NewSsoProviderRecord, "name" | "type" | "enabled" | "displayOrder" | "config" | "updatedAt" > >; export type PublicSsoProviderRecord = Pick< SsoProviderRecord, "id" | "name" | "type" | "displayOrder" >; export class SsoProviderRepository { constructor( private readonly context: DatabaseContext, private readonly onWrite?: () => void | Promise, ) {} async listEnabledPublic(): Promise { return this.context.drizzle .select({ id: ssoProviders.id, name: ssoProviders.name, type: ssoProviders.type, displayOrder: ssoProviders.displayOrder, }) .from(ssoProviders) .where(eq(ssoProviders.enabled, true)) .orderBy(asc(ssoProviders.displayOrder), asc(ssoProviders.id)); } async listEnabled(): Promise { return this.context.drizzle .select() .from(ssoProviders) .where(eq(ssoProviders.enabled, true)) .orderBy(asc(ssoProviders.displayOrder), asc(ssoProviders.id)); } async listAll(): Promise { return this.context.drizzle .select() .from(ssoProviders) .orderBy(asc(ssoProviders.displayOrder), asc(ssoProviders.id)); } async findById(id: number): Promise { const rows = await this.context.drizzle .select() .from(ssoProviders) .where(eq(ssoProviders.id, id)) .limit(1); return rows[0] ?? null; } async findFirstEnabledOidcLike(): Promise { const rows = await this.context.drizzle .select() .from(ssoProviders) .where(eq(ssoProviders.enabled, true)) .orderBy(asc(ssoProviders.displayOrder), asc(ssoProviders.id)); return ( rows.find( (row) => row.type === "oidc" || row.type === "github" || row.type === "google", ) ?? null ); } async create(provider: NewSsoProviderRecord): Promise { const rows = await insertReturning(this.context, ssoProviders, provider); await this.afterWrite(); return rows[0]; } async update( id: number, update: SsoProviderUpdate, ): Promise { const rows = await updateReturning( this.context, ssoProviders, update, eq(ssoProviders.id, id), ); await this.afterWrite(); return rows[0] ?? null; } async delete(id: number): Promise { const result = await this.context.drizzle .delete(ssoProviders) .where(eq(ssoProviders.id, id)); if (rowsAffected(result) > 0) { await this.afterWrite(); } return rowsAffected(result) > 0; } async countUsersByProviderId(providerId: number): Promise { const rows = await this.context.drizzle .select({ id: users.id }) .from(users) .where(eq(users.ssoProviderId, providerId)); return rows.length; } private async afterWrite(): Promise { await this.onWrite?.(); } }