metis-desk/modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts

63 lines
2.8 KiB
TypeScript
Raw Normal View History

2026-10-08 14:43:34 +00:00
import type { Sequelize } from "sequelize";
import { QueryTypes } from "sequelize";
type Entry = {
eventId?: string;
id: string;
companyId: string;
companyName: string;
name: string;
recordedAt: string | null;
actorName: string | null;
};
/** Consulta definiciones por stockKey, nunca por nombres editables. */
export class ResourceDashboardReader {
constructor(private readonly database: Sequelize) {}
2026-10-10 10:01:58 +00:00
stats(companyId?: string) {
return this.database.query<{ companyId: string; count: number }>(
"SELECT companyId,COUNT(*) AS count FROM resources WHERE (:companyId IS NULL OR companyId=:companyId) GROUP BY companyId",
{ type: QueryTypes.SELECT, replacements: { companyId: companyId ?? null } }
);
}
2026-10-10 10:01:58 +00:00
async entries(companyId?: string, issue?: string, page = 1) {
const expiry = issue === "certificate" || issue === "license";
const join = expiry
? " JOIN resource_definitions d ON d.id=r.templateId JOIN resource_definitions f ON f.stockKey='field:expires'"
: "";
const where =
"WHERE (:companyId IS NULL OR r.companyId=:companyId)" +
(expiry
? " AND d.stockKey=:stockKey AND JSON_EXTRACT(r.`values`,'$.active')=true AND JSON_UNQUOTE(JSON_EXTRACT(r.`values`,CONCAT('$.characteristics.\"',f.id,'\"'))) BETWEEN :today AND :until"
: "");
const today = new Date().toISOString().slice(0, 10);
const until = new Date(Date.now() + 30 * 86400000).toISOString().slice(0, 10);
const replacements = {
companyId: companyId ?? null,
stockKey: issue === "certificate" ? "template:certificate" : "template:software_license",
today,
until,
offset: (page - 1) * 10,
};
const counts = await this.database.query<{ total: number }>(
`SELECT COUNT(*) AS total FROM resources r ${join} ${where}`,
{ type: QueryTypes.SELECT, replacements }
);
const items = await this.database.query<Entry>(
`SELECT r.id,r.companyId,c.name AS companyName,JSON_UNQUOTE(JSON_EXTRACT(r.\`values\`,'$.name')) AS name,NULL AS recordedAt,NULL AS actorName FROM resources r JOIN companies c ON c.id=r.companyId ${join} ${where} ORDER BY name,r.id LIMIT 10 OFFSET :offset`,
{ type: QueryTypes.SELECT, replacements }
);
2026-10-10 10:01:58 +00:00
return { total: Number(counts[0]?.total ?? 0), items };
}
2026-10-10 10:01:58 +00:00
activity(companyId?: string) {
return this.database.query<Entry>(
"SELECT r.id,h.id AS eventId,r.companyId,c.name AS companyName,JSON_UNQUOTE(JSON_EXTRACT(r.`values`,'$.name')) AS name,h.recordedAt,u.name AS actorName FROM resource_revisions h JOIN resources r ON r.id=h.resourceId JOIN companies c ON c.id=r.companyId LEFT JOIN users u ON u.id=h.actorId WHERE (:companyId IS NULL OR r.companyId=:companyId) ORDER BY h.recordedAt DESC,h.id DESC LIMIT 6",
{ type: QueryTypes.SELECT, replacements: { companyId: companyId ?? null } }
);
}
}