172 lines
5.0 KiB
TypeScript
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,
|
|
};
|
|
}
|