574 lines
22 KiB
TypeScript
574 lines
22 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 AppDatabase } from "../src/db/database-context.js";
|
|
import { ExternalObjectRowAssignmentProjectCommandRepository } from "../src/db/repositories/external-object-row-assignment-project-command.repository.js";
|
|
import { ExternalObjectNewRowProjectCommandRepository } from "../src/db/repositories/external-object-new-row-project-command.repository.js";
|
|
import { ExternalObjectNewCircuitProjectCommandRepository } from "../src/db/repositories/external-object-new-circuit-project-command.repository.js";
|
|
import { toCircuitDeviceRowSnapshot } from "../src/db/repositories/circuit-device-row-structure.persistence.js";
|
|
import { circuitDeviceRows } from "../src/db/schema/circuit-device-rows.js";
|
|
import { circuitLists } from "../src/db/schema/circuit-lists.js";
|
|
import { circuitSections } from "../src/db/schema/circuit-sections.js";
|
|
import { circuits } from "../src/db/schema/circuits.js";
|
|
import { circuitProtectionDevices } from "../src/db/schema/circuit-protection-devices.js";
|
|
import { distributionBoards } from "../src/db/schema/distribution-boards.js";
|
|
import { externalImportBatches } from "../src/db/schema/external-import-batches.js";
|
|
import { externalModelObjects } from "../src/db/schema/external-model-objects.js";
|
|
import { externalModelSources } from "../src/db/schema/external-model-sources.js";
|
|
import { externalRoomMappings } from "../src/db/schema/external-room-mappings.js";
|
|
import { floors } from "../src/db/schema/floors.js";
|
|
import { projects } from "../src/db/schema/projects.js";
|
|
import { rooms } from "../src/db/schema/rooms.js";
|
|
import { createExternalObjectRowAssignmentProjectCommand } from "../src/domain/models/external-object-row-assignment-project-command.model.js";
|
|
import {
|
|
createExternalObjectNewRowProjectCommand,
|
|
externalObjectAssignToNewRowCommandType,
|
|
} from "../src/domain/models/external-object-new-row-project-command.model.js";
|
|
import {
|
|
createExternalObjectNewCircuitProjectCommand,
|
|
externalObjectAssignToNewCircuitCommandType,
|
|
} from "../src/domain/models/external-object-new-circuit-project-command.model.js";
|
|
import type { ExternalModelObjectSnapshot } from "../src/external-model/domain/external-model-contracts.js";
|
|
import { externalCsvTestConfiguration } from "./fixtures/revit-csv-fixtures.js";
|
|
|
|
function createFixture(initialObjectRowId: string | null = "row-1") {
|
|
const context = createDatabaseContext(":memory:");
|
|
migrate(context.db, { migrationsFolder: path.resolve("src", "db", "migrations") });
|
|
const database = context.db;
|
|
database.insert(projects).values({ id: "project-1", name: "Projekt" }).run();
|
|
database.insert(floors).values({ id: "floor-1", projectId: "project-1", name: "EG", sortOrder: 10 }).run();
|
|
database.insert(rooms).values({ id: "room-1", projectId: "project-1", floorId: "floor-1", roomNumber: "101", roomName: "Büro" }).run();
|
|
database.insert(distributionBoards).values({ id: "board-1", projectId: "project-1", name: "UV 1" }).run();
|
|
database.insert(circuitLists).values({ id: "list-1", projectId: "project-1", distributionBoardId: "board-1", name: "Liste" }).run();
|
|
database.insert(circuitSections).values({ id: "section-1", circuitListId: "list-1", key: "single-1", displayName: "1-phasig", prefix: "-2F1.", sortOrder: 10, category: "single_phase", groupNumber: 1 }).run();
|
|
for (const index of [1, 2]) {
|
|
database.insert(circuits).values({ id: `circuit-${index}`, circuitListId: "list-1", sectionId: "section-1", equipmentIdentifier: `-2F1.${index}`, sortOrder: index * 10, voltage: 230 }).run();
|
|
database.insert(circuitDeviceRows).values({
|
|
id: `row-${index}`,
|
|
circuitId: `circuit-${index}`,
|
|
sortOrder: 10,
|
|
name: "socket",
|
|
displayName: "Steckdose",
|
|
phaseType: "single_phase",
|
|
connectionKind: "socket",
|
|
category: "single_phase",
|
|
roomId: "room-1",
|
|
roomNumberSnapshot: "101",
|
|
roomNameSnapshot: "Büro",
|
|
quantity: index === 1 ? (initialObjectRowId === "row-1" ? 3 : 1) : 0,
|
|
manualQuantity: index === 1 ? 1 : 0,
|
|
powerPerUnit: 0.12,
|
|
simultaneityFactor: 1,
|
|
}).run();
|
|
}
|
|
database.insert(externalModelSources).values({ id: "source-1", projectId: "project-1", name: "Revit", sourceType: "revit_csv" }).run();
|
|
database.insert(externalImportBatches).values({
|
|
id: "batch-1",
|
|
projectId: "project-1",
|
|
sourceId: "source-1",
|
|
importKind: "initial",
|
|
importedAtIso: "2026-08-02T16:00:00.000Z",
|
|
fileName: "revit.csv",
|
|
sha256: "a".repeat(64),
|
|
appliedProjectRevision: 0,
|
|
configurationVersion: 1,
|
|
configurationSnapshot: externalCsvTestConfiguration,
|
|
originalBytes: Buffer.from("test"),
|
|
document: { delimiter: ";", encoding: "utf-8", headers: [], rows: [] },
|
|
}).run();
|
|
database.insert(externalRoomMappings).values({
|
|
id: "mapping-1",
|
|
projectId: "project-1",
|
|
sourceId: "source-1",
|
|
normalizedSourceRoomKey: "number:101",
|
|
sourceFloorName: "EG",
|
|
sourceRoomNumber: "101",
|
|
sourceRoomName: "Büro",
|
|
roomId: "room-1",
|
|
defaultDistributionBoardId: "board-1",
|
|
}).run();
|
|
database.insert(externalModelObjects).values(objectSnapshot(initialObjectRowId)).run();
|
|
return context;
|
|
}
|
|
|
|
function objectSnapshot(circuitDeviceRowId: string | null): ExternalModelObjectSnapshot {
|
|
return {
|
|
id: "object-1",
|
|
projectId: "project-1",
|
|
sourceId: "source-1",
|
|
ifcGuid: "ifc-1",
|
|
lastSeenImportBatchId: "batch-1",
|
|
lastAcceptedImportBatchId: "batch-1",
|
|
acceptedSourceValues: {
|
|
rowNumber: 2,
|
|
roomNumber: "101",
|
|
roomName: "Büro",
|
|
familyAndType: "Steckdose: Standard",
|
|
selectionMarker: "Steckdose",
|
|
circuitIdentifier: "-2F1.1",
|
|
power: "120",
|
|
quantity: "2",
|
|
additionalSourceValues: {},
|
|
},
|
|
planningValues: {
|
|
displayName: "Steckdose",
|
|
internalDeviceType: "socket",
|
|
category: "single_phase",
|
|
connectionKind: "socket",
|
|
effectiveQuantity: 2,
|
|
powerPerUnitW: 120,
|
|
simultaneityFactor: 1,
|
|
cosPhi: null,
|
|
costGroup: null,
|
|
remark: null,
|
|
},
|
|
overriddenFields: [],
|
|
externalRoomMappingId: "mapping-1",
|
|
distributionBoardId: "board-1",
|
|
linkedProjectDeviceId: null,
|
|
circuitDeviceRowId,
|
|
presenceStatus: "present",
|
|
};
|
|
}
|
|
|
|
function row(database: AppDatabase, id: string) {
|
|
return toCircuitDeviceRowSnapshot(
|
|
database.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, id)).get()!
|
|
);
|
|
}
|
|
|
|
function moveCommand(database: AppDatabase, confirmedConflictObjectIds: string[] = []) {
|
|
const row1 = row(database, "row-1");
|
|
const row2 = row(database, "row-2");
|
|
const object = objectSnapshot("row-1");
|
|
return createExternalObjectRowAssignmentProjectCommand({
|
|
rows: [
|
|
{ expected: row1, target: { ...row1, quantity: 1 } },
|
|
{ expected: row2, target: { ...row2, quantity: 2 } },
|
|
],
|
|
objects: [{ expected: object, target: { ...object, circuitDeviceRowId: "row-2" } }],
|
|
confirmedConflictObjectIds,
|
|
});
|
|
}
|
|
|
|
describe("external object row assignment project command", () => {
|
|
it("moves an object atomically and preserves exact quantities through undo and redo", () => {
|
|
const context = createFixture();
|
|
try {
|
|
const repository = new ExternalObjectRowAssignmentProjectCommandRepository(context.db);
|
|
const moved = repository.execute({ projectId: "project-1", expectedRevision: 0, source: "user", command: moveCommand(context.db) });
|
|
assert.equal(row(context.db, "row-1").quantity, 1);
|
|
assert.equal(row(context.db, "row-2").quantity, 2);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-2");
|
|
|
|
const undone = repository.execute({ projectId: "project-1", expectedRevision: 1, source: "undo", historyTargetChangeSetId: moved.revision.changeSetId, command: moved.inverse });
|
|
assert.equal(row(context.db, "row-1").quantity, 3);
|
|
assert.equal(row(context.db, "row-2").quantity, 0);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-1");
|
|
|
|
repository.execute({ projectId: "project-1", expectedRevision: 2, source: "redo", historyTargetChangeSetId: moved.revision.changeSetId, command: undone.inverse });
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-2");
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("detaches the last object but keeps the now-manual row", () => {
|
|
const context = createFixture();
|
|
try {
|
|
const currentRow = row(context.db, "row-1");
|
|
const object = objectSnapshot("row-1");
|
|
const command = createExternalObjectRowAssignmentProjectCommand({
|
|
rows: [{ expected: currentRow, target: { ...currentRow, quantity: 1 } }],
|
|
objects: [{ expected: object, target: { ...object, circuitDeviceRowId: null } }],
|
|
confirmedConflictObjectIds: [],
|
|
});
|
|
new ExternalObjectRowAssignmentProjectCommandRepository(context.db).execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command,
|
|
});
|
|
assert.equal(row(context.db, "row-1").quantity, 1);
|
|
assert.equal(row(context.db, "row-1").manualQuantity, 1);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("requires explicit confirmation for differing planning values", () => {
|
|
const context = createFixture();
|
|
try {
|
|
context.db.update(circuitDeviceRows).set({ displayName: "Abweichend" }).where(eq(circuitDeviceRows.id, "row-2")).run();
|
|
const repository = new ExternalObjectRowAssignmentProjectCommandRepository(context.db);
|
|
assert.throws(
|
|
() => repository.execute({ projectId: "project-1", expectedRevision: 0, source: "user", command: moveCommand(context.db) }),
|
|
/explicit conflict confirmation/
|
|
);
|
|
repository.execute({ projectId: "project-1", expectedRevision: 0, source: "user", command: moveCommand(context.db, ["object-1"]) });
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-2");
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("rolls back row quantities and links when history persistence fails", () => {
|
|
const context = createFixture();
|
|
try {
|
|
context.sqlite.exec(`
|
|
CREATE TRIGGER fail_assignment_history
|
|
BEFORE INSERT ON project_change_sets
|
|
BEGIN SELECT RAISE(ABORT, 'late history failure'); END;
|
|
`);
|
|
const repository = new ExternalObjectRowAssignmentProjectCommandRepository(context.db);
|
|
assert.throws(
|
|
() => repository.execute({ projectId: "project-1", expectedRevision: 0, source: "user", command: moveCommand(context.db) }),
|
|
/late history failure/
|
|
);
|
|
assert.equal(row(context.db, "row-1").quantity, 3);
|
|
assert.equal(row(context.db, "row-2").quantity, 0);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-1");
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("external object new-row project command", () => {
|
|
it("creates an external-only row and supports exact persisted undo and redo", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
const base = row(context.db, "row-2");
|
|
const newRow = {
|
|
...base,
|
|
id: "row-new",
|
|
quantity: 2,
|
|
manualQuantity: 0,
|
|
sortOrder: 20,
|
|
};
|
|
const object = objectSnapshot(null);
|
|
const command = createExternalObjectNewRowProjectCommand(
|
|
externalObjectAssignToNewRowCommandType,
|
|
{
|
|
row: newRow,
|
|
objects: [{
|
|
expected: object,
|
|
target: { ...object, circuitDeviceRowId: "row-new" },
|
|
}],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
);
|
|
const repository = new ExternalObjectNewRowProjectCommandRepository(context.db);
|
|
const inserted = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command,
|
|
});
|
|
assert.equal(row(context.db, "row-new").manualQuantity, 0);
|
|
assert.equal(row(context.db, "row-new").quantity, 2);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-new");
|
|
assert.throws(
|
|
() => repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "user",
|
|
command: inserted.inverse,
|
|
}),
|
|
/only be removed through project history/
|
|
);
|
|
|
|
const undone = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "undo",
|
|
historyTargetChangeSetId: inserted.revision.changeSetId,
|
|
command: inserted.inverse,
|
|
});
|
|
assert.equal(
|
|
context.db.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, "row-new")).get(),
|
|
undefined
|
|
);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
|
|
repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 2,
|
|
source: "redo",
|
|
historyTargetChangeSetId: inserted.revision.changeSetId,
|
|
command: undone.inverse,
|
|
});
|
|
assert.equal(row(context.db, "row-new").quantity, 2);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("rolls back the row and object link when history persistence fails", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
context.sqlite.exec(`
|
|
CREATE TRIGGER fail_new_row_history
|
|
BEFORE INSERT ON project_change_sets
|
|
BEGIN SELECT RAISE(ABORT, 'late history failure'); END;
|
|
`);
|
|
const base = row(context.db, "row-2");
|
|
const object = objectSnapshot(null);
|
|
const command = createExternalObjectNewRowProjectCommand(
|
|
externalObjectAssignToNewRowCommandType,
|
|
{
|
|
row: { ...base, id: "row-new", quantity: 2, manualQuantity: 0, sortOrder: 20 },
|
|
objects: [{ expected: object, target: { ...object, circuitDeviceRowId: "row-new" } }],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
);
|
|
assert.throws(
|
|
() => new ExternalObjectNewRowProjectCommandRepository(context.db).execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command,
|
|
}),
|
|
/late history failure/
|
|
);
|
|
assert.equal(
|
|
context.db.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, "row-new")).get(),
|
|
undefined
|
|
);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("keeps the created row when it changed after assignment", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
const base = row(context.db, "row-2");
|
|
const object = objectSnapshot(null);
|
|
const repository = new ExternalObjectNewRowProjectCommandRepository(context.db);
|
|
const inserted = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command: createExternalObjectNewRowProjectCommand(
|
|
externalObjectAssignToNewRowCommandType,
|
|
{
|
|
row: { ...base, id: "row-new", quantity: 2, manualQuantity: 0, sortOrder: 20 },
|
|
objects: [{ expected: object, target: { ...object, circuitDeviceRowId: "row-new" } }],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
),
|
|
});
|
|
context.db.update(circuitDeviceRows).set({ displayName: "Geändert" })
|
|
.where(eq(circuitDeviceRows.id, "row-new")).run();
|
|
assert.throws(
|
|
() => repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "undo",
|
|
historyTargetChangeSetId: inserted.revision.changeSetId,
|
|
command: inserted.inverse,
|
|
}),
|
|
/changed before history removal/
|
|
);
|
|
assert.equal(row(context.db, "row-new").displayName, "Geändert");
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-new");
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
});
|
|
|
|
function newExternalCircuit(database: AppDatabase) {
|
|
const sourceRow = row(database, "row-2");
|
|
return {
|
|
id: "circuit-new",
|
|
circuitListId: "list-1",
|
|
sectionId: "section-1",
|
|
equipmentIdentifier: "-2F1.3",
|
|
displayName: "Steckdose",
|
|
sortOrder: 30,
|
|
cableType: null,
|
|
cableCrossSection: null,
|
|
cableLength: null,
|
|
rcdAssignment: null,
|
|
terminalDesignation: null,
|
|
voltage: 230,
|
|
controlRequirement: null,
|
|
status: null,
|
|
isReserve: false,
|
|
remark: null,
|
|
deviceRows: [{
|
|
...sourceRow,
|
|
id: "row-new",
|
|
circuitId: "circuit-new",
|
|
quantity: 2,
|
|
manualQuantity: 0,
|
|
}],
|
|
protectionDevice: {
|
|
circuitId: "circuit-new",
|
|
type: "FI_LS" as const,
|
|
ratedCurrentA: 16,
|
|
fuseUtilizationCategory: null,
|
|
tripCharacteristic: "B" as const,
|
|
rcdType: "A" as const,
|
|
ratedResidualCurrentMa: 30,
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("external object new-circuit project command", () => {
|
|
it("creates circuit, protection, row and links as one undoable revision", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
const object = objectSnapshot(null);
|
|
const circuit = newExternalCircuit(context.db);
|
|
const command = createExternalObjectNewCircuitProjectCommand(
|
|
externalObjectAssignToNewCircuitCommandType,
|
|
{
|
|
circuit,
|
|
objects: [{
|
|
expected: object,
|
|
target: { ...object, circuitDeviceRowId: "row-new" },
|
|
}],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
);
|
|
const repository = new ExternalObjectNewCircuitProjectCommandRepository(context.db);
|
|
const inserted = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command,
|
|
});
|
|
assert.equal(
|
|
context.db.select().from(circuits).where(eq(circuits.id, "circuit-new")).get()!
|
|
.equipmentIdentifier,
|
|
"-2F1.3"
|
|
);
|
|
assert.equal(row(context.db, "row-new").manualQuantity, 0);
|
|
assert.equal(
|
|
context.db.select().from(circuitProtectionDevices)
|
|
.where(eq(circuitProtectionDevices.circuitId, "circuit-new")).get()!.type,
|
|
"FI_LS"
|
|
);
|
|
assert.equal(
|
|
context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId,
|
|
"row-new"
|
|
);
|
|
assert.throws(
|
|
() => repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "user",
|
|
command: inserted.inverse,
|
|
}),
|
|
/only be removed through project history/
|
|
);
|
|
|
|
const undone = repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 1,
|
|
source: "undo",
|
|
historyTargetChangeSetId: inserted.revision.changeSetId,
|
|
command: inserted.inverse,
|
|
});
|
|
assert.equal(
|
|
context.db.select().from(circuits).where(eq(circuits.id, "circuit-new")).get(),
|
|
undefined
|
|
);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
|
|
repository.execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 2,
|
|
source: "redo",
|
|
historyTargetChangeSetId: inserted.revision.changeSetId,
|
|
command: undone.inverse,
|
|
});
|
|
assert.equal(
|
|
context.db.select().from(circuits).where(eq(circuits.id, "circuit-new")).get()!
|
|
.equipmentIdentifier,
|
|
"-2F1.3"
|
|
);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("rejects a preplanned BMK that does not belong to the target group", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
const object = objectSnapshot(null);
|
|
const circuit = {
|
|
...newExternalCircuit(context.db),
|
|
equipmentIdentifier: "-1F1.3",
|
|
};
|
|
assert.throws(
|
|
() => new ExternalObjectNewCircuitProjectCommandRepository(context.db).execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command: createExternalObjectNewCircuitProjectCommand(
|
|
externalObjectAssignToNewCircuitCommandType,
|
|
{
|
|
circuit,
|
|
objects: [{
|
|
expected: object,
|
|
target: { ...object, circuitDeviceRowId: "row-new" },
|
|
}],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
),
|
|
}),
|
|
/equipment identifier does not match target group/
|
|
);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
|
|
it("rolls back the complete circuit subtree when history persistence fails", () => {
|
|
const context = createFixture(null);
|
|
try {
|
|
context.sqlite.exec(`
|
|
CREATE TRIGGER fail_new_circuit_history
|
|
BEFORE INSERT ON project_change_sets
|
|
BEGIN SELECT RAISE(ABORT, 'late history failure'); END;
|
|
`);
|
|
const object = objectSnapshot(null);
|
|
assert.throws(
|
|
() => new ExternalObjectNewCircuitProjectCommandRepository(context.db).execute({
|
|
projectId: "project-1",
|
|
expectedRevision: 0,
|
|
source: "user",
|
|
command: createExternalObjectNewCircuitProjectCommand(
|
|
externalObjectAssignToNewCircuitCommandType,
|
|
{
|
|
circuit: newExternalCircuit(context.db),
|
|
objects: [{
|
|
expected: object,
|
|
target: { ...object, circuitDeviceRowId: "row-new" },
|
|
}],
|
|
confirmedConflictObjectIds: [],
|
|
}
|
|
),
|
|
}),
|
|
/late history failure/
|
|
);
|
|
assert.equal(
|
|
context.db.select().from(circuits).where(eq(circuits.id, "circuit-new")).get(),
|
|
undefined
|
|
);
|
|
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
});
|