1
mirror of https://github.com/jakejarvis/hoot.git synced 2025-10-18 20:14:25 -04:00
Files
hoot/server/repos/providers.ts

78 lines
2.1 KiB
TypeScript

import "server-only";
import { and, eq, sql } from "drizzle-orm";
import { db } from "@/server/db/client";
import { type providerCategory, providers } from "@/server/db/schema";
export type ResolveProviderInput = {
category: (typeof providerCategory.enumValues)[number];
domain?: string | null;
name?: string | null;
};
/**
* Resolve a provider id by exact domain when provided, falling back to case-insensitive name.
*/
export async function resolveProviderId(
input: ResolveProviderInput,
): Promise<string | null> {
const { category } = input;
const domain = input.domain?.toLowerCase() ?? null;
const name = input.name?.trim() ?? null;
if (domain) {
const byDomain = await db
.select({ id: providers.id })
.from(providers)
.where(
and(eq(providers.category, category), eq(providers.domain, domain)),
)
.limit(1);
if (byDomain[0]?.id) return byDomain[0].id;
}
if (name) {
const byName = await db
.select({ id: providers.id })
.from(providers)
.where(
and(
eq(providers.category, category),
sql`lower(${providers.name}) = lower(${name})`,
),
)
.limit(1);
if (byName[0]?.id) return byName[0].id;
}
return null;
}
/** Resolve a provider id, creating a provider row when not found. */
export async function resolveOrCreateProviderId(
input: ResolveProviderInput,
): Promise<string | null> {
const existing = await resolveProviderId(input);
if (existing) return existing;
const name = input.name?.trim();
if (!name) return null;
const domain = input.domain?.toLowerCase() ?? null;
// Use a simple slug derived from name for uniqueness within category
const slug = name
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)+/g, "");
try {
const inserted = await db
.insert(providers)
.values({
category: input.category,
name,
domain: domain ?? undefined,
slug,
})
.returning({ id: providers.id });
return inserted[0]?.id ?? null;
} catch {
// Possible race with another insert; try resolve again
return resolveProviderId(input);
}
}