import { DataTypes, Op } from 'sequelize'; export default { up: async (queryInterface) => { const transaction = await queryInterface.sequelize.transaction(); try { await queryInterface.createTable('config_settings', { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, scope: { type: DataTypes.ENUM('SYSTEM', 'PROJECT', 'USER'), allowNull: false }, scopeId: { type: DataTypes.UUID, allowNull: true, field: 'scope_id' }, key: { type: DataTypes.STRING, allowNull: false }, value: { type: DataTypes.JSONB, allowNull: false }, isSecret: { type: DataTypes.BOOLEAN, defaultValue: false, field: 'is_secret' }, schemaVersion: { type: DataTypes.INTEGER, defaultValue: 1, field: 'schema_version' }, createdAt: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW, field: 'created_at' }, updatedAt: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW, field: 'updated_at' } }, { transaction }); // Create a unique index that handles the NULL scope_id for SYSTEM scope correctly // In Postgres 15+ we could use NULLS NOT DISTINCT, but for compatibility we use a partial index // for the NULL case and a standard unique index for the non-NULL case. // 1. Standard unique constraint for non-null scope_id (Project/User) await queryInterface.addIndex('config_settings', ['scope', 'scope_id', 'key'], { unique: true, where: { scope_id: { [Op.ne]: null } }, name: 'config_settings_scope_scope_id_key_unique', transaction }); // 2. Unique constraint for SYSTEM scope (where scope_id is NULL) await queryInterface.addIndex('config_settings', ['scope', 'key'], { unique: true, where: { scope_id: null }, name: 'config_settings_system_scope_key_unique', transaction }); await transaction.commit(); } catch (err) { await transaction.rollback(); throw err; } }, down: async (queryInterface) => { const transaction = await queryInterface.sequelize.transaction(); try { await queryInterface.dropTable('config_settings', { transaction }); await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_config_settings_scope";', { transaction }); await transaction.commit(); } catch (err) { await transaction.rollback(); throw err; } } };