121 lines
4.5 KiB
JavaScript
121 lines
4.5 KiB
JavaScript
import * as mssqlQueries from '../../providers/mssql/queries/articleDelete.js';
|
|
import * as sqliteQueries from '../../providers/sqlite3/queries/articleDelete.js';
|
|
import * as mssqlArticle from '../../providers/mssql/queries/article.js';
|
|
import * as sqliteArticle from '../../providers/sqlite3/queries/article.js';
|
|
import resolveArticleBySku from './resolveArticleBySku.js';
|
|
import recordObituary from '../posterminal/recordObituary.js';
|
|
import makeRunner from '../runner.js';
|
|
|
|
export default function del(provider) {
|
|
const resolve = resolveArticleBySku(provider);
|
|
const recordObit = recordObituary(provider);
|
|
const isSqlite = provider?.dialect === 'sqlite3';
|
|
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
|
const articleQueries = isSqlite ? sqliteArticle : mssqlArticle;
|
|
|
|
/**
|
|
* Deletes an article by its SKU, refusing when it still has children unless cascade is true.
|
|
*
|
|
* @param {number} googleAuthId - The id of the Google auth user.
|
|
* @param {string} sku - The article SKU.
|
|
* @param {object|*} [optionsOrTx] - Options object ({ cascade?: boolean }) or optional transaction.
|
|
* @param {object} [maybeTx] - Optional transaction if options was passed.
|
|
* @returns {Promise<void>}
|
|
* @throws {Error} If the article has children (when cascade=false) or is not found.
|
|
*
|
|
* @example
|
|
* await store.article.delete(42, 'SKU-1');
|
|
* await store.article.delete(42, 'SKU-1', { cascade: true });
|
|
*/
|
|
return async (googleAuthId, sku, optionsOrTx, maybeTx) => {
|
|
let options = {};
|
|
let tx;
|
|
if (optionsOrTx && typeof optionsOrTx === 'object' && typeof optionsOrTx.query !== 'function') {
|
|
options = optionsOrTx;
|
|
tx = maybeTx;
|
|
} else {
|
|
tx = optionsOrTx;
|
|
}
|
|
const cascade = Boolean(options.cascade);
|
|
|
|
const runDelete = async (runner) => {
|
|
const { articleId, companyId } = await resolve(googleAuthId, sku, runner);
|
|
|
|
const deleteArticleAndLists = async (id) => {
|
|
const listIds = await runner.query(queries.GET_LIST_IDS, { articleId: id });
|
|
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
|
|
|
await recordObit({ companyId, entityType: 'article', entityId: id }, runner);
|
|
|
|
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId: id });
|
|
|
|
// Touch any parent articles that used this article as an option before deleting it
|
|
await runner.query(articleQueries.TOUCH_OPTION_PARENT_ARTICLES_UPDATED_AT, { articleId: id });
|
|
|
|
const deleted = await runner.query(queries.DELETE_BY_ID, { articleId: id });
|
|
if (!deleted.rowsAffected) {
|
|
throw new Error('Article not found');
|
|
}
|
|
|
|
if (articlelistId != null) {
|
|
await runner.query(queries.DELETE_ARTICLELIST, { id: articlelistId });
|
|
}
|
|
|
|
if (optionslistId != null) {
|
|
await runner.query(queries.DELETE_OPTIONSLIST, { id: optionslistId });
|
|
}
|
|
};
|
|
|
|
const deleteSubtree = async (id) => {
|
|
const children = await runner.query(queries.GET_CHILDREN_IDS, { id });
|
|
for (const child of children.rows) {
|
|
await deleteSubtree(child.id);
|
|
}
|
|
await deleteArticleAndLists(id);
|
|
};
|
|
|
|
const parentRes = await runner.query(
|
|
'SELECT parentarticle_id FROM article WHERE id = @articleId',
|
|
{ articleId },
|
|
);
|
|
const parentArticleId = parentRes.rows[0]?.parentarticle_id;
|
|
|
|
const childCount = await runner.query(queries.GET_CHILD_COUNT, { articleId });
|
|
if (childCount.rows[0].count > 0) {
|
|
if (!cascade) {
|
|
throw new Error('Article has children');
|
|
}
|
|
await deleteSubtree(articleId);
|
|
} else {
|
|
await deleteArticleAndLists(articleId);
|
|
}
|
|
|
|
if (parentArticleId != null) {
|
|
const remainingChildrenRes = await runner.query(
|
|
'SELECT id, parentsort FROM article WHERE parentarticle_id = @parentArticleId ORDER BY parentsort ASC, id ASC',
|
|
{ parentArticleId },
|
|
);
|
|
for (let i = 0; i < remainingChildrenRes.rows.length; i++) {
|
|
const childRow = remainingChildrenRes.rows[i];
|
|
if (Number(childRow.parentsort) !== i) {
|
|
await runner.query(articleQueries.SET_PARENT_SORT, {
|
|
articleId: childRow.id,
|
|
parentArticleId,
|
|
parentsort: i,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (tx) {
|
|
return runDelete(makeRunner(provider, tx));
|
|
}
|
|
if (typeof provider?.transaction === 'function') {
|
|
return provider.transaction(runDelete);
|
|
}
|
|
return runDelete(makeRunner(provider));
|
|
};
|
|
}
|
|
|