From e25a6b166afd53ae869b07e4018b4246288c8384 Mon Sep 17 00:00:00 2001 From: Russ Kollmansberger Date: Sat, 6 Sep 2025 08:56:51 -0500 Subject: [PATCH] Added functions to SqlBuilder for generating more SQL scripts on differences. Versioned up NuGet. --- DbTools.nuspec | 6 ++-- SqlBuilder.cs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/DbTools.nuspec b/DbTools.nuspec index 8291ac9..2f7c670 100644 --- a/DbTools.nuspec +++ b/DbTools.nuspec @@ -2,15 +2,15 @@ DbTools - 1.0.0.0 + 1.0.1.0 DbTools Russ Kollmansberger false MIT http://project_url_here_or_delete_this_line/ - A small library to sync two database structures and apply migrations. - Summary of changes made in this release of the package. + A library to sync two database structures and apply migrations. + Added new functions to SqlBuilder to generate scripts on database differences. $copyright$ Tag1 Tag2 diff --git a/SqlBuilder.cs b/SqlBuilder.cs index 9919920..c919054 100644 --- a/SqlBuilder.cs +++ b/SqlBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Diagnostics; +using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -37,6 +38,73 @@ namespace DbTools { return tables.ToArray(); } + /// + /// Compares the tables in two database connections and returns the names of tables that exist in the second + /// database but are missing from the first. + /// + /// This method ensures that both database connections are open before performing the + /// comparison. It retrieves the table names from each database and identifies the tables that are missing + /// from the first database. + /// The database connection representing the first database. The connection must be valid and open, or it will + /// be opened automatically. + /// The database connection representing the second database. The connection must be valid and open, or it will + /// be opened automatically. + /// An array of strings containing the names of tables that are present in the second database but not in the + /// first. Returns an empty array if no such tables are found. + /// Thrown if or is . + public string[] GetMissingTables(IDbConnection db1, IDbConnection db2) { + if (db1 == null) { + throw new ArgumentNullException("Must provide a valid DBConnection for db1"); + } + if (db2 == null) { + throw new ArgumentNullException("Must provide a valid DBConnection for db2"); + } + if (db1.State != ConnectionState.Open) { + db1.Open(); + } + if (db2.State != ConnectionState.Open) { + db2.Open(); + } + + string[] db1Tables = GetTableNames(db1); + string[] db2Tables = GetTableNames(db2); + + return db2Tables.Where(f => !db1Tables.Contains(f)).ToArray(); + } + + /// + /// Retrieves the names of tables that exist in the first database but not in the second database. + /// + /// This method compares the table names in the two databases and identifies tables that + /// are unique to the first database. The connections provided will be opened if they are not already + /// open. + /// The connection to the first database. The connection must be valid and open, or it will be opened + /// automatically. + /// The connection to the second database. The connection must be valid and open, or it will be opened + /// automatically. + /// An array of strings containing the names of tables that are present in the first database but not in the + /// second database. Returns an empty array if no such tables exist. + /// Thrown if or is . + public string[] GetUnusedTables(IDbConnection db1, IDbConnection db2) { + if (db1 == null) { + throw new ArgumentNullException("Must provide a valid DBConnection for db1"); + } + if (db2 == null) { + throw new ArgumentNullException("Must provide a valid DBConnection for db2"); + } + if (db1.State != ConnectionState.Open) { + db1.Open(); + } + if (db2.State != ConnectionState.Open) { + db2.Open(); + } + + string[] db1Tables = GetTableNames(db1); + string[] db2Tables = GetTableNames(db2); + + return db1Tables.Where(f => !db2Tables.Contains(f)).ToArray(); + } + /// /// Generates the SQL script to recreate the specified table, including its schema, indexes, triggers, and /// optionally its data. @@ -115,6 +183,36 @@ namespace DbTools { } } + + public string GetTableDropSql(IDbConnection cn, string tableName) { + if (cn == null) { + throw new ArgumentNullException("cn"); + } + if (string.IsNullOrEmpty(tableName)) { + throw new ArgumentNullException("tableName"); + } + + StringBuilder sb = new StringBuilder(); + string[] indexes = GetIndexCreateSqlAsync(cn, tableName).Result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + foreach (string index in indexes) { + Match m = Regex.Match(index, "CREATE INDEX (\\S+) ON .*", RegexOptions.Singleline); + if (m.Success) { + sb.AppendLine($"DROP INDEX IF EXISTS {m.Groups[1].Value};"); + } + } + + string[] triggers = GetTriggerCreateSqlAsync(cn, tableName).Result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + foreach (string trigger in triggers) { + Match m = Regex.Match(trigger, "CREATE TRIGGER (\\S+) .*", RegexOptions.Singleline); + if (m.Success) { + sb.AppendLine($"DROP TRIGGER IF EXISTS {m.Groups[1].Value};"); + } + } + + sb.Append($"DROP TABLE IF EXISTS {tableName};"); + return sb.ToString(); + } + /// /// Retrieves the SQL statements used to create all indexes for the specified table in a SQLite database. ///