This commit is contained in:
user
2026-03-27 20:06:38 +02:00
commit 8c45efc92e
544 changed files with 33060 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
import { CreateTask, Task, TaskStatus, TaskType, UpdateTask } from "./data";
import { ResultAsync, errAsync, okAsync } from "neverthrow";
import { FlowExecCtx } from "@core/flow.execution.context";
import { Database, and, asc, eq, inArray } from "@pkg/db";
import { task } from "@pkg/db/schema";
import { type Err } from "@pkg/result";
import { taskErrors } from "./errors";
import { logger } from "@pkg/logger";
export class TasksRepository {
constructor(private db: Database) {}
createTask(fctx: FlowExecCtx, taskData: CreateTask): ResultAsync<Task, Err> {
logger.info("Creating new task", { ...fctx, taskId: taskData.id });
return ResultAsync.fromPromise(
this.db
.insert(task)
.values({
id: taskData.id,
type: taskData.type,
status: taskData.status || TaskStatus.PENDING,
progress: taskData.progress || 0,
payload: taskData.payload ?? null,
userId: taskData.userId,
resourceId: taskData.resourceId,
createdAt: new Date(),
updatedAt: new Date(),
})
.returning()
.execute(),
(error) =>
taskErrors.createTaskFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).map((result) => result[0] as Task);
}
getTaskById(fctx: FlowExecCtx, taskId: string): ResultAsync<Task, Err> {
return ResultAsync.fromPromise(
this.db.query.task.findFirst({
where: eq(task.id, taskId),
}),
(error) =>
taskErrors.getTaskFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).andThen((result) => {
if (!result) {
return errAsync(taskErrors.taskNotFound(fctx, taskId));
}
return okAsync(result as Task);
});
}
updateTask(
fctx: FlowExecCtx,
taskId: string,
updates: UpdateTask,
): ResultAsync<Task, Err> {
return this.getTaskById(fctx, taskId).andThen(() =>
ResultAsync.fromPromise(
this.db
.update(task)
.set({ ...updates, updatedAt: new Date() })
.where(eq(task.id, taskId))
.returning()
.execute(),
(error) =>
taskErrors.updateTaskFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).andThen((updateResult) => {
if (!updateResult[0]) {
return errAsync(taskErrors.taskNotFound(fctx, taskId));
}
return okAsync(updateResult[0] as Task);
}),
);
}
deleteTask(fctx: FlowExecCtx, taskId: string): ResultAsync<boolean, Err> {
return ResultAsync.fromPromise(
this.db.delete(task).where(eq(task.id, taskId)).execute(),
(error) =>
taskErrors.deleteTaskFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).map(() => true);
}
getTasksByStatuses(
fctx: FlowExecCtx,
statuses: TaskStatus[],
): ResultAsync<Task[], Err> {
return ResultAsync.fromPromise(
this.db
.select()
.from(task)
.where(inArray(task.status, statuses))
.orderBy(asc(task.createdAt)),
(error) =>
taskErrors.getTasksByStatusFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).map((result) => result as Task[]);
}
getTasksByTypeAndStatuses(
fctx: FlowExecCtx,
type: TaskType,
statuses: TaskStatus[],
): ResultAsync<Task[], Err> {
return ResultAsync.fromPromise(
this.db
.select()
.from(task)
.where(and(eq(task.type, type), inArray(task.status, statuses)))
.orderBy(asc(task.createdAt)),
(error) =>
taskErrors.getTasksByStatusFailed(
fctx,
error instanceof Error ? error.message : String(error),
),
).map((result) => result as Task[]);
}
markTaskAsCompleted(
fctx: FlowExecCtx,
taskId: string,
result?: Record<string, any>,
): ResultAsync<Task, Err> {
return this.updateTask(fctx, taskId, {
status: TaskStatus.COMPLETED,
progress: 100,
result: result ?? null,
completedAt: new Date(),
});
}
markTaskAsFailed(
fctx: FlowExecCtx,
taskId: string,
error: any,
): ResultAsync<Task, Err> {
return this.updateTask(fctx, taskId, {
status: TaskStatus.FAILED,
error: {
code: error.code || "UNKNOWN_ERROR",
message: error.message || "Task failed",
detail: error.detail,
timestamp: new Date(),
},
completedAt: new Date(),
});
}
}