Add placeholder move history

This commit is contained in:
2026-07-23 22:39:59 +02:00
parent 0a51703315
commit 53282e8c7c
12 changed files with 1106 additions and 160 deletions
@@ -1,7 +1,15 @@
import type { SerializedProjectCommand } from "./project-command.model.js";
import {
assertCircuitInsertProjectCommand,
circuitInsertCommandType,
circuitStructureCommandSchemaVersion,
type CircuitSnapshot,
} from "./circuit-structure-project-command.model.js";
export const circuitDeviceRowMoveCommandType =
"circuit-device-row.move" as const;
export const circuitDeviceRowMoveWithNewCircuitCommandType =
"circuit-device-row.move-with-new-circuit" as const;
export const circuitDeviceRowMoveCommandSchemaVersion = 1 as const;
export interface CircuitDeviceRowMoveAssignment {
@@ -22,6 +30,26 @@ export interface CircuitDeviceRowMoveProjectCommand
type: typeof circuitDeviceRowMoveCommandType;
}
export type CircuitDeviceRowMoveTargetCircuitAction =
| "create"
| "delete";
export interface CircuitDeviceRowMoveWithNewCircuitCommandPayload {
targetCircuitAction: CircuitDeviceRowMoveTargetCircuitAction;
targetCircuit: CircuitSnapshot;
moves: CircuitDeviceRowMoveAssignment[];
}
export interface CircuitDeviceRowMoveWithNewCircuitProjectCommand
extends SerializedProjectCommand<CircuitDeviceRowMoveWithNewCircuitCommandPayload> {
schemaVersion: typeof circuitDeviceRowMoveCommandSchemaVersion;
type: typeof circuitDeviceRowMoveWithNewCircuitCommandType;
}
export type CircuitDeviceRowMoveHistoryProjectCommand =
| CircuitDeviceRowMoveProjectCommand
| CircuitDeviceRowMoveWithNewCircuitProjectCommand;
export function createCircuitDeviceRowMoveProjectCommand(
moves: CircuitDeviceRowMoveAssignment[]
): CircuitDeviceRowMoveProjectCommand {
@@ -34,6 +62,24 @@ export function createCircuitDeviceRowMoveProjectCommand(
return command;
}
export function createCircuitDeviceRowMoveWithNewCircuitProjectCommand(
targetCircuitAction: CircuitDeviceRowMoveTargetCircuitAction,
targetCircuit: CircuitSnapshot,
moves: CircuitDeviceRowMoveAssignment[]
): CircuitDeviceRowMoveWithNewCircuitProjectCommand {
const command: CircuitDeviceRowMoveWithNewCircuitProjectCommand = {
schemaVersion: circuitDeviceRowMoveCommandSchemaVersion,
type: circuitDeviceRowMoveWithNewCircuitCommandType,
payload: {
targetCircuitAction,
targetCircuit,
moves,
},
};
assertCircuitDeviceRowMoveWithNewCircuitProjectCommand(command);
return command;
}
export function assertCircuitDeviceRowMoveProjectCommand(
command: SerializedProjectCommand<unknown>
): asserts command is CircuitDeviceRowMoveProjectCommand {
@@ -91,6 +137,76 @@ export function assertCircuitDeviceRowMoveProjectCommand(
}
}
export function assertCircuitDeviceRowMoveWithNewCircuitProjectCommand(
command: SerializedProjectCommand<unknown>
): asserts command is CircuitDeviceRowMoveWithNewCircuitProjectCommand {
if (
command.schemaVersion !== circuitDeviceRowMoveCommandSchemaVersion ||
command.type !== circuitDeviceRowMoveWithNewCircuitCommandType
) {
throw new Error(
"Unsupported circuit device-row move-with-new-circuit command."
);
}
if (!isPlainObject(command.payload)) {
throw new Error(
"Circuit device-row move-with-new-circuit payload must be an object."
);
}
const { targetCircuitAction, targetCircuit, moves } =
command.payload;
if (
targetCircuitAction !== "create" &&
targetCircuitAction !== "delete"
) {
throw new Error(
"Target circuit action must be create or delete."
);
}
assertCircuitInsertProjectCommand({
schemaVersion: circuitStructureCommandSchemaVersion,
type: circuitInsertCommandType,
payload: { circuit: targetCircuit },
});
const validatedTargetCircuit = targetCircuit as CircuitSnapshot;
if (
validatedTargetCircuit.isReserve !== true ||
validatedTargetCircuit.deviceRows.length !== 0
) {
throw new Error(
"Move target circuit snapshot must describe an empty reserve circuit."
);
}
assertCircuitDeviceRowMoveProjectCommand({
schemaVersion: circuitDeviceRowMoveCommandSchemaVersion,
type: circuitDeviceRowMoveCommandType,
payload: { moves },
});
const validatedMoves = moves as CircuitDeviceRowMoveAssignment[];
for (const move of validatedMoves) {
if (
targetCircuitAction === "create" &&
(move.expectedCircuitId === validatedTargetCircuit.id ||
move.targetCircuitId !== validatedTargetCircuit.id)
) {
throw new Error(
"Create-target moves must move rows into the new circuit."
);
}
if (
targetCircuitAction === "delete" &&
(move.expectedCircuitId !== validatedTargetCircuit.id ||
move.targetCircuitId === validatedTargetCircuit.id)
) {
throw new Error(
"Delete-target moves must move rows out of the created circuit."
);
}
}
}
function assertNonEmptyString(
value: unknown,
field: string
@@ -1,4 +1,4 @@
import type { CircuitDeviceRowMoveProjectCommand } from "../models/circuit-device-row-move-project-command.model.js";
import type { CircuitDeviceRowMoveHistoryProjectCommand } from "../models/circuit-device-row-move-project-command.model.js";
import type {
AppendedProjectRevision,
ProjectRevisionSource,
@@ -11,12 +11,12 @@ export interface ExecuteCircuitDeviceRowMoveCommandInput {
description?: string;
actorId?: string;
historyTargetChangeSetId?: string;
command: CircuitDeviceRowMoveProjectCommand;
command: CircuitDeviceRowMoveHistoryProjectCommand;
}
export interface ExecutedCircuitDeviceRowMoveCommand {
revision: AppendedProjectRevision;
inverse: CircuitDeviceRowMoveProjectCommand;
inverse: CircuitDeviceRowMoveHistoryProjectCommand;
}
export interface CircuitDeviceRowMoveProjectCommandStore {
@@ -1,7 +1,9 @@
import { ProjectHistoryOperationUnavailableError } from "../errors/project-history-operation-unavailable.error.js";
import {
assertCircuitDeviceRowMoveProjectCommand,
assertCircuitDeviceRowMoveWithNewCircuitProjectCommand,
circuitDeviceRowMoveCommandType,
circuitDeviceRowMoveWithNewCircuitCommandType,
} from "../models/circuit-device-row-move-project-command.model.js";
import {
assertCircuitDeviceRowUpdateProjectCommand,
@@ -161,6 +163,15 @@ export class ProjectCommandService implements ProjectCommandExecutor {
command: input.command,
}).revision;
}
case circuitDeviceRowMoveWithNewCircuitCommandType: {
assertCircuitDeviceRowMoveWithNewCircuitProjectCommand(
input.command
);
return this.deviceRowMoveStore.execute({
...input,
command: input.command,
}).revision;
}
case circuitInsertCommandType: {
assertCircuitInsertProjectCommand(input.command);
return this.circuitStructureStore.execute({