223 lines
6.3 KiB
JavaScript
223 lines
6.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Function to generate a timestamp for the migration filename
|
|
function generateTimestamp() {
|
|
const now = new Date();
|
|
const year = now.getFullYear();
|
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
const day = String(now.getDate()).padStart(2, '0');
|
|
const hours = String(now.getHours()).padStart(2, '0');
|
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
|
|
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
}
|
|
|
|
// Function to parse SQL CREATE TABLE statement
|
|
function parseCreateTable(sql) {
|
|
// Extract table name
|
|
const tableNameMatch = sql.match(/CREATE TABLE `([^`]+)`/i);
|
|
if (!tableNameMatch) {
|
|
throw new Error('Could not find table name in SQL statement');
|
|
}
|
|
const tableName = tableNameMatch[1];
|
|
|
|
// Extract column definitions
|
|
const columnsSection = sql.match(/\(([^)]+)\)/)[1];
|
|
|
|
// Split by commas, but be careful with commas inside parentheses (for default values)
|
|
let depth = 0;
|
|
let columns = [];
|
|
let currentColumn = '';
|
|
|
|
for (let i = 0; i < columnsSection.length; i++) {
|
|
const char = columnsSection[i];
|
|
if (char === '(') depth++;
|
|
if (char === ')') depth--;
|
|
|
|
if (char === ',' && depth === 0) {
|
|
columns.push(currentColumn.trim());
|
|
currentColumn = '';
|
|
} else {
|
|
currentColumn += char;
|
|
}
|
|
}
|
|
if (currentColumn.trim()) {
|
|
columns.push(currentColumn.trim());
|
|
}
|
|
|
|
// Filter out non-column definitions (like PRIMARY KEY)
|
|
const columnDefs = columns.filter(col => col.trim().startsWith('`'));
|
|
|
|
// Extract primary key
|
|
const primaryKeyMatch = columnsSection.match(/PRIMARY KEY \(`([^`]+)`\)/i);
|
|
const primaryKey = primaryKeyMatch ? primaryKeyMatch[1] : null;
|
|
|
|
// Extract table options
|
|
const engineMatch = sql.match(/ENGINE=(\w+)/i);
|
|
const engine = engineMatch ? engineMatch[1] : null;
|
|
|
|
const charsetMatch = sql.match(/CHARSET=([^\s]+)/i);
|
|
const charset = charsetMatch ? charsetMatch[1] : null;
|
|
|
|
const collateMatch = sql.match(/COLLATE=([^\s]+)/i);
|
|
const collate = collateMatch ? collateMatch[1] : null;
|
|
|
|
const commentMatch = sql.match(/COMMENT='([^']+)'/i);
|
|
const comment = commentMatch ? commentMatch[1] : null;
|
|
|
|
return {
|
|
tableName,
|
|
columns: columnDefs,
|
|
primaryKey,
|
|
engine,
|
|
charset,
|
|
collate,
|
|
comment
|
|
};
|
|
}
|
|
|
|
// Function to convert SQL column definition to Knex column builder
|
|
function convertColumnToKnex(columnDef) {
|
|
// Extract column name
|
|
const nameMatch = columnDef.match(/`([^`]+)`/);
|
|
if (!nameMatch) return null;
|
|
const name = nameMatch[1];
|
|
|
|
// Determine column type
|
|
let type = '';
|
|
let knexType = '';
|
|
|
|
if (columnDef.includes('varchar')) {
|
|
const sizeMatch = columnDef.match(/varchar\((\d+)\)/i);
|
|
const size = sizeMatch ? parseInt(sizeMatch[1]) : 255;
|
|
type = `varchar(${size})`;
|
|
knexType = `string('${name}', ${size})`;
|
|
} else if (columnDef.includes('datetime')) {
|
|
type = 'datetime';
|
|
knexType = `datetime('${name}')`;
|
|
} else if (columnDef.includes('tinyint')) {
|
|
type = 'tinyint';
|
|
knexType = `boolean('${name}')`;
|
|
} else {
|
|
// Default to string if type is not recognized
|
|
knexType = `string('${name}')`;
|
|
}
|
|
|
|
// Check for NOT NULL
|
|
const isNullable = !columnDef.includes('NOT NULL');
|
|
if (isNullable) {
|
|
knexType += '.nullable()';
|
|
}
|
|
|
|
// Check for DEFAULT value
|
|
const defaultMatch = columnDef.match(/DEFAULT\s+(?:'([^']+)'|(\d+))/i);
|
|
if (defaultMatch) {
|
|
const defaultValue = defaultMatch[1] || defaultMatch[2];
|
|
if (type === 'tinyint') {
|
|
knexType += `.defaultTo(${defaultValue})`;
|
|
} else {
|
|
knexType += `.defaultTo('${defaultValue}')`;
|
|
}
|
|
}
|
|
|
|
// Check for character set and collation
|
|
if (columnDef.includes('CHARACTER SET') || columnDef.includes('COLLATE')) {
|
|
const charsetMatch = columnDef.match(/CHARACTER SET\s+([^\s]+)/i);
|
|
const collateMatch = columnDef.match(/COLLATE\s+([^\s]+)/i);
|
|
|
|
if (charsetMatch) {
|
|
knexType += `.charset('${charsetMatch[1]}')`;
|
|
}
|
|
|
|
if (collateMatch) {
|
|
knexType += `.collate('${collateMatch[1]}')`;
|
|
}
|
|
}
|
|
|
|
return knexType;
|
|
}
|
|
|
|
// Function to generate Knex migration file content
|
|
function generateKnexMigration(parsedTable) {
|
|
const { tableName, columns, primaryKey, engine, charset, collate, comment } = parsedTable;
|
|
|
|
let knexColumns = columns.map(convertColumnToKnex).filter(Boolean);
|
|
|
|
let migrationContent = `exports.up = function(knex) {
|
|
return knex.schema.createTable('${tableName}', function(table) {
|
|
${knexColumns.map(col => ` table.${col};`).join('\n')}
|
|
`;
|
|
|
|
if (primaryKey) {
|
|
migrationContent += ` table.primary(['${primaryKey}']);\n`;
|
|
}
|
|
|
|
if (engine || charset || collate || comment) {
|
|
migrationContent += ` // Table options\n`;
|
|
|
|
if (comment) {
|
|
migrationContent += ` table.comment('${comment}');\n`;
|
|
}
|
|
}
|
|
|
|
migrationContent += ` })`;
|
|
|
|
if (engine || charset || collate) {
|
|
migrationContent += `.options({`;
|
|
|
|
const options = [];
|
|
if (engine) options.push(`engine: '${engine}'`);
|
|
if (charset) options.push(`charset: '${charset}'`);
|
|
if (collate) options.push(`collate: '${collate}'`);
|
|
|
|
migrationContent += `\n ${options.join(',\n ')}\n })`;
|
|
}
|
|
|
|
migrationContent += `;\n};
|
|
|
|
exports.down = function(knex) {
|
|
return knex.schema.dropTable('${tableName}');
|
|
};
|
|
`;
|
|
|
|
return migrationContent;
|
|
}
|
|
|
|
// Main function
|
|
function main() {
|
|
// Get SQL from command line argument or stdin
|
|
let sql = '';
|
|
|
|
if (process.argv.length > 2) {
|
|
// Read from file if provided
|
|
const filePath = process.argv[2];
|
|
sql = fs.readFileSync(filePath, 'utf8');
|
|
} else {
|
|
return console.log('No file provided');
|
|
}
|
|
|
|
try {
|
|
const parsedTable = parseCreateTable(sql);
|
|
const migrationContent = generateKnexMigration(parsedTable);
|
|
|
|
// Generate filename with timestamp
|
|
const timestamp = generateTimestamp();
|
|
const filename = `${timestamp}_create_${parsedTable.tableName}_table.js`;
|
|
|
|
// Write to file
|
|
fs.writeFileSync(filename, migrationContent);
|
|
console.log(`Migration file created: ${filename}`);
|
|
|
|
// Also output to console
|
|
console.log('\nMigration content:');
|
|
console.log(migrationContent);
|
|
} catch (error) {
|
|
console.error('Error:', error.message);
|
|
}
|
|
}
|
|
|
|
main(); |