-
Notifications
You must be signed in to change notification settings - Fork 19
fix organization code #768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
17d7c70
42126ec
d7d1fd5
2b3a44d
9d1494e
0317a0b
5708441
1c9708e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| const { Sequelize } = require('sequelize') | ||
|
|
||
| module.exports = { | ||
| async up(queryInterface, Sequelize) { | ||
| let transaction | ||
| let fk_retainer = [] | ||
| let table, fk_name, fkey, refTable, refKey | ||
|
|
||
| try { | ||
| // Start a transaction | ||
| transaction = await queryInterface.sequelize.transaction() | ||
|
|
||
| const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\\s+' OR code ~ '[A-Z]';` | ||
| const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` | ||
| const enableFK = (table, fk_name, fkey, refTable, refKey) => | ||
| `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` | ||
| const updateQuery = (table, key) => | ||
| `UPDATE ${table} SET ${key} = LOWER(REGEXP_REPLACE(${key}, '\\s+', '_', 'g')) WHERE ${key} ~ '[A-Z|\\s+]';` | ||
|
|
||
| // Execute the query to fetch organizations with whitespace | ||
| const fetchOrg = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { | ||
| type: Sequelize.QueryTypes.SELECT, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| if (fetchOrg.length > 0) { | ||
| // Disable foreign key constraints and store enable queries | ||
| table = 'organization_registration_codes' | ||
| fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' | ||
| fkey = '(organization_code, tenant_code)' | ||
| refTable = 'organizations' | ||
| refKey = '(code, tenant_code)' | ||
| fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) | ||
| await queryInterface.sequelize.query(disableFK(table, fk_name), { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| table = 'user_organizations' | ||
| fk_name = 'fk_user_organizations_organizations' | ||
| fkey = '(organization_code, tenant_code)' | ||
| refTable = 'organizations' | ||
| refKey = '(code, tenant_code)' | ||
| await queryInterface.sequelize.query(disableFK(table, fk_name), { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
| fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) | ||
|
|
||
| table = 'organization_user_invites' | ||
| fk_name = 'fk_org_user_invites_organization_id' | ||
| fkey = '(organization_code, tenant_code)' | ||
| refTable = 'organizations' | ||
| refKey = '(code, tenant_code)' | ||
| await queryInterface.sequelize.query(disableFK(table, fk_name), { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| table = 'user_organization_roles' | ||
| fk_name = 'fk_user_org_roles_user_organizations' | ||
| fkey = '(user_id, organization_code, tenant_code)' | ||
| refTable = 'user_organizations' | ||
| refKey = '(user_id, organization_code, tenant_code)' | ||
| await queryInterface.sequelize.query(disableFK(table, fk_name), { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
| fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) | ||
|
|
||
| table = 'organization_features' | ||
| fk_name = 'fk_org_features_organization' | ||
| fkey = '(organization_code, tenant_code)' | ||
| refTable = 'organizations' | ||
| refKey = '(code, tenant_code)' | ||
| await queryInterface.sequelize.query(disableFK(table, fk_name), { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
| fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) | ||
|
|
||
| // Update tables to remove whitespace | ||
| let updateTable = 'organizations' | ||
| let key = 'code' | ||
| const updateOrgs = await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| updateTable = 'organization_registration_codes' | ||
| key = 'organization_code' | ||
| await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| updateTable = 'organization_user_invites' | ||
| key = 'organization_code' | ||
| await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| updateTable = 'user_organizations' | ||
| key = 'organization_code' | ||
| await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| updateTable = 'user_organization_roles' | ||
| key = 'organization_code' | ||
| await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
| updateTable = 'organization_features' | ||
| key = 'organization_code' | ||
| await queryInterface.sequelize.query(updateQuery(updateTable, key), { | ||
| type: Sequelize.QueryTypes.UPDATE, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| // Verify the update | ||
| const fetchOrgs = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { | ||
| type: Sequelize.QueryTypes.SELECT, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
|
|
||
| // Re-enable foreign key constraints | ||
| let fk_retainerPromise = [] | ||
| for (let i = 0; i < fk_retainer.length; i++) { | ||
| fk_retainerPromise.push( | ||
| queryInterface.sequelize.query(fk_retainer[i], { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| transaction, | ||
| }) | ||
| ) | ||
| } | ||
|
|
||
| await Promise.all(fk_retainerPromise) | ||
|
|
||
| // Commit the transaction | ||
nevil-mathew marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await transaction.commit() | ||
| } | ||
| } catch (error) { | ||
| // Rollback transaction on error | ||
| if (transaction) await transaction.rollback() | ||
| console.error(`Error during transaction: ${error}`) | ||
| throw error | ||
| } | ||
| }, | ||
|
|
||
| async down(queryInterface, Sequelize) { | ||
| console.warn( | ||
| 'Down migration not implemented: Cannot reliably restore original whitespace in organization codes.' | ||
| ) | ||
| }, | ||
|
Comment on lines
+168
to
+172
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Implement down migration for rollback capability The down migration is not implemented, which means this migration cannot be rolled back. While the transformation is indeed irreversible (we can't know which underscores were originally spaces), you should at least document what manual steps would be needed for a rollback. Consider implementing a partial down migration or better documentation: async down(queryInterface, Sequelize) {
throw new Error(
'Down migration not supported. Manual intervention required:\n' +
'1. Restore organization codes from backup\n' +
'2. Update all related tables (organization_registration_codes, user_organizations, etc.)\n' +
'3. Re-establish foreign key constraints\n' +
'Original format cannot be automatically restored as spaces were converted to underscores.'
);
}🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate foreign key constraint handling
The migration attempts to drop the same constraint twice for the
organization_user_invitestable but with different constraint names. This appears to be handling different naming conventions, but only oneenableFKis added tofk_retainer.Verify if both constraints exist and ensure both are properly restored:
table = 'organization_user_invites' fk_name = 'fk_org_user_invites_org_code' fkey = '(organization_code, tenant_code)' refTable = 'organizations' refKey = '(code, tenant_code)' await queryInterface.sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction, }) fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) table = 'organization_user_invites' fk_name = 'fk_org_user_invites_organization_id' fkey = '(organization_code, tenant_code)' refTable = 'organizations' refKey = '(code, tenant_code)' await queryInterface.sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction, }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey))📝 Committable suggestion
🤖 Prompt for AI Agents