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<Material[]> {
return dbGetAll("materials", {
orderBy: desc(materials.name),
}) as Promise<Material[]>;
}
async getById(materialId: MaterialId): Promise<Material> {
const data = await dbGetOne("materials", {
where: eq(materials.id, materialId.value),
});
return data as Material;
}
async getProjectMaterialByProject(
materialId: MaterialId,
projectId: ProjectId
): Promise<ProjectMaterial> {
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<Material> {
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<ProjectMaterial> {
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<ProjectMaterial>,
userId: UserId
): Promise<Partial<ProjectMaterial>> {
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<Material[]> {
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<DeleteProjectMaterial> {
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();