fix(catalog): never create a page that reuses a sibling's order number
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 41s
CI / tests-unit (push) Successful in 1m53s
CI / tests-integration (push) Successful in 2m19s
CI / tests-ui (push) Successful in 2m46s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m9s
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 41s
CI / tests-unit (push) Successful in 1m53s
CI / tests-integration (push) Successful in 2m19s
CI / tests-ui (push) Successful in 2m46s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m9s
The emulator complained "Sibling order 2 is used more than once" 74 times in production, covering 19 pages across 12 parents. The cause was that nearly every page-creation path passed orderNum 0, so each new page collided with whatever sibling already sat at 0 or 1, and the Park placeholder pages all shared the sentinel values 99 and 999. The production rows themselves are repaired out of band (renumbered 1..N per affected parent, ordered by order_num then id so the existing visual order is preserved, plus one dangling catalog_items row whose items_base no longer existed removed). This commit stops it recurring. - hierarchy.ts: add nextFreeSiblingOrder(), which ignores -1 and 0 as the same root set, treats a missing orderNum as 0, and returns an order strictly above the highest sibling in use. An explicit order is still honoured whenever it is free, so callers that genuinely want a position keep it. - page-commands.ts: createPageCommand resolves the real order through nextFreeSiblingOrder instead of writing the requested 0 straight through. Note that furni-import.ts and upload-import.ts still take their order from the furnidata catInfo.order, so two categories carrying the same furnidata order can still collide. That is caught by the emulator audit and repaired by fixEmulatorIssues(), but it is not prevented here.
This commit is contained in:
1 parent
9cc57cddfc
commit
4be7eaed59
3 files changed
+72
-6
No files matched your search
@@ -9,6 +9,7 @@ import {
|
||||
CatalogNotFound,
|
||||
collectSubtree,
|
||||
type HierarchyPage,
|
||||
nextFreeSiblingOrder,
|
||||
positiveId,
|
||||
validateSiblingOrder,
|
||||
} from "../domain/hierarchy";
|
||||
@@ -102,9 +103,13 @@ export async function createPageCommand(
|
||||
if (!data.caption) throw new CatalogInputError("Category name is required");
|
||||
return db.transaction(async (tx) => {
|
||||
const rows = await lockedPages(tx, kind);
|
||||
assertParent(rows, 0, data.parentId ?? -1);
|
||||
const parentId = data.parentId ?? -1;
|
||||
assertParent(rows, 0, parentId);
|
||||
const assignments = fieldsSql(kind, {
|
||||
...data,
|
||||
// Never trust a caller-supplied order number: the emulator rejects a
|
||||
// catalog where two siblings share one.
|
||||
orderNum: nextFreeSiblingOrder(rows, parentId, data.orderNum),
|
||||
captionSave: data.captionSave ?? data.caption?.slice(0, 25),
|
||||
});
|
||||
const [result] = await tx.execute(
|
||||
|
||||
Reference in new issue
Block a user