Remap occupied furniture IDs during Catalog Studio imports
CI / check (push) Successful in 1m39s
CI / deploy (push) Successful in 1m19s
CI / e2e (push) Successful in 21s

This commit is contained in:
Simo committed 2026-09-05 13:51:29 +02:00
1 parent 9f791ba284
commit 9dc6b8a261
6 files changed
+206 -9

No files matched your search

@@ -0,0 +1,56 @@
import { sql } from "drizzle-orm";
import { db } from "@/lib/db";
import { findFurniDataIdConflict } from "./furni-data";
let reservation: Promise<void> = Promise.resolve();
/** Reserve both SQL and client identifiers by inserting while holding the local queue.
* The primary key handles competing processes; only duplicate-key failures retry.
*/
export async function reserveFurnitureId(
preferred: number,
classname: string,
insert: (id: number) => Promise<void>,
): Promise<number> {
let release!: () => void;
const previous = reservation;
reservation = new Promise<void>((resolve) => {
release = resolve;
});
await previous;
try {
let candidate = preferred;
for (let attempt = 0; attempt < 100; attempt++) {
if (
!Number.isSafeInteger(candidate) ||
candidate < 1 ||
candidate > 2147483647
)
throw new Error("No valid furniture ID is available");
const [owners] = (await db.execute(
sql`SELECT item_name FROM items_base WHERE id = ${candidate} OR sprite_id = ${candidate} LIMIT 1`,
)) as unknown as [Array<{ item_name: string }>, unknown];
const occupied =
owners.length > 0 ||
!!(await findFurniDataIdConflict(candidate, classname));
if (!occupied) {
try {
await insert(candidate);
return candidate;
} catch (error) {
const cause =
(error as { cause?: { code?: string; errno?: number } }).cause ??
(error as { code?: string; errno?: number });
if (cause.code !== "ER_DUP_ENTRY" && cause.errno !== 1062)
throw error;
}
}
const [rows] = (await db.execute(
sql`SELECT GREATEST(COALESCE(MAX(id), 0), COALESCE(MAX(sprite_id), 0)) AS maximum FROM items_base`,
)) as unknown as [Array<{ maximum: number | string }>, unknown];
candidate = Math.max(candidate + 1, Number(rows[0]?.maximum ?? 0) + 1);
}
throw new Error("Cannot reserve a free furniture ID; retry the import");
} finally {
release();
}
}