Add method to intelligently insert/update.

The `upsert()` method can both create and update tasks. The method
checks for an `id` propery to determine whether to `INSERT` or `UPDATE`.

A successful operation returns a `ServiceResponse` object with the
inserted task `id`, which can be used to fetch updated information if
needed.

The `NewTask` type is exported for use in form actions, etc.
This commit is contained in:
themodrnhakr 2025-09-29 21:13:26 -05:00
parent f63f5ccc5a
commit eddaf02824

View File

@ -1,7 +1,7 @@
import { type DB, db } from "$lib/server/db/db"; import { type DB, db } from "$lib/server/db/db";
import type { tasks, taskTypes } from "$lib/server/db/schema/tasks"; import { tasks, type taskTypes } from "$lib/server/db/schema/tasks";
import type { ServiceResponse } from "$lib/server/services/service.types"; import type { ServiceResponse } from "$lib/server/services/service.types";
import type { InferSelectModel } from "drizzle-orm"; import { eq, type InferSelectModel } from "drizzle-orm";
import logger from "../logger"; import logger from "../logger";
export type Task = InferSelectModel<typeof tasks> & { export type Task = InferSelectModel<typeof tasks> & {
@ -12,6 +12,8 @@ export type TaskOrNull = InferSelectModel<typeof tasks> & {
type: InferSelectModel<typeof taskTypes> | null; type: InferSelectModel<typeof taskTypes> | null;
}; };
export type NewTask = typeof tasks.$inferInsert;
class TasksService { class TasksService {
private db: DB; private db: DB;
private caller: "internal" | "api"; private caller: "internal" | "api";
@ -90,6 +92,33 @@ class TasksService {
}) })
); );
} }
public async upsert(taskData: NewTask): Promise<ServiceResponse<{ id: number }, "INTERNAL_ERROR" | "VALIDATION_ERROR">> {
try {
if (taskData.id) {
const updated = await this.db.update(tasks)
.set(taskData)
.where(eq(tasks.id, taskData.id))
.returning({ id: tasks.id });
if (updated.length === 0) {
return { status: "failure", code: "VALIDATION_ERROR", error: `Task with ID ${taskData.id} not found for update.` };
}
return { status: "ok", data: { id: updated[0].id } };
} else {
const created = await this.db.insert(tasks)
.values(taskData)
.returning({ id: tasks.id });
if (created.length === 0) {
throw new Error("Insert operation failed to return the new task.");
}
return { status: "ok", data: { id: created[0].id } };
}
}
catch (error) {
logger.error({ msg: "Error upserting task.", error });
return { status: "failure", error: "An internal server error occurred while saving the task.", code: "INTERNAL_ERROR" };
}
}
} }
export default TasksService; export default TasksService;