Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use strict";

// Columns that currently have a table-wide UNIQUE constraint but should only
// be unique among non-deleted users, so a soft-deleted user's email/username
// etc. can be reused by a new signup.
const columns = ["email", "userName", "extId", "orcidId", "samlNameId"];

function indexName(column) {
return `user_${column}_not_deleted_unique`;
}

module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.sequelize.transaction(async (transaction) => {
for (const column of columns) {
const [constraints] = await queryInterface.sequelize.query(
`SELECT con.conname
FROM pg_constraint con
JOIN pg_class rel ON rel.oid = con.conrelid
JOIN pg_attribute att ON att.attrelid = rel.oid AND att.attnum = ANY(con.conkey)
WHERE rel.relname = 'user' AND att.attname = :column AND con.contype = 'u'`,
{replacements: {column}, transaction}
);

for (const {conname} of constraints) {
await queryInterface.sequelize.query(`ALTER TABLE "user" DROP CONSTRAINT "${conname}"`, {transaction});
}

await queryInterface.addIndex("user", {
fields: [column],
unique: true,
where: {deleted: false},
name: indexName(column),
transaction,
});
}
});
},

async down(queryInterface, Sequelize) {
await queryInterface.sequelize.transaction(async (transaction) => {
for (const column of columns) {
await queryInterface.removeIndex("user", indexName(column), {transaction});
await queryInterface.addConstraint("user", {
fields: [column],
type: "unique",
transaction,
});
}
});
},
};
Loading