Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions migrations/20260320041449-cleanup-duplicate-removed-folders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

const MAX_ATTEMPTS = 10;

module.exports = {
up: async (queryInterface) => {
console.info('Starting cleanup of duplicate removed folders...');

const [pairs] = await queryInterface.sequelize.query(`
SELECT parent_uuid, plain_name
FROM folders
WHERE deleted = false
AND parent_uuid IS NOT NULL
AND plain_name IS NOT NULL
GROUP BY parent_uuid, plain_name
HAVING COUNT(*) > 1;
`);

console.info(
`Found ${pairs.length} duplicate (parent_uuid, plain_name) pairs among removed folders.`,
);

let renamed = 0;

for (const { parent_uuid, plain_name } of pairs) {
const [rows] = await queryInterface.sequelize.query(
`SELECT id FROM folders
WHERE parent_uuid = $1 AND plain_name = $2
AND deleted = false
ORDER BY id`,
{ bind: [parent_uuid, plain_name] },
);

for (let i = 1; i < rows.length; i++) {
const { id } = rows[i];
let attempts = 0;

while (attempts < MAX_ATTEMPTS) {
try {
await queryInterface.sequelize.query(
`UPDATE folders SET plain_name = $1 WHERE id = $2`,
{ bind: [`${plain_name}_${id}`, id] },
);
renamed++;
break;
} catch (err) {
attempts++;
console.error(
`[ERROR]: Failed to rename folder id=${id} (attempt ${attempts}/${MAX_ATTEMPTS}): ${err.message}`,
);
if (attempts >= MAX_ATTEMPTS) throw err;
}
}
}
}

console.info(
`=== Cleanup Complete: renamed ${renamed} removed folders ===`,
);
},

down: async () => {},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
up: async (queryInterface) => {
await queryInterface.sequelize.query(`
DROP INDEX CONCURRENTLY IF EXISTS folders_parentuuid_plainname_unique;
`);

await queryInterface.sequelize.query(`
CREATE UNIQUE INDEX CONCURRENTLY folders_parentuuid_plainname_unique
ON folders (parent_uuid, plain_name)
WHERE deleted = false and removed = false;
`);
},

down: async (queryInterface) => {
await queryInterface.sequelize.query(`
DROP INDEX CONCURRENTLY IF EXISTS folders_parentuuid_plainname_unique;
`);
},
};
Loading