132 lines
5.6 KiB
TypeScript
132 lines
5.6 KiB
TypeScript
import path from "node:path";
|
|
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
import { eq } from "drizzle-orm";
|
|
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
|
import { createDatabaseContext, type DatabaseContext } from "../src/db/database-context.js";
|
|
import { ExternalModelConfigurationProjectCommandRepository } from "../src/db/repositories/external-model-configuration-project-command.repository.js";
|
|
import { ExternalModelConfigurationRepository } from "../src/db/repositories/external-model-configuration.repository.js";
|
|
import { ProjectTransferRepository } from "../src/db/repositories/project-transfer.repository.js";
|
|
import { externalModelConfigurations } from "../src/db/schema/external-model-configurations.js";
|
|
import { projects } from "../src/db/schema/projects.js";
|
|
import { createExternalModelConfigurationUpdateProjectCommand } from "../src/domain/models/external-model-configuration-project-command.model.js";
|
|
import {
|
|
assertExternalModelConfiguration,
|
|
createDefaultExternalModelConfiguration,
|
|
} from "../src/external-model/configuration/external-model-configuration.js";
|
|
|
|
const deviceTypeId = "10000000-0000-4000-8000-000000000001";
|
|
const ruleId = "20000000-0000-4000-8000-000000000001";
|
|
|
|
function configuration() {
|
|
const value = createDefaultExternalModelConfiguration();
|
|
value.deviceTypes.push({
|
|
id: deviceTypeId,
|
|
name: "Steckdose",
|
|
category: "single_phase",
|
|
defaults: { powerPerUnitW: 200, simultaneityFactor: null, cosPhi: 0.95, costGroup: "440" },
|
|
});
|
|
value.familyTypeRules.push({
|
|
id: ruleId,
|
|
exactFamilyAndType: "Steckdose: Standard",
|
|
deviceTypeId,
|
|
quantityRule: "socketCount",
|
|
});
|
|
return value;
|
|
}
|
|
|
|
function snapshot(projectId = "project-1") {
|
|
return { id: "config-1", projectId, configuration: configuration() };
|
|
}
|
|
|
|
function createTestDatabase(): DatabaseContext {
|
|
const context = createDatabaseContext(":memory:");
|
|
migrate(context.db, { migrationsFolder: path.resolve("src", "db", "migrations") });
|
|
context.db.insert(projects).values({ id: "project-1", name: "Projekt" }).run();
|
|
return context;
|
|
}
|
|
|
|
describe("external model configuration", () => {
|
|
it("validates the single Worksharing-ID mapping and exact family rules", () => {
|
|
const value = configuration();
|
|
assert.doesNotThrow(() => assertExternalModelConfiguration(value));
|
|
assert.equal("idColumn" in value.layout, false);
|
|
|
|
const duplicate = structuredClone(value);
|
|
duplicate.columns.ifcGuid = duplicate.columns.worksharingId;
|
|
assert.throws(() => assertExternalModelConfiguration(duplicate), /nicht eindeutig/);
|
|
|
|
const unknownType = structuredClone(value);
|
|
unknownType.familyTypeRules[0]!.deviceTypeId = "30000000-0000-4000-8000-000000000001";
|
|
assert.throws(() => assertExternalModelConfiguration(unknownType), /unbekannte Ger.*teart/);
|
|
});
|
|
|
|
it("persists changes without an independent configuration revision", () => {
|
|
const context = createTestDatabase();
|
|
try {
|
|
const repository = new ExternalModelConfigurationProjectCommandRepository(context.db);
|
|
const initial = snapshot();
|
|
const inserted = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command: createExternalModelConfigurationUpdateProjectCommand(null, initial),
|
|
});
|
|
assert.equal(inserted.revision.revisionNumber, 1);
|
|
assert.equal("configurationVersion" in initial, false);
|
|
|
|
const target = structuredClone(initial);
|
|
target.configuration.deviceTypes[0]!.name = "Steckdose allgemein";
|
|
const updated = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "user",
|
|
command: createExternalModelConfigurationUpdateProjectCommand(initial, target),
|
|
});
|
|
assert.equal(updated.revision.revisionNumber, 2);
|
|
assert.deepEqual(updated.inverse.payload, { expected: target, target: initial });
|
|
assert.throws(
|
|
() => repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 2,
|
|
source: "user",
|
|
command: createExternalModelConfigurationUpdateProjectCommand(initial, target),
|
|
}),
|
|
/zwischenzeitlich ge.*ndert/
|
|
);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("distinguishes missing projects and remaps configuration identities on duplicate", () => {
|
|
const context = createTestDatabase();
|
|
try {
|
|
const reader = new ExternalModelConfigurationRepository(context.db);
|
|
assert.deepEqual(reader.getByProject("project-1"), { projectExists: true, configuration: null });
|
|
assert.deepEqual(reader.getByProject("missing"), { projectExists: false, configuration: null });
|
|
|
|
new ExternalModelConfigurationProjectCommandRepository(context.db).execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command: createExternalModelConfigurationUpdateProjectCommand(null, snapshot()),
|
|
});
|
|
const transferRepository = new ProjectTransferRepository(context.db);
|
|
const transfer = transferRepository.exportProject("project-1");
|
|
assert.ok(transfer);
|
|
const duplicate = transferRepository.importDuplicate(transfer);
|
|
const copied = context.db.select().from(externalModelConfigurations)
|
|
.where(eq(externalModelConfigurations.projectId, duplicate.projectId)).get();
|
|
assert.ok(copied);
|
|
assert.notEqual(copied.id, "config-1");
|
|
assert.notEqual(copied.configuration.deviceTypes[0]!.id, deviceTypeId);
|
|
assert.equal(
|
|
copied.configuration.familyTypeRules[0]!.deviceTypeId,
|
|
copied.configuration.deviceTypes[0]!.id
|
|
);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
});
|