diff --git a/Database.cs b/Database.cs index ba2b359..92e9643 100644 --- a/Database.cs +++ b/Database.cs @@ -14,28 +14,39 @@ public class Database { static readonly Regex goEx = new Regex(@"^\s*go\s*$", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase); + readonly string connectionString; readonly Assembly ass; readonly string[] createSql; readonly string[] clearSql; - public Database(Type scriptType) + public string ConnectionString => connectionString; + + public Database(string connectionString, Type scriptType) { + if (String.IsNullOrWhiteSpace(connectionString)) + throw new ArgumentNullException(nameof(connectionString)); + if (scriptType == null) throw new ArgumentNullException(nameof(scriptType)); + this.connectionString = connectionString; ass = scriptType.GetTypeInfo().Assembly; createSql = ParseScript(ReadScript(scriptType.Namespace, "create")); clearSql = ParseScript(ReadScript(scriptType.Namespace, "clear")); } - public Database(Assembly scriptAss, string scriptNamespace) + public Database(string connectionString, Assembly scriptAss, string scriptNamespace) { + if (String.IsNullOrWhiteSpace(connectionString)) + throw new ArgumentNullException(nameof(connectionString)); + if (scriptAss == null) throw new ArgumentNullException(nameof(scriptAss)); if (String.IsNullOrWhiteSpace(scriptNamespace)) throw new ArgumentNullException(nameof(scriptNamespace)); + this.connectionString = connectionString; ass = scriptAss; createSql = ParseScript(ReadScript(scriptNamespace, "create")); clearSql = ParseScript(ReadScript(scriptNamespace, "clear")); @@ -65,7 +76,7 @@ string[] ParseScript(string script) return goEx.Split(script).Where(c => !goEx.IsMatch(c) && !String.IsNullOrWhiteSpace(c)).ToArray(); } - public bool Exists(string connectionString) + public bool Exists() { var builder = new SqlConnectionStringBuilder(connectionString); @@ -81,7 +92,12 @@ public bool Exists(string connectionString) return count > 0; } - public void Rebuild(string connectionString) + public void Rebuild() + { + Rebuild(null); + } + + public void Rebuild(Func modifyScript) { var builder = new SqlConnectionStringBuilder(connectionString); @@ -99,10 +115,15 @@ public void Rebuild(string connectionString) )); } - Build(connectionString); + Build(modifyScript); + } + + public void Build() + { + Build(null); } - public void Build(string connectionString) + public void Build(Func modifyScript) { var builder = new SqlConnectionStringBuilder(connectionString); @@ -116,37 +137,68 @@ public void Build(string connectionString) using (var conn = new SqlConnection(connectionString)) { - BuildSchema(conn); + BuildSchema(conn, modifyScript); } } public void BuildSchema(IDbConnection conn) + { + BuildSchema(conn, null); + } + + public void BuildSchema(IDbConnection conn, Func modifyScript) { conn.EnsureOpen(); foreach (string statement in createSql) - conn.Execute(statement); + ExecuteScript(conn, statement, modifyScript); } - public void Clear(string connectionString) + public void Clear() + { + Clear((Func)null); + } + + public void Clear(Func modifyScript) { using (var conn = new SqlConnection(connectionString)) { - Clear(conn); + Clear(conn, modifyScript); } } public void Clear(IDbConnection conn) + { + Clear(conn, null); + } + + public void Clear(IDbConnection conn, Func modifyScript) { conn.EnsureOpen(); using (var tx = conn.BeginTransaction()) { foreach (string statement in clearSql) - conn.Execute(statement, transaction: tx); + ExecuteScript(conn, statement, modifyScript, tx); tx.Commit(); } } + + void ExecuteScript(IDbConnection conn, string sql, Func modify, IDbTransaction tx = null) + { + if (modify != null) + { + string newStatement = modify(sql); + if (!String.IsNullOrWhiteSpace(newStatement)) + { + conn.Execute(newStatement, transaction: tx); + } + } + else + { + conn.Execute(sql, transaction: tx); + } + } } } \ No newline at end of file diff --git a/README.md b/README.md index 0d19594..7721344 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,15 @@ dotnet add package Archon.Data You should have a `create.sql` & a `clear.sql` as embedded resources in your class library. The `create.sql` script should only create tables & schemas and whatnot. It shouldn't try to create the database. The `clear.sql` script should simply clear the tables. Don't drop or create tables in the `clear.sql` script. ```cs -var db = new Database(typeof(MyType)); //where MyType is in the same namespace as your create.sql & clear.sql +string connectionString = "server=.\\sqlexpress;database=mydb;integrated security=true;"; +var db = new Database(connectionString, typeof(MyType)); //where MyType is in the same namespace as your create.sql & clear.sql ``` or ```cs -var db = new Database(typeof(MyType).Assembly, "MyAssembly.Weird.Namespace.Folder1"); //specify what namespace the embedded create & clear sql scripts are in +string connectionString = "server=.\\sqlexpress;database=mydb;integrated security=true;"; +var db = new Database(connectionString, typeof(MyType).Assembly, "MyAssembly.Weird.Namespace.Folder1"); //specify what namespace the embedded create & clear sql scripts are in ``` ### Check if Database Exists @@ -29,7 +31,7 @@ var db = new Database(typeof(MyType).Assembly, "MyAssembly.Weird.Namespace.Folde To check if a database exists: ```cs -bool exists = db.Exists("server=.\\sqlexpress;database=mydb;integrated security=true;"); +bool exists = db.Exists(); ``` It will return `true` or `false` depending on if the database in the connection string exists or not. @@ -39,20 +41,26 @@ It will return `true` or `false` depending on if the database in the connection To build a new database using the `create.sql` script: ```cs -db.Build("server=.\\sqlexpress;database=mydb;integrated security=true;"); +db.Build(); ``` -This will create the database if it doesn't already exist and then run the `create.sql` script against it. +This will create the database if it doesn't already exist and then run the `create.sql` script against it. You can also use the overload which takes a `modifyScript` delegate to modify each script before it is executed (e.g. to replace tokens based on environment): + +```cs +db.Build(sql => sql.Replace("{schema_name}", Thread.CurrentThread.Name)); +``` + +Note: if the delegate returns `null` for a particular script, that script will not be run. ### Rebuild a Database To drop an existing database and recreate it using the `create.sql` script: ```cs -db.Rebuild("server=.\\sqlexpress;database=mydb;integrated security=true;"); +db.Rebuild(); ``` -This will drop the database if it exists and then recreate it running the `create.sql` script against it. +This will drop the database if it exists and then recreate it running the `create.sql` script against it. This method also has an overload which accepts a a `modifyScript` delegate. ### Build the Schema Only @@ -62,17 +70,17 @@ To only run the `create.sql` script with an existing `IDbConnection`: db.BuildSchema(myConn); ``` -The connection will be opened if it is not already opened and then the `create.sql` script will be run. +The connection will be opened if it is not already opened and then the `create.sql` script will be run. This method also has an overload which accepts a a `modifyScript` delegate. ### Clear the Database To run the `clear.sql` against an existing database: ```cs -db.Clear(myConn); //you can also pass a connection string here +db.Clear(myConn); //you can also not pass a connection object to run against the original connection string ``` -This will open the connection if it is not already open (or create a connection from the connection string) and then run the `clear.sql` script. This will fail if the database does not exist. +This will open the connection if it is not already open (or create a connection from the connection string) and then run the `clear.sql` script. This will fail if the database does not exist. This method also has an overload which accepts a a `modifyScript` delegate. ### `DataContext`