This commit is contained in:
seb
2026-10-26 01:01:08 +01:00
parent 358e3009b2
commit 563945394b
4 changed files with 117 additions and 0 deletions

View File

@@ -206,3 +206,37 @@ WHERE ca.category_id = @categoryId
ORDER BY a.id ASC ORDER BY a.id ASC
`; `;
export const TOUCH_SUBTREE_CATEGORIES = `
;WITH cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
UPDATE category
SET updated_at = SYSUTCDATETIME()
WHERE id IN (SELECT id FROM cats)
`;
export const TOUCH_SUBTREE_ARTICLES = `
;WITH cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
UPDATE article
SET updated_at = SYSUTCDATETIME()
WHERE id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
UNION
SELECT child.id FROM article child
WHERE child.parentarticle_id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
)
UNION
SELECT parent.parentarticle_id FROM article parent
WHERE parent.id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
) AND parent.parentarticle_id IS NOT NULL
)
`;

View File

@@ -129,4 +129,38 @@ FROM categoryarticle ca
INNER JOIN article a ON a.id = ca.article_id INNER JOIN article a ON a.id = ca.article_id
WHERE ca.category_id IN (SELECT id FROM tree) WHERE ca.category_id IN (SELECT id FROM tree)
AND a.parentarticle_id IS NULL AND a.parentarticle_id IS NULL
`;
export const TOUCH_SUBTREE_CATEGORIES = `
WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
UPDATE category
SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE id IN (SELECT id FROM cats)
`;
export const TOUCH_SUBTREE_ARTICLES = `
WITH RECURSIVE cats AS (
SELECT id FROM category WHERE id = @id
UNION ALL
SELECT c.id FROM category c INNER JOIN cats ON c.parent_id = cats.id
)
UPDATE article
SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
UNION
SELECT child.id FROM article child
WHERE child.parentarticle_id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
)
UNION
SELECT parent.parentarticle_id FROM article parent
WHERE parent.id IN (
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id IN (SELECT id FROM cats)
) AND parent.parentarticle_id IS NOT NULL
)
`; `;

View File

@@ -2,11 +2,15 @@ import {
GET_NEXT_SIBLING_SORT as MSSQL_GET_NEXT_SIBLING_SORT, GET_NEXT_SIBLING_SORT as MSSQL_GET_NEXT_SIBLING_SORT,
IS_ANCESTOR as MSSQL_IS_ANCESTOR, IS_ANCESTOR as MSSQL_IS_ANCESTOR,
MOVE as MSSQL_MOVE, MOVE as MSSQL_MOVE,
TOUCH_SUBTREE_CATEGORIES as MSSQL_TOUCH_SUBTREE_CATEGORIES,
TOUCH_SUBTREE_ARTICLES as MSSQL_TOUCH_SUBTREE_ARTICLES,
} from '../../providers/mssql/queries/category.js'; } from '../../providers/mssql/queries/category.js';
import { import {
GET_NEXT_SIBLING_SORT as SQLITE_GET_NEXT_SIBLING_SORT, GET_NEXT_SIBLING_SORT as SQLITE_GET_NEXT_SIBLING_SORT,
IS_ANCESTOR as SQLITE_IS_ANCESTOR, IS_ANCESTOR as SQLITE_IS_ANCESTOR,
MOVE as SQLITE_MOVE, MOVE as SQLITE_MOVE,
TOUCH_SUBTREE_CATEGORIES as SQLITE_TOUCH_SUBTREE_CATEGORIES,
TOUCH_SUBTREE_ARTICLES as SQLITE_TOUCH_SUBTREE_ARTICLES,
} from '../../providers/sqlite3/queries/category.js'; } from '../../providers/sqlite3/queries/category.js';
import resolveCategoryAccess from './resolveCategoryAccess.js'; import resolveCategoryAccess from './resolveCategoryAccess.js';
import makeRunner from '../runner.js'; import makeRunner from '../runner.js';
@@ -20,6 +24,12 @@ export default function move(provider) {
? SQLITE_GET_NEXT_SIBLING_SORT ? SQLITE_GET_NEXT_SIBLING_SORT
: MSSQL_GET_NEXT_SIBLING_SORT; : MSSQL_GET_NEXT_SIBLING_SORT;
const moveSql = isSqlite ? SQLITE_MOVE : MSSQL_MOVE; const moveSql = isSqlite ? SQLITE_MOVE : MSSQL_MOVE;
const touchCategoriesSql = isSqlite
? SQLITE_TOUCH_SUBTREE_CATEGORIES
: MSSQL_TOUCH_SUBTREE_CATEGORIES;
const touchArticlesSql = isSqlite
? SQLITE_TOUCH_SUBTREE_ARTICLES
: MSSQL_TOUCH_SUBTREE_ARTICLES;
/** /**
* Moves a category to a new parent, preventing cycles and cross-company moves. * Moves a category to a new parent, preventing cycles and cross-company moves.
@@ -70,6 +80,9 @@ export default function move(provider) {
throw new Error('Category not found'); throw new Error('Category not found');
} }
await runner.query(touchCategoriesSql, { id });
await runner.query(touchArticlesSql, { id });
return { id, parentId, sort }; return { id, parentId, sort };
}; };

View File

@@ -225,6 +225,42 @@ describe('store.category', () => {
/Not authorized|Parent not found/, /Not authorized|Parent not found/,
); );
}); });
it('touches updated_at on moved category, subcategories, and associated articles', async () => {
const topTarget = await create('Move Target');
const movedCat = await create('Moved Cat');
const subCat = await create('Sub Cat', movedCat.id);
const artMoved = await createArticle(store, tenant, { parentId: movedCat.id, name: 'Article in Moved' });
const artSub = await createArticle(store, tenant, { parentId: subCat.id, name: 'Article in Sub' });
const oldDate = '2020-01-01T00:00:00.000Z';
await ctx.provider.query(
`UPDATE category SET updated_at = '${oldDate}' WHERE id IN (${movedCat.id}, ${subCat.id})`
);
await ctx.provider.query(
`UPDATE article SET updated_at = '${oldDate}' WHERE id IN (${artMoved.id}, ${artSub.id})`
);
await store.category.move({
googleAuthId: tenant.googleAuthId,
id: movedCat.id,
parentId: topTarget.id,
});
const cats = await ctx.provider.query(
`SELECT id, updated_at FROM category WHERE id IN (${movedCat.id}, ${subCat.id})`
);
for (const row of cats.rows) {
assert.ok(new Date(row.updated_at) > new Date(oldDate), `Category ${row.id} updated_at was touched`);
}
const arts = await ctx.provider.query(
`SELECT id, updated_at FROM article WHERE id IN (${artMoved.id}, ${artSub.id})`
);
for (const row of arts.rows) {
assert.ok(new Date(row.updated_at) > new Date(oldDate), `Article ${row.id} updated_at was touched`);
}
});
}); });
describe('order', () => { describe('order', () => {