Persist device row moves
This commit is contained in:
@@ -23,7 +23,10 @@ describe("circuit write service rules", () => {
|
||||
},
|
||||
} as never,
|
||||
circuitSectionTransactionStore: {
|
||||
updateEquipmentIdentifiers(_listId: string, updates: Array<{ id: string; equipmentIdentifier: string }>) {
|
||||
updateEquipmentIdentifiers(
|
||||
_listId: string,
|
||||
updates: Array<{ id: string; equipmentIdentifier: string }>
|
||||
) {
|
||||
safeUpdatePayload = updates;
|
||||
},
|
||||
} as never,
|
||||
@@ -58,7 +61,10 @@ describe("circuit write service rules", () => {
|
||||
},
|
||||
} as never,
|
||||
circuitSectionTransactionStore: {
|
||||
updateEquipmentIdentifiers(_listId: string, updates: Array<{ id: string; equipmentIdentifier: string }>) {
|
||||
updateEquipmentIdentifiers(
|
||||
_listId: string,
|
||||
updates: Array<{ id: string; equipmentIdentifier: string }>
|
||||
) {
|
||||
safeUpdatePayload = updates;
|
||||
},
|
||||
} as never,
|
||||
@@ -72,7 +78,7 @@ describe("circuit write service rules", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("renumber handles gaps and keeps device rows untouched by identifier-only update path", async () => {
|
||||
it("renumber handles gaps without touching device rows", async () => {
|
||||
let safeCalled = 0;
|
||||
const service = new CircuitWriteService({
|
||||
circuitSectionRepository: {
|
||||
@@ -97,292 +103,12 @@ describe("circuit write service rules", () => {
|
||||
safeCalled += 1;
|
||||
},
|
||||
} as never,
|
||||
deviceRowRepository: {
|
||||
async update() {
|
||||
throw new Error("device rows must not be touched");
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
await service.renumberSection("s1");
|
||||
assert.equal(safeCalled, 1);
|
||||
});
|
||||
|
||||
it("moving a device row to another circuit preserves row and toggles reserve flags", async () => {
|
||||
let transactionalMove:
|
||||
| {
|
||||
rows: Array<{ id: string; expectedCircuitId: string }>;
|
||||
targetCircuitId?: string;
|
||||
createTargetCircuit?: unknown;
|
||||
}
|
||||
| undefined;
|
||||
const service = new CircuitWriteService({
|
||||
deviceRowRepository: {
|
||||
async findById() {
|
||||
return { id: "r1", circuitId: "c1" } as never;
|
||||
},
|
||||
} as never,
|
||||
deviceRowTransactionStore: {
|
||||
moveRows(input: typeof transactionalMove) {
|
||||
transactionalMove = input;
|
||||
return {
|
||||
movedRowIds: input!.rows.map((row) => row.id),
|
||||
targetCircuitId: input!.targetCircuitId!,
|
||||
};
|
||||
},
|
||||
} as never,
|
||||
circuitRepository: {
|
||||
async findById(circuitId: string) {
|
||||
if (circuitId === "c1") {
|
||||
return {
|
||||
id: "c1",
|
||||
sectionId: "s1",
|
||||
circuitListId: "l1",
|
||||
equipmentIdentifier: "-1F1",
|
||||
sortOrder: 10,
|
||||
isReserve: 0,
|
||||
} as never;
|
||||
}
|
||||
return {
|
||||
id: "c2",
|
||||
sectionId: "s1",
|
||||
circuitListId: "l1",
|
||||
equipmentIdentifier: "-1F2",
|
||||
sortOrder: 20,
|
||||
isReserve: 1,
|
||||
} as never;
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
await service.moveDeviceRow("r1", { targetCircuitId: "c2" });
|
||||
assert.deepEqual(transactionalMove, {
|
||||
rows: [{ id: "r1", expectedCircuitId: "c1" }],
|
||||
targetCircuitId: "c2",
|
||||
createTargetCircuit: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("moving a device row to placeholder creates a new circuit in target section", async () => {
|
||||
let preparedTarget:
|
||||
| {
|
||||
circuitListId: string;
|
||||
sectionId: string;
|
||||
equipmentIdentifier: string;
|
||||
displayName: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
| undefined;
|
||||
const service = new CircuitWriteService({
|
||||
deviceRowRepository: {
|
||||
async findById() {
|
||||
return { id: "r1", circuitId: "c1" } as never;
|
||||
},
|
||||
} as never,
|
||||
deviceRowTransactionStore: {
|
||||
moveRows(input: { rows: Array<{ id: string }>; createTargetCircuit?: typeof preparedTarget }) {
|
||||
preparedTarget = input.createTargetCircuit;
|
||||
return {
|
||||
movedRowIds: input.rows.map((row) => row.id),
|
||||
targetCircuitId: "c-new",
|
||||
createdCircuitId: "c-new",
|
||||
};
|
||||
},
|
||||
} as never,
|
||||
circuitRepository: {
|
||||
async findById(circuitId: string) {
|
||||
if (circuitId === "c1") {
|
||||
return {
|
||||
id: "c1",
|
||||
sectionId: "s1",
|
||||
circuitListId: "l1",
|
||||
equipmentIdentifier: "-1F1",
|
||||
sortOrder: 10,
|
||||
isReserve: 0,
|
||||
} as never;
|
||||
}
|
||||
return null as never;
|
||||
},
|
||||
async listBySection() {
|
||||
return [{ sortOrder: 40 }] as never[];
|
||||
},
|
||||
} as never,
|
||||
circuitSectionRepository: {
|
||||
async findById() {
|
||||
return { id: "s2", circuitListId: "l1", prefix: "-2F" } as never;
|
||||
},
|
||||
} as never,
|
||||
numberingService: {
|
||||
async getNextIdentifier() {
|
||||
return "-2F8";
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
await service.moveDeviceRow("r1", { targetSectionId: "s2", createNewCircuit: true });
|
||||
assert.deepEqual(preparedTarget, {
|
||||
circuitListId: "l1",
|
||||
sectionId: "s2",
|
||||
equipmentIdentifier: "-2F8",
|
||||
displayName: "Neuer Stromkreis",
|
||||
sortOrder: 50,
|
||||
});
|
||||
});
|
||||
|
||||
it("moving a device row to its current circuit remains a no-op", async () => {
|
||||
let transactionalMoveCount = 0;
|
||||
const service = new CircuitWriteService({
|
||||
deviceRowRepository: {
|
||||
async findById() {
|
||||
return { id: "r1", circuitId: "c1" } as never;
|
||||
},
|
||||
} as never,
|
||||
deviceRowTransactionStore: {
|
||||
moveRows() {
|
||||
transactionalMoveCount += 1;
|
||||
throw new Error("same-circuit move must not write");
|
||||
},
|
||||
} as never,
|
||||
circuitRepository: {
|
||||
async findById() {
|
||||
return {
|
||||
id: "c1",
|
||||
sectionId: "s1",
|
||||
circuitListId: "l1",
|
||||
equipmentIdentifier: "-1F1",
|
||||
sortOrder: 10,
|
||||
isReserve: 0,
|
||||
} as never;
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
const result = await service.moveDeviceRow("r1", { targetCircuitId: "c1" });
|
||||
assert.equal(transactionalMoveCount, 0);
|
||||
assert.equal(result?.id, "r1");
|
||||
});
|
||||
|
||||
it("moving multiple device rows to a circuit preserves input order and toggles reserve", async () => {
|
||||
let transactionalMove:
|
||||
| {
|
||||
rows: Array<{ id: string; expectedCircuitId: string }>;
|
||||
targetCircuitId?: string;
|
||||
createTargetCircuit?: unknown;
|
||||
}
|
||||
| undefined;
|
||||
const service = new CircuitWriteService({
|
||||
deviceRowRepository: {
|
||||
async findById(rowId: string) {
|
||||
if (rowId === "r1") {
|
||||
return { id: "r1", circuitId: "c1" } as never;
|
||||
}
|
||||
return { id: "r2", circuitId: "c2" } as never;
|
||||
},
|
||||
} as never,
|
||||
deviceRowTransactionStore: {
|
||||
moveRows(input: typeof transactionalMove) {
|
||||
transactionalMove = input;
|
||||
return {
|
||||
movedRowIds: input!.rows.map((row) => row.id),
|
||||
targetCircuitId: input!.targetCircuitId!,
|
||||
};
|
||||
},
|
||||
} as never,
|
||||
circuitRepository: {
|
||||
async findById(circuitId: string) {
|
||||
if (circuitId === "c1") {
|
||||
return { id: "c1", sectionId: "s1", circuitListId: "l1", equipmentIdentifier: "-1F1", sortOrder: 10, isReserve: 0 } as never;
|
||||
}
|
||||
if (circuitId === "c2") {
|
||||
return { id: "c2", sectionId: "s1", circuitListId: "l1", equipmentIdentifier: "-1F2", sortOrder: 20, isReserve: 0 } as never;
|
||||
}
|
||||
return { id: "c3", sectionId: "s1", circuitListId: "l1", equipmentIdentifier: "-1F3", sortOrder: 30, isReserve: 1 } as never;
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
const result = await service.moveDeviceRowsBulk({ rowIds: ["r1", "r2"], targetCircuitId: "c3" });
|
||||
assert.deepEqual(transactionalMove, {
|
||||
rows: [
|
||||
{ id: "r1", expectedCircuitId: "c1" },
|
||||
{ id: "r2", expectedCircuitId: "c2" },
|
||||
],
|
||||
targetCircuitId: "c3",
|
||||
createTargetCircuit: undefined,
|
||||
});
|
||||
assert.deepEqual(result, {
|
||||
movedRowIds: ["r1", "r2"],
|
||||
targetCircuitId: "c3",
|
||||
});
|
||||
});
|
||||
|
||||
it("moving multiple device rows to placeholder creates exactly one new circuit", async () => {
|
||||
let transactionCount = 0;
|
||||
let preparedTarget:
|
||||
| {
|
||||
circuitListId: string;
|
||||
sectionId: string;
|
||||
equipmentIdentifier: string;
|
||||
displayName: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
| undefined;
|
||||
const service = new CircuitWriteService({
|
||||
deviceRowRepository: {
|
||||
async findById(rowId: string) {
|
||||
return { id: rowId, circuitId: rowId === "r1" ? "c1" : "c2" } as never;
|
||||
},
|
||||
} as never,
|
||||
deviceRowTransactionStore: {
|
||||
moveRows(input: { rows: Array<{ id: string }>; createTargetCircuit?: typeof preparedTarget }) {
|
||||
transactionCount += 1;
|
||||
preparedTarget = input.createTargetCircuit;
|
||||
return {
|
||||
movedRowIds: input.rows.map((row) => row.id),
|
||||
targetCircuitId: "c-new",
|
||||
createdCircuitId: "c-new",
|
||||
};
|
||||
},
|
||||
} as never,
|
||||
circuitRepository: {
|
||||
async findById(circuitId: string) {
|
||||
if (circuitId === "c1" || circuitId === "c2") {
|
||||
return { id: circuitId, sectionId: "s1", circuitListId: "l1", equipmentIdentifier: "-1F1", sortOrder: 10, isReserve: 0 } as never;
|
||||
}
|
||||
return null as never;
|
||||
},
|
||||
async listBySection() {
|
||||
return [{ sortOrder: 30 }] as never[];
|
||||
},
|
||||
} as never,
|
||||
circuitSectionRepository: {
|
||||
async findById() {
|
||||
return { id: "s2", circuitListId: "l1", prefix: "-2F" } as never;
|
||||
},
|
||||
} as never,
|
||||
numberingService: {
|
||||
async getNextIdentifier() {
|
||||
return "-2F8";
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
const result = await service.moveDeviceRowsBulk({
|
||||
rowIds: ["r1", "r2"],
|
||||
targetSectionId: "s2",
|
||||
createNewCircuit: true,
|
||||
});
|
||||
assert.equal(transactionCount, 1);
|
||||
assert.deepEqual(preparedTarget, {
|
||||
circuitListId: "l1",
|
||||
sectionId: "s2",
|
||||
equipmentIdentifier: "-2F8",
|
||||
displayName: "Neuer Stromkreis",
|
||||
sortOrder: 40,
|
||||
});
|
||||
assert.equal(result.createdCircuitId, "c-new");
|
||||
});
|
||||
|
||||
it("reorders circuits inside one section without renumbering identifiers", async () => {
|
||||
let safeReorder: { sectionId: string; circuitIds: string[] } | undefined;
|
||||
const service = new CircuitWriteService({
|
||||
@@ -407,14 +133,16 @@ describe("circuit write service rules", () => {
|
||||
} as never,
|
||||
});
|
||||
|
||||
await service.reorderCircuitsInSection("s1", { orderedCircuitIds: ["c3", "c1", "c2"] });
|
||||
await service.reorderCircuitsInSection("s1", {
|
||||
orderedCircuitIds: ["c3", "c1", "c2"],
|
||||
});
|
||||
assert.deepEqual(safeReorder, {
|
||||
sectionId: "s1",
|
||||
circuitIds: ["c3", "c1", "c2"],
|
||||
});
|
||||
});
|
||||
|
||||
it("safe section identifier bulk update validates full section set (undo safety)", async () => {
|
||||
it("validates the complete section set before safe identifier updates", async () => {
|
||||
let safeCalled = false;
|
||||
const service = new CircuitWriteService({
|
||||
circuitSectionRepository: {
|
||||
@@ -436,6 +164,7 @@ describe("circuit write service rules", () => {
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
await service.updateSectionEquipmentIdentifiers("s1", {
|
||||
identifiers: [
|
||||
{ circuitId: "c1", equipmentIdentifier: "-1F2" },
|
||||
@@ -444,5 +173,4 @@ describe("circuit write service rules", () => {
|
||||
});
|
||||
assert.equal(safeCalled, true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user