This commit is contained in:
seb
2026-09-30 21:27:27 +02:00
parent ed91ccbaee
commit bc467e29da
3 changed files with 100 additions and 8 deletions

View File

@@ -4,6 +4,39 @@ import resolveArticleBySku from '../article/resolveArticleBySku.js';
import getOptionsByArticleSku from './getOptionsByArticleSku.js';
import makeRunner from '../runner.js';
async function hasOptionslistCycle(runner, rootArticleId, candidateOptionId) {
const visited = new Set();
const queue = [candidateOptionId];
while (queue.length > 0) {
const currentId = queue.shift();
if (currentId === rootArticleId) {
return true;
}
if (visited.has(currentId)) continue;
visited.add(currentId);
const res = await runner.query(
`SELECT ola.article_id
FROM article a
INNER JOIN optionslistarticle ola ON ola.optionslist_id = a.optionslist_id
WHERE a.id = @currentId`,
{ currentId },
);
for (const row of res.rows) {
if (row.article_id === rootArticleId) {
return true;
}
if (!visited.has(row.article_id)) {
queue.push(row.article_id);
}
}
}
return false;
}
export default function setOptionsByArticleSku(provider) {
const resolve = resolveArticleBySku(provider);
const getOptions = getOptionsByArticleSku(provider);
@@ -75,8 +108,8 @@ export default function setOptionsByArticleSku(provider) {
throw new Error(`Option at index ${i} must specify a valid articleId or sku`);
}
if (itemArticleId === articleId) {
throw new Error('An article cannot have itself as an option');
if (itemArticleId === articleId || await hasOptionslistCycle(runner, articleId, itemArticleId)) {
throw new Error('An article cannot have itself as an option or form a circular reference in options');
}
if (seenArticleIds.has(itemArticleId)) {
@@ -93,7 +126,16 @@ export default function setOptionsByArticleSku(provider) {
throw new Error(`Article not found for option: ${itemArticleId}`);
}
const count = item?.count != null && Number(item.count) > 0 ? Number(item.count) : 1;
const rawCount = item?.count;
if (
typeof rawCount !== 'number' ||
!Number.isInteger(rawCount) ||
rawCount <= 0 ||
rawCount > 2147483647
) {
throw new Error(`Invalid count for options item at index ${i}: must be a positive integer`);
}
const count = rawCount;
let sort = item?.sort != null && Number.isInteger(Number(item.sort)) ? Number(item.sort) : i;
while (seenSorts.has(sort)) {