feat: add AI catalog description generation
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||
import { z } from "zod";
|
||||
import { isPrincipalContext, requirePermission } from "../auth/authorization.js";
|
||||
import type { CatalogOperationCoordinator } from "../catalog/operation-coordinator.js";
|
||||
import {
|
||||
CatalogOperationInProgressError,
|
||||
CatalogUnavailableError,
|
||||
type CatalogRepository,
|
||||
} from "../catalog/types.js";
|
||||
|
||||
const idSchema = z.uuid();
|
||||
const consolidationSchema = z.object({
|
||||
target: z.enum(["tables", "columns"]),
|
||||
targetIds: z.array(idSchema).min(1).max(10_000),
|
||||
}).strict();
|
||||
|
||||
function manage(request: FastifyRequest, reply: FastifyReply) {
|
||||
return isPrincipalContext(requirePermission(request, reply, "database.manage"));
|
||||
}
|
||||
|
||||
function safeError(reply: FastifyReply, error: unknown) {
|
||||
if (error instanceof CatalogUnavailableError) {
|
||||
return reply.code(503).send({ code: "catalog_unavailable", message: "Database catalog is unavailable." });
|
||||
}
|
||||
if (error instanceof CatalogOperationInProgressError) {
|
||||
return reply.code(409).send({
|
||||
code: "database_operation_in_progress",
|
||||
message: "A database operation is already in progress.",
|
||||
});
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return reply.code(400).send({
|
||||
code: "description_consolidation_invalid",
|
||||
message: "Description consolidation request is invalid.",
|
||||
});
|
||||
}
|
||||
return reply.code(500).send({
|
||||
code: "description_consolidation_failed",
|
||||
message: "Description consolidation failed.",
|
||||
});
|
||||
}
|
||||
|
||||
export function catalogDescriptionConsolidationRoutes(
|
||||
app: FastifyInstance,
|
||||
deps: { repository: CatalogRepository; operations: CatalogOperationCoordinator },
|
||||
): void {
|
||||
app.post("/catalog/databases/:databaseId/descriptions/consolidate", async (request, reply) => {
|
||||
if (!manage(request, reply)) return reply;
|
||||
try {
|
||||
const databaseId = idSchema.parse((request.params as { databaseId?: unknown }).databaseId);
|
||||
const input = consolidationSchema.parse(request.body);
|
||||
const targetIds = [...new Set(input.targetIds)];
|
||||
const result = await deps.operations.run(
|
||||
databaseId,
|
||||
async () => await deps.repository.consolidateGeneratedDescriptions(
|
||||
databaseId,
|
||||
input.target,
|
||||
targetIds,
|
||||
),
|
||||
);
|
||||
if (!result) {
|
||||
return reply.code(404).send({
|
||||
code: "catalog_target_not_found",
|
||||
message: "The database or one or more selected catalog targets were not found.",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
return safeError(reply, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user