Make device sync atomic and undoable
This commit is contained in:
@@ -1,11 +1,53 @@
|
||||
import crypto from "node:crypto";
|
||||
import { and, asc, eq, inArray } from "drizzle-orm";
|
||||
import { and, asc, eq, inArray, isNull } from "drizzle-orm";
|
||||
import { db } from "../client.js";
|
||||
import { circuitDeviceRows } from "../schema/circuit-device-rows.js";
|
||||
import { circuitLists } from "../schema/circuit-lists.js";
|
||||
import { circuits } from "../schema/circuits.js";
|
||||
import { distributionBoards } from "../schema/distribution-boards.js";
|
||||
|
||||
export interface CircuitDeviceRowUpdateInput {
|
||||
linkedProjectDeviceId?: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
phaseType?: string;
|
||||
connectionKind?: string;
|
||||
costGroup?: string;
|
||||
category?: string;
|
||||
level?: string;
|
||||
roomId?: string;
|
||||
roomNumberSnapshot?: string;
|
||||
roomNameSnapshot?: string;
|
||||
quantity: number;
|
||||
powerPerUnit: number;
|
||||
simultaneityFactor: number;
|
||||
cosPhi?: number;
|
||||
remark?: string;
|
||||
overriddenFields?: string;
|
||||
}
|
||||
|
||||
function toUpdateValues(input: CircuitDeviceRowUpdateInput) {
|
||||
return {
|
||||
linkedProjectDeviceId: input.linkedProjectDeviceId ?? null,
|
||||
name: input.name,
|
||||
displayName: input.displayName,
|
||||
phaseType: input.phaseType ?? null,
|
||||
connectionKind: input.connectionKind ?? null,
|
||||
costGroup: input.costGroup ?? null,
|
||||
category: input.category ?? null,
|
||||
level: input.level ?? null,
|
||||
roomId: input.roomId ?? null,
|
||||
roomNumberSnapshot: input.roomNumberSnapshot ?? null,
|
||||
roomNameSnapshot: input.roomNameSnapshot ?? null,
|
||||
quantity: input.quantity,
|
||||
powerPerUnit: input.powerPerUnit,
|
||||
simultaneityFactor: input.simultaneityFactor,
|
||||
cosPhi: input.cosPhi ?? null,
|
||||
remark: input.remark ?? null,
|
||||
overriddenFields: input.overriddenFields ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export class CircuitDeviceRowRepository {
|
||||
async findById(rowId: string) {
|
||||
const [row] = await db.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, rowId)).limit(1);
|
||||
@@ -72,6 +114,21 @@ export class CircuitDeviceRowRepository {
|
||||
.orderBy(asc(distributionBoards.name), asc(circuits.equipmentIdentifier), asc(circuitDeviceRows.sortOrder));
|
||||
}
|
||||
|
||||
async listLinkStatesByIds(projectId: string, rowIds: string[]) {
|
||||
if (rowIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return db
|
||||
.select({
|
||||
id: circuitDeviceRows.id,
|
||||
linkedProjectDeviceId: circuitDeviceRows.linkedProjectDeviceId,
|
||||
})
|
||||
.from(circuitDeviceRows)
|
||||
.innerJoin(circuits, eq(circuitDeviceRows.circuitId, circuits.id))
|
||||
.innerJoin(circuitLists, eq(circuits.circuitListId, circuitLists.id))
|
||||
.where(and(eq(circuitLists.projectId, projectId), inArray(circuitDeviceRows.id, rowIds)));
|
||||
}
|
||||
|
||||
async create(input: {
|
||||
circuitId: string;
|
||||
linkedProjectDeviceId?: string;
|
||||
@@ -123,50 +180,72 @@ export class CircuitDeviceRowRepository {
|
||||
|
||||
async update(
|
||||
rowId: string,
|
||||
input: {
|
||||
linkedProjectDeviceId?: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
phaseType?: string;
|
||||
connectionKind?: string;
|
||||
costGroup?: string;
|
||||
category?: string;
|
||||
level?: string;
|
||||
roomId?: string;
|
||||
roomNumberSnapshot?: string;
|
||||
roomNameSnapshot?: string;
|
||||
quantity: number;
|
||||
powerPerUnit: number;
|
||||
simultaneityFactor: number;
|
||||
cosPhi?: number;
|
||||
remark?: string;
|
||||
overriddenFields?: string;
|
||||
}
|
||||
input: CircuitDeviceRowUpdateInput
|
||||
) {
|
||||
await db
|
||||
.update(circuitDeviceRows)
|
||||
.set({
|
||||
linkedProjectDeviceId: input.linkedProjectDeviceId ?? null,
|
||||
name: input.name,
|
||||
displayName: input.displayName,
|
||||
phaseType: input.phaseType ?? null,
|
||||
connectionKind: input.connectionKind ?? null,
|
||||
costGroup: input.costGroup ?? null,
|
||||
category: input.category ?? null,
|
||||
level: input.level ?? null,
|
||||
roomId: input.roomId ?? null,
|
||||
roomNumberSnapshot: input.roomNumberSnapshot ?? null,
|
||||
roomNameSnapshot: input.roomNameSnapshot ?? null,
|
||||
quantity: input.quantity,
|
||||
powerPerUnit: input.powerPerUnit,
|
||||
simultaneityFactor: input.simultaneityFactor,
|
||||
cosPhi: input.cosPhi ?? null,
|
||||
remark: input.remark ?? null,
|
||||
overriddenFields: input.overriddenFields ?? null,
|
||||
})
|
||||
.set(toUpdateValues(input))
|
||||
.where(eq(circuitDeviceRows.id, rowId));
|
||||
}
|
||||
|
||||
updateLinkedRowsTransactional(
|
||||
projectDeviceId: string,
|
||||
changes: Array<{ rowId: string; input: CircuitDeviceRowUpdateInput }>
|
||||
) {
|
||||
db.transaction((tx) => {
|
||||
for (const change of changes) {
|
||||
const result = tx
|
||||
.update(circuitDeviceRows)
|
||||
.set(toUpdateValues(change.input))
|
||||
.where(
|
||||
and(
|
||||
eq(circuitDeviceRows.id, change.rowId),
|
||||
eq(circuitDeviceRows.linkedProjectDeviceId, projectDeviceId)
|
||||
)
|
||||
)
|
||||
.run();
|
||||
if (result.changes !== 1) {
|
||||
throw new Error("A linked row changed before the operation could be completed.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
disconnectLinkedRowsTransactional(projectDeviceId: string, rowIds: string[]) {
|
||||
db.transaction((tx) => {
|
||||
for (const rowId of rowIds) {
|
||||
const result = tx
|
||||
.update(circuitDeviceRows)
|
||||
.set({ linkedProjectDeviceId: null })
|
||||
.where(
|
||||
and(
|
||||
eq(circuitDeviceRows.id, rowId),
|
||||
eq(circuitDeviceRows.linkedProjectDeviceId, projectDeviceId)
|
||||
)
|
||||
)
|
||||
.run();
|
||||
if (result.changes !== 1) {
|
||||
throw new Error("A linked row changed before the operation could be completed.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reconnectRowsTransactional(projectDeviceId: string, rowIds: string[]) {
|
||||
db.transaction((tx) => {
|
||||
for (const rowId of rowIds) {
|
||||
const result = tx
|
||||
.update(circuitDeviceRows)
|
||||
.set({ linkedProjectDeviceId: projectDeviceId })
|
||||
.where(and(eq(circuitDeviceRows.id, rowId), isNull(circuitDeviceRows.linkedProjectDeviceId)))
|
||||
.run();
|
||||
if (result.changes !== 1) {
|
||||
throw new Error("A disconnected row changed before the operation could be undone.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async delete(rowId: string) {
|
||||
await db.delete(circuitDeviceRows).where(eq(circuitDeviceRows.id, rowId));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user