Add device row move history
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import type { SerializedProjectCommand } from "./project-command.model.js";
|
||||
|
||||
export const circuitDeviceRowMoveCommandType =
|
||||
"circuit-device-row.move" as const;
|
||||
export const circuitDeviceRowMoveCommandSchemaVersion = 1 as const;
|
||||
|
||||
export interface CircuitDeviceRowMoveAssignment {
|
||||
rowId: string;
|
||||
expectedCircuitId: string;
|
||||
expectedSortOrder: number;
|
||||
targetCircuitId: string;
|
||||
targetSortOrder: number;
|
||||
}
|
||||
|
||||
export interface CircuitDeviceRowMoveCommandPayload {
|
||||
moves: CircuitDeviceRowMoveAssignment[];
|
||||
}
|
||||
|
||||
export interface CircuitDeviceRowMoveProjectCommand
|
||||
extends SerializedProjectCommand<CircuitDeviceRowMoveCommandPayload> {
|
||||
schemaVersion: typeof circuitDeviceRowMoveCommandSchemaVersion;
|
||||
type: typeof circuitDeviceRowMoveCommandType;
|
||||
}
|
||||
|
||||
export function createCircuitDeviceRowMoveProjectCommand(
|
||||
moves: CircuitDeviceRowMoveAssignment[]
|
||||
): CircuitDeviceRowMoveProjectCommand {
|
||||
const command: CircuitDeviceRowMoveProjectCommand = {
|
||||
schemaVersion: circuitDeviceRowMoveCommandSchemaVersion,
|
||||
type: circuitDeviceRowMoveCommandType,
|
||||
payload: { moves },
|
||||
};
|
||||
assertCircuitDeviceRowMoveProjectCommand(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
export function assertCircuitDeviceRowMoveProjectCommand(
|
||||
command: SerializedProjectCommand<unknown>
|
||||
): asserts command is CircuitDeviceRowMoveProjectCommand {
|
||||
if (
|
||||
command.schemaVersion !== circuitDeviceRowMoveCommandSchemaVersion ||
|
||||
command.type !== circuitDeviceRowMoveCommandType
|
||||
) {
|
||||
throw new Error("Unsupported circuit device-row move command.");
|
||||
}
|
||||
if (!isPlainObject(command.payload)) {
|
||||
throw new Error(
|
||||
"Circuit device-row move payload must be an object."
|
||||
);
|
||||
}
|
||||
const moves = command.payload.moves;
|
||||
if (!Array.isArray(moves) || moves.length === 0) {
|
||||
throw new Error(
|
||||
"Circuit device-row move command requires at least one move."
|
||||
);
|
||||
}
|
||||
|
||||
const rowIds = new Set<string>();
|
||||
for (const move of moves) {
|
||||
if (!isPlainObject(move)) {
|
||||
throw new Error(
|
||||
"Circuit device-row move command contains an invalid move."
|
||||
);
|
||||
}
|
||||
assertNonEmptyString(move.rowId, "rowId");
|
||||
assertNonEmptyString(
|
||||
move.expectedCircuitId,
|
||||
"expectedCircuitId"
|
||||
);
|
||||
assertFiniteNumber(
|
||||
move.expectedSortOrder,
|
||||
"expectedSortOrder"
|
||||
);
|
||||
assertNonEmptyString(move.targetCircuitId, "targetCircuitId");
|
||||
assertFiniteNumber(move.targetSortOrder, "targetSortOrder");
|
||||
if (rowIds.has(move.rowId)) {
|
||||
throw new Error(
|
||||
"Circuit device-row move command contains duplicate row ids."
|
||||
);
|
||||
}
|
||||
if (
|
||||
move.expectedCircuitId === move.targetCircuitId &&
|
||||
move.expectedSortOrder === move.targetSortOrder
|
||||
) {
|
||||
throw new Error(
|
||||
"Circuit device-row move command contains a no-op move."
|
||||
);
|
||||
}
|
||||
|
||||
rowIds.add(move.rowId);
|
||||
}
|
||||
}
|
||||
|
||||
function assertNonEmptyString(
|
||||
value: unknown,
|
||||
field: string
|
||||
): asserts value is string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new Error(`${field} must be a non-empty string.`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertFiniteNumber(
|
||||
value: unknown,
|
||||
field: string
|
||||
): asserts value is number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new Error(`${field} must be a finite number.`);
|
||||
}
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { CircuitDeviceRowMoveProjectCommand } from "../models/circuit-device-row-move-project-command.model.js";
|
||||
import type {
|
||||
AppendedProjectRevision,
|
||||
ProjectRevisionSource,
|
||||
} from "./project-revision.store.js";
|
||||
|
||||
export interface ExecuteCircuitDeviceRowMoveCommandInput {
|
||||
projectId: string;
|
||||
expectedRevision: number;
|
||||
source: ProjectRevisionSource;
|
||||
description?: string;
|
||||
actorId?: string;
|
||||
historyTargetChangeSetId?: string;
|
||||
command: CircuitDeviceRowMoveProjectCommand;
|
||||
}
|
||||
|
||||
export interface ExecutedCircuitDeviceRowMoveCommand {
|
||||
revision: AppendedProjectRevision;
|
||||
inverse: CircuitDeviceRowMoveProjectCommand;
|
||||
}
|
||||
|
||||
export interface CircuitDeviceRowMoveProjectCommandStore {
|
||||
execute(
|
||||
input: ExecuteCircuitDeviceRowMoveCommandInput
|
||||
): ExecutedCircuitDeviceRowMoveCommand;
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
import { ProjectHistoryOperationUnavailableError } from "../errors/project-history-operation-unavailable.error.js";
|
||||
import {
|
||||
assertCircuitDeviceRowMoveProjectCommand,
|
||||
circuitDeviceRowMoveCommandType,
|
||||
} from "../models/circuit-device-row-move-project-command.model.js";
|
||||
import {
|
||||
assertCircuitDeviceRowUpdateProjectCommand,
|
||||
circuitDeviceRowUpdateCommandType,
|
||||
@@ -24,6 +28,7 @@ import {
|
||||
type SerializedProjectCommand,
|
||||
} from "../models/project-command.model.js";
|
||||
import type { CircuitDeviceRowProjectCommandStore } from "../ports/circuit-device-row-project-command.store.js";
|
||||
import type { CircuitDeviceRowMoveProjectCommandStore } from "../ports/circuit-device-row-move-project-command.store.js";
|
||||
import type { CircuitDeviceRowStructureProjectCommandStore } from "../ports/circuit-device-row-structure-project-command.store.js";
|
||||
import type { CircuitProjectCommandStore } from "../ports/circuit-project-command.store.js";
|
||||
import type { CircuitStructureProjectCommandStore } from "../ports/circuit-structure-project-command.store.js";
|
||||
@@ -54,6 +59,7 @@ export class ProjectCommandService implements ProjectCommandExecutor {
|
||||
private readonly circuitStore: CircuitProjectCommandStore,
|
||||
private readonly deviceRowStore: CircuitDeviceRowProjectCommandStore,
|
||||
private readonly deviceRowStructureStore: CircuitDeviceRowStructureProjectCommandStore,
|
||||
private readonly deviceRowMoveStore: CircuitDeviceRowMoveProjectCommandStore,
|
||||
private readonly circuitStructureStore: CircuitStructureProjectCommandStore,
|
||||
private readonly historyStore: ProjectHistoryStore
|
||||
) {}
|
||||
@@ -148,6 +154,13 @@ export class ProjectCommandService implements ProjectCommandExecutor {
|
||||
command: input.command,
|
||||
}).revision;
|
||||
}
|
||||
case circuitDeviceRowMoveCommandType: {
|
||||
assertCircuitDeviceRowMoveProjectCommand(input.command);
|
||||
return this.deviceRowMoveStore.execute({
|
||||
...input,
|
||||
command: input.command,
|
||||
}).revision;
|
||||
}
|
||||
case circuitInsertCommandType: {
|
||||
assertCircuitInsertProjectCommand(input.command);
|
||||
return this.circuitStructureStore.execute({
|
||||
|
||||
Reference in New Issue
Block a user