Files
Alfred/src/server/db/providers.ts

172 lines
5.0 KiB
TypeScript

import type Database from "bun:sqlite";
import { desc, eq, like } from "drizzle-orm";
import type { CreateProviderRequest, Provider, ProviderOption, UpdateProviderRequest } from "../../shared/api";
import type { Logger } from "../logger";
import { paginateQuery, wrap } from "./connection";
import { providers } from "./schema";
export function createProvider(
raw: Database,
request: CreateProviderRequest,
logger: Logger,
): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const name = request.name.trim();
if (!name) return { error: "供应商名称不能为空", status: 400 };
const baseUrl = request.baseUrl.trim();
if (!baseUrl) return { error: "Base URL 不能为空", status: 400 };
const apiKey = request.apiKey.trim();
if (!apiKey) return { error: "API Key 不能为空", status: 400 };
const id = crypto.randomUUID();
const now = new Date().toISOString();
try {
db.insert(providers)
.values({
apiKey,
baseUrl,
createdAt: now,
id,
name,
type: request.type,
updatedAt: now,
})
.run();
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
if (msg.includes("UNIQUE constraint")) {
return { error: "供应商名称已存在", status: 409 };
}
logger.error({ error: msg, operation: "create", table: "providers" }, "数据库操作失败");
throw e;
}
const row = db.select().from(providers).where(eq(providers.id, id)).get();
return { provider: toProvider(row!) };
}
export function deleteProvider(
raw: Database,
id: string,
_logger: Logger,
): { error: string; status: number } | { success: true } {
const db = wrap(raw);
const existing = db.select().from(providers).where(eq(providers.id, id)).get();
if (!existing) return { error: "供应商不存在", status: 404 };
db.delete(providers).where(eq(providers.id, id)).run();
return { success: true };
}
export function getProvider(raw: Database, id: string): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const row = db.select().from(providers).where(eq(providers.id, id)).get();
if (!row) return { error: "供应商不存在", status: 404 };
return { provider: toProvider(row) };
}
export function listProviderOptions(raw: Database): ProviderOption[] {
const db = wrap(raw);
const rows = db
.select({ id: providers.id, name: providers.name, type: providers.type })
.from(providers)
.orderBy(desc(providers.createdAt))
.all();
return rows;
}
export function listProviders(
raw: Database,
options: { keyword?: string; page: number; pageSize: number },
): { items: Provider[]; page: number; pageSize: number; total: number } {
const conditions = [];
if (options.keyword) {
const pattern = `%${options.keyword}%`;
conditions.push(like(providers.name, pattern));
}
return paginateQuery(raw, providers, {
conditions,
mapRow: toProvider,
orderBy: () => desc(providers.createdAt),
page: options.page,
pageSize: options.pageSize,
});
}
export function updateProvider(
raw: Database,
id: string,
request: UpdateProviderRequest,
logger: Logger,
): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const existing = db.select().from(providers).where(eq(providers.id, id)).get();
if (!existing) return { error: "供应商不存在", status: 404 };
const updates: Partial<typeof providers.$inferInsert> = {
updatedAt: new Date().toISOString(),
};
const name = request.name?.trim();
if (name === "") return { error: "供应商名称不能为空", status: 400 };
if (name !== undefined && name !== existing.name) {
updates.name = name;
}
const baseUrl = request.baseUrl?.trim();
if (baseUrl === "") return { error: "Base URL 不能为空", status: 400 };
if (baseUrl !== undefined) {
updates.baseUrl = baseUrl;
}
const apiKey = request.apiKey?.trim();
if (apiKey === "") return { error: "API Key 不能为空", status: 400 };
if (apiKey !== undefined) {
updates.apiKey = apiKey;
}
if (request.type !== undefined) {
updates.type = request.type;
}
if (Object.keys(updates).length === 1 && updates.updatedAt) {
return { provider: toProvider(existing) };
}
try {
db.update(providers).set(updates).where(eq(providers.id, id)).run();
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
if (msg.includes("UNIQUE constraint")) {
return { error: "供应商名称已存在", status: 409 };
}
logger.error({ error: msg, operation: "update", table: "providers" }, "数据库操作失败");
throw e;
}
const updated = db.select().from(providers).where(eq(providers.id, id)).get();
return { provider: toProvider(updated!) };
}
function toProvider(row: typeof providers.$inferSelect): Provider {
return {
apiKey: row.apiKey,
baseUrl: row.baseUrl,
createdAt: row.createdAt,
id: row.id,
name: row.name,
type: row.type,
updatedAt: row.updatedAt,
};
}