@magic-mustard/sqlsync
Version:
SQLSync simplifies database schema evolution by allowing a declarative approach to table management
117 lines (116 loc) • 5.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlterEnumsProcessor = void 0;
const namespace_1 = require("../namespace");
const namespace_2 = require("./namespace");
const logger_1 = require("../../utils/logger");
const crypto_1 = require("crypto");
class AlterEnumsProcessor extends namespace_1.Parser.AbstractProcessor {
constructor(file, appender, handler, contentBetweenFlags) {
super(file, appender, handler, contentBetweenFlags);
}
process() {
// Extract alter enum statements from the file content
const alterEnumBlocks = this.getAlterEnumBlocks();
// Process each block of statements
this.processAlterEnumBlocks(alterEnumBlocks);
}
getAlterEnumBlocks() {
// Extract ALTER TYPE or ALTER ENUM statements directly from file content
const content = this.file.contents;
const alterEnumRegex = /ALTER\s+(?:TYPE|ENUM)\s+\w+\s*\.\s*\w+\s+[^;]*;/gi;
const matches = content.match(alterEnumRegex) || [];
logger_1.logger.debug(`Extracted ALTER TYPE/ENUM statements: ${matches.length} found`);
return matches;
}
hasAlterEnumStatements() {
try {
const blocks = this.getAlterEnumBlocks();
return blocks.length > 0;
}
catch (error) {
return false;
}
}
processAlterEnumBlocks(blocks) {
// Get the full migration state for alter enums
const migrationState = this.state.getMigrationState(namespace_2.Enums.AlterEnumStateIndex);
for (const block of blocks) {
if (!this.validateAlterEnumBlock(block)) {
logger_1.logger.warn(`Invalid ALTER TYPE/ENUM block in file: ${this.file.path}`);
continue;
}
const statements = this.splitIntoAlterStatements(block);
for (const statement of statements) {
const checksum = this.generateChecksum(statement);
// Check if this statement already exists in any migration
let statementExists = false;
for (const [, namespaceData] of Object.entries(migrationState)) {
if (namespaceData[namespace_2.Enums.AlterEnumStateIndex] && Object.values(namespaceData[namespace_2.Enums.AlterEnumStateIndex]).some((statements) => Array.isArray(statements) && statements.includes(checksum))) {
statementExists = true;
break;
}
if (statementExists)
break;
}
if (statementExists) {
// Silently ignore as it's already in the state
continue;
}
// Get the current migration state to update using getLatestMigrationName
const currentMigration = this.migrations.getLatestMigrationName();
if (!migrationState[currentMigration]) {
migrationState[currentMigration] = { [namespace_2.Enums.AlterEnumStateIndex]: {} };
}
const currentState = migrationState[currentMigration];
// Extract schema and enum name from the ALTER TYPE/ENUM statement
const schemaEnumName = this.extractSchemaEnumNameFromAlter(statement);
if (!schemaEnumName) {
logger_1.logger.error(`Failed to extract schema and enum name from ALTER TYPE/ENUM statement in file: ${this.file.path}`);
continue;
}
// If new, add to state
if (!currentState[namespace_2.Enums.AlterEnumStateIndex][schemaEnumName]) {
currentState[namespace_2.Enums.AlterEnumStateIndex][schemaEnumName] = [];
}
currentState[namespace_2.Enums.AlterEnumStateIndex][schemaEnumName].push(checksum);
// Update state for the latest migration only
console.log("AlterEnumsProcessor | State before update:", JSON.stringify(currentState, null, 2));
this.state.updateMigrationState(currentState);
// Append to migration
this.migrations.append({
token: statement,
filePath: this.file.path,
checksum: checksum
});
}
}
}
splitIntoAlterStatements(block) {
// Simple split based on semicolon for now; could be improved with a proper SQL parser
return block.split(';')
.filter(statement => statement.trim().length > 0 && statement.match(/ALTER\s+(?:TYPE|ENUM)/i))
.map(statement => statement.trim() + ';');
}
generateChecksum(statement) {
return (0, crypto_1.createHash)('sha256').update(statement).digest('hex');
}
validateAlterEnumBlock(block) {
// Check if the block contains at least one ALTER TYPE statement
const alterTypeCount = (block.match(/ALTER\s+(?:TYPE|ENUM)/i) || []).length;
return alterTypeCount > 0;
}
extractSchemaEnumNameFromAlter(statement) {
const schemaMatch = statement.match(/ALTER\s+(?:TYPE|ENUM)\s+(?:(\w+)\.)?(\w+)/i);
if (!schemaMatch) {
return null;
}
const schema = schemaMatch[1];
if (!schema) {
throw new Error(`Invalid ALTER TYPE/ENUM statement in file ${this.file.path}: Schema must be specified (e.g., public.user_role).`);
}
const enumName = schemaMatch[2];
return `${schema}.${enumName}`;
}
}
exports.AlterEnumsProcessor = AlterEnumsProcessor;