261 lines
6.9 KiB
TypeScript
261 lines
6.9 KiB
TypeScript
|
|
import type { RowDataPacket, ResultSetHeader } from "mysql2";
|
||
|
|
|
||
|
|
import { db } from "@/src/lib/db";
|
||
|
|
import type {
|
||
|
|
Macchina,
|
||
|
|
MacchinaWithDetails,
|
||
|
|
MacchinaCreateInput,
|
||
|
|
MacchinaUpdateInput,
|
||
|
|
TipoMacchina,
|
||
|
|
} from "@/src/types/macchina";
|
||
|
|
|
||
|
|
type MacchinaRow = Macchina & RowDataPacket;
|
||
|
|
type MacchinaWithDetailsRow = MacchinaWithDetails & RowDataPacket;
|
||
|
|
|
||
|
|
export async function listMacchine(): Promise<MacchinaWithDetails[]> {
|
||
|
|
const [rows] = await db.execute<MacchinaWithDetailsRow[]>(`
|
||
|
|
SELECT
|
||
|
|
m.id,
|
||
|
|
m.nome,
|
||
|
|
m.tipo,
|
||
|
|
m.id_padre,
|
||
|
|
m.id_stabilimento,
|
||
|
|
m.colore_testo,
|
||
|
|
s.descrizione AS stabilimento_nome,
|
||
|
|
p.nome AS padre_nome
|
||
|
|
FROM macchine_parti m
|
||
|
|
LEFT JOIN stabilimenti s ON s.id = m.id_stabilimento
|
||
|
|
LEFT JOIN macchine_parti p ON p.id = m.id_padre
|
||
|
|
ORDER BY ISNULL(m.id_padre) DESC, m.id_padre ASC, m.nome ASC
|
||
|
|
`);
|
||
|
|
|
||
|
|
return rows.map((row) => ({
|
||
|
|
id: row.id,
|
||
|
|
nome: row.nome,
|
||
|
|
tipo: row.tipo as TipoMacchina,
|
||
|
|
id_padre: row.id_padre,
|
||
|
|
id_stabilimento: row.id_stabilimento,
|
||
|
|
colore_testo: row.colore_testo || "#000000",
|
||
|
|
stabilimento_nome: row.stabilimento_nome,
|
||
|
|
padre_nome: row.padre_nome,
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getMacchinaById(id: number): Promise<MacchinaWithDetails | null> {
|
||
|
|
const [rows] = await db.execute<MacchinaWithDetailsRow[]>(
|
||
|
|
`SELECT
|
||
|
|
m.id,
|
||
|
|
m.nome,
|
||
|
|
m.tipo,
|
||
|
|
m.id_padre,
|
||
|
|
m.id_stabilimento,
|
||
|
|
m.colore_testo,
|
||
|
|
s.descrizione AS stabilimento_nome,
|
||
|
|
p.nome AS padre_nome
|
||
|
|
FROM macchine_parti m
|
||
|
|
LEFT JOIN stabilimenti s ON s.id = m.id_stabilimento
|
||
|
|
LEFT JOIN macchine_parti p ON p.id = m.id_padre
|
||
|
|
WHERE m.id = :id
|
||
|
|
LIMIT 1`,
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
|
||
|
|
const row = rows[0];
|
||
|
|
if (!row) return null;
|
||
|
|
|
||
|
|
return {
|
||
|
|
id: row.id,
|
||
|
|
nome: row.nome,
|
||
|
|
tipo: row.tipo as TipoMacchina,
|
||
|
|
id_padre: row.id_padre,
|
||
|
|
id_stabilimento: row.id_stabilimento,
|
||
|
|
colore_testo: row.colore_testo || "#000000",
|
||
|
|
stabilimento_nome: row.stabilimento_nome,
|
||
|
|
padre_nome: row.padre_nome,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function createMacchina(input: MacchinaCreateInput): Promise<Macchina> {
|
||
|
|
const { nome, tipo, id_padre, id_stabilimento, colore_testo = "#000000" } = input;
|
||
|
|
|
||
|
|
let stabilimentoId = id_stabilimento;
|
||
|
|
|
||
|
|
if (tipo === "macchina" && !id_padre && !stabilimentoId) {
|
||
|
|
throw new Error("Stabilimento obbligatorio per macchine di livello root");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (id_padre && !stabilimentoId) {
|
||
|
|
const [parentRows] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id_stabilimento FROM macchine_parti WHERE id = :id_padre LIMIT 1",
|
||
|
|
{ id_padre }
|
||
|
|
);
|
||
|
|
const parent = parentRows[0];
|
||
|
|
if (parent?.id_stabilimento) {
|
||
|
|
stabilimentoId = parent.id_stabilimento;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const [result] = await db.execute<ResultSetHeader>(
|
||
|
|
`INSERT INTO macchine_parti (nome, tipo, id_padre, id_stabilimento, colore_testo)
|
||
|
|
VALUES (:nome, :tipo, :id_padre, :id_stabilimento, :colore_testo)`,
|
||
|
|
{
|
||
|
|
nome,
|
||
|
|
tipo,
|
||
|
|
id_padre: id_padre || null,
|
||
|
|
id_stabilimento: stabilimentoId || null,
|
||
|
|
colore_testo,
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
return {
|
||
|
|
id: result.insertId,
|
||
|
|
nome,
|
||
|
|
tipo,
|
||
|
|
id_padre: id_padre || null,
|
||
|
|
id_stabilimento: stabilimentoId || null,
|
||
|
|
colore_testo,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function updateMacchina(
|
||
|
|
id: number,
|
||
|
|
input: MacchinaUpdateInput
|
||
|
|
): Promise<MacchinaWithDetails | null> {
|
||
|
|
const current = await getMacchinaById(id);
|
||
|
|
if (!current) return null;
|
||
|
|
|
||
|
|
const nome = input.nome ?? current.nome;
|
||
|
|
const tipo = input.tipo ?? current.tipo;
|
||
|
|
const id_padre = input.id_padre !== undefined ? input.id_padre : current.id_padre;
|
||
|
|
const colore_testo = input.colore_testo ?? current.colore_testo;
|
||
|
|
|
||
|
|
let id_stabilimento = input.id_stabilimento !== undefined
|
||
|
|
? input.id_stabilimento
|
||
|
|
: current.id_stabilimento;
|
||
|
|
|
||
|
|
if (id_padre && !id_stabilimento) {
|
||
|
|
const [parentRows] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id_stabilimento FROM macchine_parti WHERE id = :id_padre LIMIT 1",
|
||
|
|
{ id_padre }
|
||
|
|
);
|
||
|
|
const parent = parentRows[0];
|
||
|
|
if (parent?.id_stabilimento) {
|
||
|
|
id_stabilimento = parent.id_stabilimento;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
await db.execute(
|
||
|
|
`UPDATE macchine_parti
|
||
|
|
SET nome = :nome, tipo = :tipo, id_padre = :id_padre,
|
||
|
|
id_stabilimento = :id_stabilimento, colore_testo = :colore_testo
|
||
|
|
WHERE id = :id`,
|
||
|
|
{
|
||
|
|
id,
|
||
|
|
nome,
|
||
|
|
tipo,
|
||
|
|
id_padre: id_padre || null,
|
||
|
|
id_stabilimento: id_stabilimento || null,
|
||
|
|
colore_testo,
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
return getMacchinaById(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function deleteMacchina(id: number): Promise<boolean> {
|
||
|
|
const [childRows] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id FROM macchine_parti WHERE id_padre = :id",
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (childRows.length > 0) {
|
||
|
|
for (const child of childRows) {
|
||
|
|
await deleteMacchina(child.id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const [result] = await db.execute<ResultSetHeader>(
|
||
|
|
"DELETE FROM macchine_parti WHERE id = :id",
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
|
||
|
|
return result.affectedRows > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function cloneMacchina(
|
||
|
|
id: number,
|
||
|
|
newParentId: number | null = null
|
||
|
|
): Promise<Macchina | null> {
|
||
|
|
const original = await getMacchinaById(id);
|
||
|
|
if (!original) return null;
|
||
|
|
|
||
|
|
let copyName = `${original.nome} (copia)`;
|
||
|
|
let counter = 1;
|
||
|
|
|
||
|
|
const [existingRows] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT nome FROM macchine_parti WHERE nome LIKE :pattern",
|
||
|
|
{ pattern: `${original.nome} (copia%` }
|
||
|
|
);
|
||
|
|
|
||
|
|
const existingNames = new Set(existingRows.map((r) => r.nome));
|
||
|
|
while (existingNames.has(copyName)) {
|
||
|
|
copyName = `${original.nome} (copia ${counter})`;
|
||
|
|
counter++;
|
||
|
|
}
|
||
|
|
|
||
|
|
let stabilimentoId = original.id_stabilimento;
|
||
|
|
if (newParentId) {
|
||
|
|
const [parentRows] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id_stabilimento FROM macchine_parti WHERE id = :id LIMIT 1",
|
||
|
|
{ id: newParentId }
|
||
|
|
);
|
||
|
|
if (parentRows[0]?.id_stabilimento) {
|
||
|
|
stabilimentoId = parentRows[0].id_stabilimento;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const newMacchina = await createMacchina({
|
||
|
|
nome: copyName,
|
||
|
|
tipo: original.tipo,
|
||
|
|
id_padre: newParentId ?? original.id_padre,
|
||
|
|
id_stabilimento: stabilimentoId,
|
||
|
|
colore_testo: original.colore_testo,
|
||
|
|
});
|
||
|
|
|
||
|
|
const [children] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id FROM macchine_parti WHERE id_padre = :id",
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
|
||
|
|
for (const child of children) {
|
||
|
|
await cloneMacchina(child.id, newMacchina.id);
|
||
|
|
}
|
||
|
|
|
||
|
|
return newMacchina;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getChildrenCount(id: number): Promise<number> {
|
||
|
|
const [rows] = await db.execute<(RowDataPacket & { count: number })[]>(
|
||
|
|
"SELECT COUNT(*) as count FROM macchine_parti WHERE id_padre = :id",
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
return rows[0]?.count ?? 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getAllDescendantIds(id: number): Promise<number[]> {
|
||
|
|
const ids: number[] = [];
|
||
|
|
|
||
|
|
const [children] = await db.execute<MacchinaRow[]>(
|
||
|
|
"SELECT id FROM macchine_parti WHERE id_padre = :id",
|
||
|
|
{ id }
|
||
|
|
);
|
||
|
|
|
||
|
|
for (const child of children) {
|
||
|
|
ids.push(child.id);
|
||
|
|
const descendantIds = await getAllDescendantIds(child.id);
|
||
|
|
ids.push(...descendantIds);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ids;
|
||
|
|
}
|