Files
DbTools/Delta.cs

123 lines
6.2 KiB
C#

using DbTools.Model;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DbTools {
public class Delta {
public string BuildDelta(IDbConnection currentDb, IDbConnection newDb, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) {
Database db1 = new Database(currentDb);
Database db2 = new Database(newDb);
return BuildDelta(db1, db2, removeUnusedTables, removeUnusedColumns, removeUnusedTriggers, removeUnusedIndexes);
}
public string BuildDelta(string currentDbSql, string newDbSql, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) {
Database db1 = new Database(currentDbSql);
Database db2 = new Database(newDbSql);
return BuildDelta(db1, db2, removeUnusedTables, removeUnusedColumns, removeUnusedTriggers, removeUnusedIndexes);
}
public string BuildDelta(IDbConnection currentDb, string newDbSql, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) {
Database db1 = new Database(currentDb);
Database db2 = new Database(newDbSql);
return BuildDelta(db1, db2, removeUnusedTables, removeUnusedColumns, removeUnusedTriggers, removeUnusedIndexes);
}
public string BuildDelta(string currentDbSql, IDbConnection newDb, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) {
Database db1 = new Database(currentDbSql);
Database db2 = new Database(newDb);
return BuildDelta(db1, db2, removeUnusedTables, removeUnusedColumns, removeUnusedTriggers, removeUnusedIndexes);
}
public async Task<bool> ApplyDeltaAsync(IDbConnection cn, string sql) {
return await Task.Run(() => {
return ApplyDelta(cn, sql);
});
}
public bool ApplyDelta(IDbConnection cn, string sql) {
bool success = false;
using (var cmd = cn.CreateCommand()) {
cmd.CommandText = sql;
success = cmd.ExecuteNonQuery() > 0;
}
return success;
}
private string BuildDelta(Database db1, Database db2, bool removeUnusedTables, bool removeUnusedColumns, bool removeUnusedTriggers, bool removeUnusedIndexes) {
StringBuilder sb = new StringBuilder();
// Remove tables that are not in db2 if requested
if (removeUnusedTables) {
var unusedTables = db1.Tables.GetTables().Where(t1 => !db2.ContainsTable(t1.TableName)).ToArray();
if (unusedTables.Length > 0) {
sb.AppendLine("-- DROP UNUSED TABLES --");
foreach (var table in unusedTables) {
sb.AppendLine(table.GenerateDropTable());
}
sb.AppendLine();
}
}
foreach (var table2 in db2.Tables.GetTables()) {
var table1 = db1.Tables[table2.TableName];
if (table1 == null) {
sb.AppendLine(table2.FullSql());
} else {
// Remove unused triggers if requested
if (removeUnusedTriggers) {
var unusedTriggers = table1.Triggers.Keys.Where(t1 => !table2.Triggers.ContainsKey(t1)).ToArray();
if (unusedTriggers.Length > 0) {
sb.AppendLine("-- DROP UNUSED TRIGGERS " + table2.TableName + " --");
foreach (var trigger in unusedTriggers) {
sb.AppendLine($"DROP TRIGGER IF EXISTS {trigger};");
}
sb.AppendLine();
}
}
// Remove unused indexes if requested
if (removeUnusedIndexes) {
var unusedIndexes = table1.Indexes.Keys.Where(i1 => !table2.Indexes.ContainsKey(i1)).ToArray();
if (unusedIndexes.Length > 0) {
sb.AppendLine("-- DROP UNUSED INDEXES IN TABLE " + table2.TableName + " --");
foreach (var index in unusedIndexes) {
sb.AppendLine($"DROP INDEX IF EXISTS {index};");
}
sb.AppendLine();
}
}
// Add missing columns
var commonColumns = table1.GetCommonColumns(table2);
var onlyInTable2 = table2.Columns.GetColumnNames().Where(c => !commonColumns.Contains(c)).ToArray();
var onlyInTable1 = table1.Columns.GetColumnNames().Where(c => !commonColumns.Contains(c)).ToArray();
if (removeUnusedColumns && onlyInTable1.Length > 0) {
// We have columns in table1 that are not in table2 and we want to remove them,
// so we need to recreate the table
sb.AppendLine("-- UNUSED COLUMNS EXIST IN TABLE " + table2.TableName + " --");
string sql = table2.GenerateTableMigration(table1);
sb.AppendLine(sql);
}
if (onlyInTable2.Length > 0) {
// We have columns in table2 that are not in table1, so we can just add them
sb.AppendLine($"-- ALTER TABLE {table2.TableName} --");
foreach (var colName in onlyInTable2) {
var col = table2.Columns[colName];
sb.AppendLine($"ALTER TABLE {table2.TableName} ADD COLUMN {col};");
}
sb.AppendLine($"-- END ALTER TABLE {table2.TableName} --");
sb.AppendLine();
}
}
}
return sb.ToString();
}
}
}