import { dbGetAll, dbGetOne } from "@/lib/db/drizzle-client"; import { DeleteMaterial, DeleteProjectMaterial, Material, MaterialId, ProjectMaterial, UpdateProjectMaterial, } from "../domain/models"; import { db } from "@/database/db"; import { materials, projectMaterials } from "@/database/schema"; import { and, desc, eq, inArray, sql } from "drizzle-orm"; import { createLogRecord } from "@/server/log"; import { UserId } from "@/server/user/domain/models"; import { MaterialRepository } from "../domain/repositories"; import { ProjectId } from "@/server/project/domain/models"; class MaterialRepositoryImpl implements MaterialRepository { getAll(): Promise { return dbGetAll("materials", { orderBy: desc(materials.name), }) as Promise; } async getById(materialId: MaterialId): Promise { const data = await dbGetOne("materials", { where: eq(materials.id, materialId.value), }); return data as Material; } async getProjectMaterialByProject( materialId: MaterialId, projectId: ProjectId ): Promise { const data = await dbGetOne("projectMaterials", { where: and( eq(projectMaterials.materialId, materialId.value), eq(projectMaterials.projectId, projectId.value) ), }); return data as ProjectMaterial; } async create(data: Material, userId: UserId): Promise { await db.transaction(async (tx) => { const createPromise = db.insert(materials).values(data); const logRecordPromise = createLogRecord(tx, { userId: userId.value, modifiedItem: `Material-${data.name} creado`, eventType: "crear", tableName: "materials", item: data, }); await Promise.all([createPromise, logRecordPromise]); }); return data; } async createProjectMaterial( data: ProjectMaterial, userId: UserId ): Promise { await db.transaction(async (tx) => { const material = await this.getById({ value: data.materialId }); const createPromise = tx .insert(projectMaterials) .values(data) .onConflictDoUpdate({ target: [projectMaterials.materialId, projectMaterials.projectId], set: { requiredQuantity: sql`${projectMaterials.requiredQuantity} + ${data.requiredQuantity}`, availableQuantity: sql`${projectMaterials.availableQuantity} + ${data.availableQuantity}`, }, }); const logRecordPromise = createLogRecord(tx, { userId: userId.value, modifiedItem: `Material-${material.name}-${data.projectName}`, eventType: "crear", tableName: "projectMaterials", item: data, }); await Promise.all([createPromise, logRecordPromise]); }); return data; } async updateProjectMaterial( data: Partial, userId: UserId ): Promise> { const { projectId, materialId, projectName, ...fieldsToUpdate } = data; await db.transaction(async (tx) => { const material = await this.getById({ value: data.materialId! }); const updatePromise = tx .update(projectMaterials) .set(fieldsToUpdate) .where( and( eq(projectMaterials.materialId, data.materialId!), eq(projectMaterials.projectId, data.projectId!) ) ); const logRecordPromise = createLogRecord(tx, { userId: userId.value, modifiedItem: `Material-${material.name}-${data.projectName}`, eventType: "modificar", tableName: "projectMaterials", item: fieldsToUpdate, }); await Promise.all([updatePromise, logRecordPromise]); }); return data; } async delete(data: DeleteMaterial, userId: UserId): Promise { return await db.transaction(async (tx) => { const deletedMaterials = await tx .delete(materials) .where(inArray(materials.id, data.materialIds)) .returning(); const logRecordPromises = deletedMaterials.map((item) => createLogRecord(tx, { userId: userId.value, modifiedItem: `Material-${item.name}`, eventType: "eliminar", tableName: "materials", item: deletedMaterials, }) ); await Promise.all([...logRecordPromises]); return deletedMaterials as Material[]; }); } async deleteProjectMaterials( data: DeleteProjectMaterial, userId: UserId ): Promise { await db.transaction(async (tx) => { const material = await this.getById({ value: data.materialId }); const deletePromise = tx .delete(projectMaterials) .where( and( eq(projectMaterials.materialId, data.materialId), eq(projectMaterials.projectId, data.projectId) ) ) .returning(); const logRecordPromises = createLogRecord(tx, { userId: userId.value, modifiedItem: `Material-${material.name}-${data.projectName}`, eventType: "eliminar", tableName: "materials", item: data, }); await Promise.all([deletePromise, logRecordPromises]); }); return data; } } export const defaultMaterialRepository = new MaterialRepositoryImpl();