188 lines
4.8 KiB
JavaScript
188 lines
4.8 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Migration: Create project_element_defaults table
|
|
*
|
|
* This table stores project-specific element default settings that override
|
|
* the global element_type_defaults. Key design decisions:
|
|
*
|
|
* - element_type is TEXT (not ENUM) for flexibility
|
|
* - source_element_id is optional FK for audit trail (SET NULL on global delete)
|
|
* - snapshot_version tracks generations for "check for updates" feature
|
|
* - NO environment field - applies across all environments for consistent branding
|
|
* - Unique constraint on (projectId, element_type) ensures one override per type per project
|
|
*/
|
|
module.exports = {
|
|
async up(queryInterface, Sequelize) {
|
|
// Check if table already exists
|
|
const tableExists = await queryInterface.sequelize.query(
|
|
`SELECT EXISTS (
|
|
SELECT FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'project_element_defaults'
|
|
);`,
|
|
{ type: Sequelize.QueryTypes.SELECT },
|
|
);
|
|
|
|
if (tableExists[0]?.exists) {
|
|
console.log(
|
|
'Table project_element_defaults already exists, skipping creation',
|
|
);
|
|
return;
|
|
}
|
|
|
|
await queryInterface.createTable('project_element_defaults', {
|
|
id: {
|
|
type: Sequelize.UUID,
|
|
defaultValue: Sequelize.UUIDV4,
|
|
primaryKey: true,
|
|
},
|
|
element_type: {
|
|
type: Sequelize.TEXT,
|
|
allowNull: false,
|
|
},
|
|
name: {
|
|
type: Sequelize.TEXT,
|
|
allowNull: true,
|
|
},
|
|
sort_order: {
|
|
type: Sequelize.INTEGER,
|
|
allowNull: false,
|
|
defaultValue: 0,
|
|
},
|
|
settings_json: {
|
|
type: Sequelize.TEXT,
|
|
allowNull: true,
|
|
},
|
|
source_element_id: {
|
|
type: Sequelize.UUID,
|
|
allowNull: true,
|
|
references: {
|
|
model: 'element_type_defaults',
|
|
key: 'id',
|
|
},
|
|
onDelete: 'SET NULL',
|
|
onUpdate: 'CASCADE',
|
|
},
|
|
snapshot_version: {
|
|
type: Sequelize.INTEGER,
|
|
allowNull: false,
|
|
defaultValue: 1,
|
|
},
|
|
projectId: {
|
|
type: Sequelize.UUID,
|
|
allowNull: false,
|
|
references: {
|
|
model: 'projects',
|
|
key: 'id',
|
|
},
|
|
onDelete: 'CASCADE',
|
|
onUpdate: 'CASCADE',
|
|
},
|
|
createdById: {
|
|
type: Sequelize.UUID,
|
|
allowNull: true,
|
|
references: {
|
|
model: 'users',
|
|
key: 'id',
|
|
},
|
|
onDelete: 'SET NULL',
|
|
onUpdate: 'CASCADE',
|
|
},
|
|
updatedById: {
|
|
type: Sequelize.UUID,
|
|
allowNull: true,
|
|
references: {
|
|
model: 'users',
|
|
key: 'id',
|
|
},
|
|
onDelete: 'SET NULL',
|
|
onUpdate: 'CASCADE',
|
|
},
|
|
importHash: {
|
|
type: Sequelize.STRING(255),
|
|
allowNull: true,
|
|
unique: true,
|
|
},
|
|
createdAt: {
|
|
type: Sequelize.DATE,
|
|
allowNull: false,
|
|
},
|
|
updatedAt: {
|
|
type: Sequelize.DATE,
|
|
allowNull: false,
|
|
},
|
|
deletedAt: {
|
|
type: Sequelize.DATE,
|
|
allowNull: true,
|
|
},
|
|
});
|
|
|
|
// Add indexes
|
|
await queryInterface.addIndex('project_element_defaults', ['projectId'], {
|
|
name: 'project_element_defaults_projectId',
|
|
});
|
|
|
|
await queryInterface.addIndex(
|
|
'project_element_defaults',
|
|
['projectId', 'element_type'],
|
|
{
|
|
name: 'project_element_defaults_projectId_element_type',
|
|
unique: true,
|
|
where: { deletedAt: null },
|
|
},
|
|
);
|
|
|
|
await queryInterface.addIndex(
|
|
'project_element_defaults',
|
|
['element_type'],
|
|
{
|
|
name: 'project_element_defaults_element_type',
|
|
},
|
|
);
|
|
|
|
await queryInterface.addIndex(
|
|
'project_element_defaults',
|
|
['source_element_id'],
|
|
{
|
|
name: 'project_element_defaults_source_element_id',
|
|
},
|
|
);
|
|
|
|
await queryInterface.addIndex('project_element_defaults', ['deletedAt'], {
|
|
name: 'project_element_defaults_deletedAt',
|
|
});
|
|
|
|
console.log('Successfully created project_element_defaults table');
|
|
},
|
|
|
|
async down(queryInterface, _Sequelize) {
|
|
// Drop indexes first
|
|
await queryInterface.removeIndex(
|
|
'project_element_defaults',
|
|
'project_element_defaults_projectId',
|
|
);
|
|
await queryInterface.removeIndex(
|
|
'project_element_defaults',
|
|
'project_element_defaults_projectId_element_type',
|
|
);
|
|
await queryInterface.removeIndex(
|
|
'project_element_defaults',
|
|
'project_element_defaults_element_type',
|
|
);
|
|
await queryInterface.removeIndex(
|
|
'project_element_defaults',
|
|
'project_element_defaults_source_element_id',
|
|
);
|
|
await queryInterface.removeIndex(
|
|
'project_element_defaults',
|
|
'project_element_defaults_deletedAt',
|
|
);
|
|
|
|
// Drop table
|
|
await queryInterface.dropTable('project_element_defaults');
|
|
|
|
console.log('Successfully dropped project_element_defaults table');
|
|
},
|
|
};
|