u
This commit is contained in:
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user