feat(F-120): completed feature
This commit is contained in:
48
project/migrations/041_category_delete_cascade.js
Normal file
48
project/migrations/041_category_delete_cascade.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* F-120: Allow deleting a category by cascading to its children and the
|
||||
* product-category links that point at it.
|
||||
*
|
||||
* - catalog_product_categories.category_id: ON DELETE CASCADE — when a product
|
||||
* loses all its categories it is fine; the product itself stays active.
|
||||
* - categories_categories.parent_id: ON DELETE CASCADE — child categories are
|
||||
* removed along with their parent so admins can prune a branch in one go.
|
||||
*
|
||||
* @param {import('node-pg-migrate').MigrationBuilder} pgm
|
||||
*/
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(
|
||||
'ALTER TABLE catalog_product_categories DROP CONSTRAINT IF EXISTS catalog_product_categories_category_id_fkey',
|
||||
);
|
||||
pgm.sql(
|
||||
`ALTER TABLE catalog_product_categories
|
||||
ADD CONSTRAINT catalog_product_categories_category_id_fkey
|
||||
FOREIGN KEY (category_id) REFERENCES categories_categories(id) ON DELETE CASCADE`,
|
||||
);
|
||||
pgm.sql(
|
||||
'ALTER TABLE categories_categories DROP CONSTRAINT IF EXISTS categories_categories_parent_id_fkey',
|
||||
);
|
||||
pgm.sql(
|
||||
`ALTER TABLE categories_categories
|
||||
ADD CONSTRAINT categories_categories_parent_id_fkey
|
||||
FOREIGN KEY (parent_id) REFERENCES categories_categories(id) ON DELETE CASCADE`,
|
||||
);
|
||||
};
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(
|
||||
'ALTER TABLE catalog_product_categories DROP CONSTRAINT IF EXISTS catalog_product_categories_category_id_fkey',
|
||||
);
|
||||
pgm.sql(
|
||||
`ALTER TABLE catalog_product_categories
|
||||
ADD CONSTRAINT catalog_product_categories_category_id_fkey
|
||||
FOREIGN KEY (category_id) REFERENCES categories_categories(id) ON DELETE RESTRICT`,
|
||||
);
|
||||
pgm.sql(
|
||||
'ALTER TABLE categories_categories DROP CONSTRAINT IF EXISTS categories_categories_parent_id_fkey',
|
||||
);
|
||||
pgm.sql(
|
||||
`ALTER TABLE categories_categories
|
||||
ADD CONSTRAINT categories_categories_parent_id_fkey
|
||||
FOREIGN KEY (parent_id) REFERENCES categories_categories(id) ON DELETE RESTRICT`,
|
||||
);
|
||||
};
|
||||
@@ -155,9 +155,7 @@ export async function registerCategoriesRoutes(
|
||||
if (result === 'not_found') {
|
||||
throw new AppError(404, 'NOT_FOUND', 'Category not found');
|
||||
}
|
||||
if (result === 'has_children') {
|
||||
throw new AppError(409, 'CATEGORY_HAS_CHILDREN', 'Category has child categories');
|
||||
}
|
||||
// Children and product-category links cascade at the DB level (F-120).
|
||||
return reply.code(204).send();
|
||||
});
|
||||
|
||||
|
||||
@@ -75,19 +75,22 @@ export class UpdateCategory {
|
||||
}
|
||||
}
|
||||
|
||||
export type DeleteCategoryResult = 'deleted' | 'not_found' | 'has_children';
|
||||
export type DeleteCategoryResult = 'deleted' | 'not_found';
|
||||
|
||||
export class DeleteCategory {
|
||||
constructor(private readonly categories: CategoryRepository) {}
|
||||
|
||||
/**
|
||||
* Deletes the category and lets the database cascade to children and
|
||||
* product-category links (F-120). Returns:
|
||||
* - 'not_found' if the id does not exist;
|
||||
* - 'deleted' on success.
|
||||
*/
|
||||
async execute(id: string): Promise<DeleteCategoryResult> {
|
||||
const category = await this.categories.findById(id);
|
||||
if (!category) {
|
||||
return 'not_found';
|
||||
}
|
||||
if (await this.categories.hasChildren(id)) {
|
||||
return 'has_children';
|
||||
}
|
||||
return (await this.categories.delete(id)) ? 'deleted' : 'not_found';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user