leistungsbilanz-ts/tests/external-model-xlsx-foundation.test.ts

87 lines
3.5 KiB
TypeScript

import path from "node:path";
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
import { createDatabaseContext } from "../src/db/database-context.js";
import { parseExternalModelStateSnapshot } from "../src/domain/models/project-state-snapshot.model.js";
import { createDefaultExternalModelConfiguration } from "../src/external-model/configuration/external-model-configuration.js";
const lowerId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee-ffffffff";
const upperId = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE-FFFFFFFF";
function fullBatch(id: string, importedAtIso: string) {
return {
id,
projectId: "p",
sourceId: "s",
importKind: "follow_up" as const,
importedAtIso,
fileName: `${id}.xlsx`,
sha256: "a".repeat(64),
objectCount: 1,
appliedProjectRevision: 3,
configurationSnapshot: createDefaultExternalModelConfiguration(),
originalContentBase64: "AA==",
document: {
sheetName: "Bauteilliste",
headerRowNumber: 1,
firstDataRowNumber: 3,
firstDataColumnNumber: 1,
columns: [],
rows: [],
issues: [],
},
};
}
describe("Linear XLSX external model foundation", () => {
it("keeps only the newest batch complete", () => {
const newest = fullBatch("new", "2026-02-01T00:00:00.000Z");
const older = {
...fullBatch("old", "2026-01-01T00:00:00.000Z"),
appliedProjectRevision: null,
configurationSnapshot: null,
originalContentBase64: null,
document: null,
};
assert.doesNotThrow(() => parseExternalModelStateSnapshot({
source: { id: "s", projectId: "p", name: "Revit", sourceType: "revit_xlsx" },
importBatches: [older, newest],
roomMappings: [],
objects: [],
}));
assert.throws(() => parseExternalModelStateSnapshot({
source: { id: "s", projectId: "p", name: "Revit", sourceType: "revit_xlsx" },
importBatches: [newest, fullBatch("newer", "2026-03-01T00:00:00.000Z")],
roomMappings: [],
objects: [],
}), /Nur der letzte Importbatch/);
});
it("compares Worksharing-IDs exactly and allows duplicate IfcGUID values", () => {
const context = createDatabaseContext(":memory:");
try {
migrate(context.db, { migrationsFolder: path.resolve("src", "db", "migrations") });
context.sqlite.exec(`
INSERT INTO projects (id, name) VALUES ('p', 'Projekt');
INSERT INTO external_model_sources (id, project_id, name) VALUES ('s', 'p', 'Revit');
INSERT INTO external_import_batches
(id, project_id, source_id, import_kind, imported_at_iso, file_name, sha256, object_count)
VALUES ('b', 'p', 's', 'initial', '2026-01-01T00:00:00.000Z', 'model.xlsx', '${"a".repeat(64)}', 2);
`);
const insert = context.sqlite.prepare(`
INSERT INTO external_model_objects
(id, project_id, source_id, worksharing_id, ifc_guid, device_type_id,
last_seen_import_batch_id, last_accepted_import_batch_id,
accepted_source_values, planning_values, overridden_fields)
VALUES (?, 'p', 's', ?, 'same-IfcGUID', 'type', 'b', 'b', '{}', '{}', '[]')
`);
insert.run("o1", lowerId);
insert.run("o2", upperId);
assert.equal(context.sqlite.prepare("SELECT count(*) AS count FROM external_model_objects").get()!.count, 2);
assert.throws(() => insert.run("o3", lowerId), /UNIQUE constraint failed/);
} finally {
context.close();
}
});
});