feat: enhance soft delete functionality for fields to cascade delete items and their values if last field is removed
This commit is contained in:
@@ -54,16 +54,38 @@ router.put('/:id', async (req: Request, res: Response) => {
|
|||||||
router.delete('/:id', async (req: Request, res: Response) => {
|
router.delete('/:id', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const updatedAt = Date.now();
|
const updatedAt = Date.now();
|
||||||
const result = await dbAdapter.execute(
|
// Soft delete the field first
|
||||||
|
const field = await dbAdapter.queryOne('SELECT * FROM fields WHERE id = ?', [req.params.id]);
|
||||||
|
if (!field) {
|
||||||
|
return res.status(404).json({ error: 'Field not found' });
|
||||||
|
}
|
||||||
|
await dbAdapter.execute(
|
||||||
'UPDATE fields SET isDeleted = 1, updatedAt = ? WHERE id = ?',
|
'UPDATE fields SET isDeleted = 1, updatedAt = ? WHERE id = ?',
|
||||||
[updatedAt, req.params.id]
|
[updatedAt, req.params.id]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.changes === 0) {
|
// Remove any item_values referencing this field (already handled in sync route, but ensure consistency for direct REST usage)
|
||||||
return res.status(404).json({ error: 'Field not found' });
|
await dbAdapter.execute('DELETE FROM item_values WHERE fieldId = ?', [req.params.id]);
|
||||||
|
|
||||||
|
// Determine if this was the last remaining (non-deleted) field in its list.
|
||||||
|
const listId = field.listId;
|
||||||
|
const remaining = await dbAdapter.queryOne(
|
||||||
|
'SELECT COUNT(*) as cnt FROM fields WHERE listId = ? AND isDeleted = 0',
|
||||||
|
[listId]
|
||||||
|
);
|
||||||
|
const remainingCount = remaining ? (remaining.cnt ?? remaining.CNT ?? remaining.count ?? 0) : 0;
|
||||||
|
|
||||||
|
if (remainingCount === 0) {
|
||||||
|
// Last field deleted -> soft delete all items and purge their values for this list
|
||||||
|
try {
|
||||||
|
await dbAdapter.execute('UPDATE items SET isDeleted = 1, updatedAt = ? WHERE listId = ?', [updatedAt, listId]);
|
||||||
|
await dbAdapter.execute('DELETE FROM item_values WHERE itemId IN (SELECT id FROM items WHERE listId = ?)', [listId]);
|
||||||
|
} catch (cascadeErr) {
|
||||||
|
console.warn('[FIELD DELETE] Cascade item cleanup failed:', cascadeErr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ message: 'Field deleted successfully' });
|
res.json({ message: 'Field deleted successfully', cascadeItemsDeleted: remainingCount === 0 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ error: 'Failed to delete field' });
|
res.status(500).json({ error: 'Failed to delete field' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,13 +151,26 @@ router.post('/sync', async (req: Request, res: Response) => {
|
|||||||
field.updatedAt,
|
field.updatedAt,
|
||||||
field.isDeleted ? 1 : 0
|
field.isDeleted ? 1 : 0
|
||||||
]);
|
]);
|
||||||
// If a field was deleted, remove any item_values referencing it so clients converge
|
|
||||||
if (field.isDeleted) {
|
if (field.isDeleted) {
|
||||||
|
// Remove item_values for this field
|
||||||
try {
|
try {
|
||||||
await tx.execute('DELETE FROM item_values WHERE fieldId = ?', [field.id]);
|
await tx.execute('DELETE FROM item_values WHERE fieldId = ?', [field.id]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[SYNC] Cascade delete for field failed:', String(err));
|
console.warn('[SYNC] Cascade delete for field failed:', String(err));
|
||||||
}
|
}
|
||||||
|
// Check if this was the last remaining non-deleted field for the list
|
||||||
|
try {
|
||||||
|
const remaining = await tx.queryOne('SELECT COUNT(*) as cnt FROM fields WHERE listId = ? AND isDeleted = 0', [field.listId]);
|
||||||
|
const remainingCount = remaining ? (remaining.cnt ?? remaining.CNT ?? remaining.count ?? 0) : 0;
|
||||||
|
if (remainingCount === 0) {
|
||||||
|
// Soft delete items in this list and purge their values
|
||||||
|
await tx.execute('UPDATE items SET isDeleted = 1, updatedAt = ? WHERE listId = ?', [field.updatedAt, field.listId]);
|
||||||
|
await tx.execute('DELETE FROM item_values WHERE itemId IN (SELECT id FROM items WHERE listId = ?)', [field.listId]);
|
||||||
|
console.log('[SYNC] Last field deleted; cascaded item+value cleanup for list', field.listId);
|
||||||
|
}
|
||||||
|
} catch (cascadeErr) {
|
||||||
|
console.warn('[SYNC] Cascade last-field cleanup failed:', cascadeErr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user