From ce63f055124c5211fb0a5b85671dcb5befb3b58d Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Mon, 23 May 2011 17:34:57 -0700 Subject: [PATCH] added better db migration support than what Subsonic provides out of the box. --- Migrator.net/Migrator.Framework/Column.cs | 126 +++ .../Migrator.Framework/ColumnProperty.cs | 50 + .../ForeignKeyConstraint.cs | 11 + Migrator.net/Migrator.Framework/IColumn.cs | 34 + Migrator.net/Migrator.Framework/ILogger.cs | 97 ++ Migrator.net/Migrator.Framework/IMigration.cs | 39 + .../ITransformationProvider.cs | 469 ++++++++++ .../Loggers/.svn/all-wcprops | 35 + .../Migrator.Framework/Loggers/.svn/entries | 198 ++++ .../.svn/text-base/ConsoleWriter.cs.svn-base | 28 + .../text-base/IAttachableLogger.cs.svn-base | 33 + .../.svn/text-base/ILogWriter.cs.svn-base | 33 + .../Loggers/.svn/text-base/Logger.cs.svn-base | 169 ++++ .../text-base/SqlScriptFileLogger.cs.svn-base | 93 ++ .../Loggers/ConsoleWriter.cs | 28 + .../Loggers/IAttachableLogger.cs | 33 + .../Migrator.Framework/Loggers/ILogWriter.cs | 33 + .../Migrator.Framework/Loggers/Logger.cs | 169 ++++ .../Loggers/SqlScriptFileLogger.cs | 93 ++ Migrator.net/Migrator.Framework/Migration.cs | 119 +++ .../Migrator.Framework/MigrationAttribute.cs | 53 ++ .../Migrator.Framework/MigrationException.cs | 30 + .../Migrator.Framework.csproj | 83 ++ .../Migrator.Framework/MigratorDotNet.snk | Bin 0 -> 596 bytes .../SchemaBuilder/.svn/all-wcprops | 77 ++ .../SchemaBuilder/.svn/entries | 436 +++++++++ .../.svn/prop-base/ForeignKey.cs.svn-base | 5 + .../.svn/prop-base/IFluentColumn.cs.svn-base | 5 + .../text-base/AddColumnExpression.cs.svn-base | 40 + .../text-base/AddTableExpression.cs.svn-base | 28 + .../DeleteTableExpression.cs.svn-base | 28 + .../.svn/text-base/FluentColumn.cs.svn-base | 80 ++ .../.svn/text-base/ForeignKey.cs.svn-base | 39 + .../.svn/text-base/IColumnOptions.cs.svn-base | 13 + .../text-base/IDeleteTableOptions.cs.svn-base | 24 + .../.svn/text-base/IFluentColumn.cs.svn-base | 22 + .../text-base/IForeignKeyOptions.cs.svn-base | 20 + .../ISchemaBuilderExpression.cs.svn-base | 20 + .../RenameTableExpression.cs.svn-base | 31 + .../.svn/text-base/SchemaBuilder.cs.svn-base | 169 ++++ .../SchemaBuilder/AddColumnExpression.cs | 40 + .../SchemaBuilder/AddTableExpression.cs | 28 + .../SchemaBuilder/DeleteTableExpression.cs | 28 + .../SchemaBuilder/FluentColumn.cs | 80 ++ .../SchemaBuilder/ForeignKey.cs | 39 + .../SchemaBuilder/IColumnOptions.cs | 13 + .../SchemaBuilder/IDeleteTableOptions.cs | 24 + .../SchemaBuilder/IFluentColumn.cs | 22 + .../SchemaBuilder/IForeignKeyOptions.cs | 20 + .../SchemaBuilder/ISchemaBuilderExpression.cs | 20 + .../SchemaBuilder/RenameTableExpression.cs | 31 + .../SchemaBuilder/SchemaBuilder.cs | 169 ++++ .../Migrator.Framework/StringUtils.cs | 43 + .../ColumnPropertiesMapper.cs | 119 +++ Migrator.net/Migrator.Providers/Dialect.cs | 181 ++++ .../ForeignKeyConstraintMapper.cs | 24 + .../Migrator.Providers/Impl/.svn/all-wcprops | 5 + .../Migrator.Providers/Impl/.svn/entries | 43 + .../Impl/SQLite/.svn/all-wcprops | 17 + .../Impl/SQLite/.svn/entries | 96 ++ .../.svn/text-base/SQLiteDialect.cs.svn-base | 44 + .../SQLiteTransformationProvider.cs.svn-base | 232 +++++ .../Impl/SQLite/SQLiteDialect.cs | 44 + .../SQLite/SQLiteTransformationProvider.cs | 232 +++++ .../Migrator.Providers.csproj | 118 +++ .../Migrator.Providers/MigratorDotNet.snk | Bin 0 -> 596 bytes .../NoOpTransformationProvider.cs | 336 +++++++ .../TransformationProvider.cs | 853 ++++++++++++++++++ Migrator.net/Migrator.Providers/TypeNames.cs | 130 +++ Migrator.net/Migrator/BaseMigrate.cs | 110 +++ Migrator.net/Migrator/Compile/ScriptEngine.cs | 118 +++ .../Migrator/DuplicatedVersionException.cs | 26 + .../IrreversibleMigrationException.cs | 26 + Migrator.net/Migrator/MigrateAnywhere.cs | 99 ++ Migrator.net/Migrator/MigrateDown.cs | 0 Migrator.net/Migrator/MigrateUp.cs | 0 Migrator.net/Migrator/MigrationComparer.cs | 43 + Migrator.net/Migrator/MigrationLoader.cs | 136 +++ Migrator.net/Migrator/Migrator.cs | 177 ++++ Migrator.net/Migrator/Migrator.csproj | 76 ++ Migrator.net/Migrator/MigratorDotNet.snk | Bin 0 -> 596 bytes Migrator.net/Migrator/ProviderFactory.cs | 75 ++ Migrator.net/Migrator/Tools/SchemaDumper.cs | 70 ++ Migrator.net/config/AssemblyInfo.cs | 27 + NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 24 +- NzbDrone.Core.Test/RepositoryProviderTest.cs | 10 +- NzbDrone.Core/Datastore/Migrations.cs | 39 +- NzbDrone.Core/Datastore/RepositoryProvider.cs | 7 +- NzbDrone.Core/NzbDrone.Core.csproj | 26 +- NzbDrone.Core/Providers/Jobs/JobProvider.cs | 4 +- NzbDrone.sln | 47 + 91 files changed, 7217 insertions(+), 47 deletions(-) create mode 100644 Migrator.net/Migrator.Framework/Column.cs create mode 100644 Migrator.net/Migrator.Framework/ColumnProperty.cs create mode 100644 Migrator.net/Migrator.Framework/ForeignKeyConstraint.cs create mode 100644 Migrator.net/Migrator.Framework/IColumn.cs create mode 100644 Migrator.net/Migrator.Framework/ILogger.cs create mode 100644 Migrator.net/Migrator.Framework/IMigration.cs create mode 100644 Migrator.net/Migrator.Framework/ITransformationProvider.cs create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/all-wcprops create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/entries create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ConsoleWriter.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/text-base/IAttachableLogger.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ILogWriter.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/text-base/Logger.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/Loggers/.svn/text-base/SqlScriptFileLogger.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/Loggers/ConsoleWriter.cs create mode 100644 Migrator.net/Migrator.Framework/Loggers/IAttachableLogger.cs create mode 100644 Migrator.net/Migrator.Framework/Loggers/ILogWriter.cs create mode 100644 Migrator.net/Migrator.Framework/Loggers/Logger.cs create mode 100644 Migrator.net/Migrator.Framework/Loggers/SqlScriptFileLogger.cs create mode 100644 Migrator.net/Migrator.Framework/Migration.cs create mode 100644 Migrator.net/Migrator.Framework/MigrationAttribute.cs create mode 100644 Migrator.net/Migrator.Framework/MigrationException.cs create mode 100644 Migrator.net/Migrator.Framework/Migrator.Framework.csproj create mode 100644 Migrator.net/Migrator.Framework/MigratorDotNet.snk create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/all-wcprops create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/entries create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/ForeignKey.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/IFluentColumn.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddColumnExpression.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddTableExpression.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/DeleteTableExpression.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/FluentColumn.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ForeignKey.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IColumnOptions.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IDeleteTableOptions.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IFluentColumn.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IForeignKeyOptions.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ISchemaBuilderExpression.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/RenameTableExpression.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/SchemaBuilder.cs.svn-base create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/AddTableExpression.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/FluentColumn.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/ForeignKey.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/IColumnOptions.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/IFluentColumn.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs create mode 100644 Migrator.net/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs create mode 100644 Migrator.net/Migrator.Framework/StringUtils.cs create mode 100644 Migrator.net/Migrator.Providers/ColumnPropertiesMapper.cs create mode 100644 Migrator.net/Migrator.Providers/Dialect.cs create mode 100644 Migrator.net/Migrator.Providers/ForeignKeyConstraintMapper.cs create mode 100644 Migrator.net/Migrator.Providers/Impl/.svn/all-wcprops create mode 100644 Migrator.net/Migrator.Providers/Impl/.svn/entries create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/.svn/all-wcprops create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/.svn/entries create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteDialect.cs.svn-base create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteTransformationProvider.cs.svn-base create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs create mode 100644 Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs create mode 100644 Migrator.net/Migrator.Providers/Migrator.Providers.csproj create mode 100644 Migrator.net/Migrator.Providers/MigratorDotNet.snk create mode 100644 Migrator.net/Migrator.Providers/NoOpTransformationProvider.cs create mode 100644 Migrator.net/Migrator.Providers/TransformationProvider.cs create mode 100644 Migrator.net/Migrator.Providers/TypeNames.cs create mode 100644 Migrator.net/Migrator/BaseMigrate.cs create mode 100644 Migrator.net/Migrator/Compile/ScriptEngine.cs create mode 100644 Migrator.net/Migrator/DuplicatedVersionException.cs create mode 100644 Migrator.net/Migrator/IrreversibleMigrationException.cs create mode 100644 Migrator.net/Migrator/MigrateAnywhere.cs create mode 100644 Migrator.net/Migrator/MigrateDown.cs create mode 100644 Migrator.net/Migrator/MigrateUp.cs create mode 100644 Migrator.net/Migrator/MigrationComparer.cs create mode 100644 Migrator.net/Migrator/MigrationLoader.cs create mode 100644 Migrator.net/Migrator/Migrator.cs create mode 100644 Migrator.net/Migrator/Migrator.csproj create mode 100644 Migrator.net/Migrator/MigratorDotNet.snk create mode 100644 Migrator.net/Migrator/ProviderFactory.cs create mode 100644 Migrator.net/Migrator/Tools/SchemaDumper.cs create mode 100644 Migrator.net/config/AssemblyInfo.cs diff --git a/Migrator.net/Migrator.Framework/Column.cs b/Migrator.net/Migrator.Framework/Column.cs new file mode 100644 index 000000000..8542ecc8b --- /dev/null +++ b/Migrator.net/Migrator.Framework/Column.cs @@ -0,0 +1,126 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework +{ + /// + /// Represents a table column. + /// + public class Column : IColumn + { + private string _name; + private DbType _type; + private int _size; + private ColumnProperty _property; + private object _defaultValue; + + public Column(string name) + { + Name = name; + } + + public Column(string name, DbType type) + { + Name = name; + Type = type; + } + + public Column(string name, DbType type, int size) + { + Name = name; + Type = type; + Size = size; + } + + public Column(string name, DbType type, object defaultValue) + { + Name = name; + Type = type; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property) + { + Name = name; + Type = type; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + public DbType Type + { + get { return _type; } + set { _type = value; } + } + + public int Size + { + get { return _size; } + set { _size = value; } + } + + public ColumnProperty ColumnProperty + { + get { return _property; } + set { _property = value; } + } + + public object DefaultValue + { + get { return _defaultValue; } + set { _defaultValue = value; } + } + + public bool IsIdentity + { + get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } + } + + public bool IsPrimaryKey + { + get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } + } + } +} diff --git a/Migrator.net/Migrator.Framework/ColumnProperty.cs b/Migrator.net/Migrator.Framework/ColumnProperty.cs new file mode 100644 index 000000000..434f89f13 --- /dev/null +++ b/Migrator.net/Migrator.Framework/ColumnProperty.cs @@ -0,0 +1,50 @@ +using System; + +namespace Migrator.Framework +{ + + /// + /// Represents a table column properties. + /// + [Flags] + public enum ColumnProperty + { + None = 0, + /// + /// Null is allowable + /// + Null = 1, + /// + /// Null is not allowable + /// + NotNull = 2, + /// + /// Identity column, autoinc + /// + Identity = 4, + /// + /// Unique Column + /// + Unique = 8, + /// + /// Indexed Column + /// + Indexed = 16, + /// + /// Unsigned Column + /// + Unsigned = 32, + /// + /// Foreign Key + /// + ForeignKey = Unsigned | Null, + /// + /// Primary Key + /// + PrimaryKey = 64 | Unsigned | NotNull, + /// + /// Primary key. Make the column a PrimaryKey and unsigned + /// + PrimaryKeyWithIdentity = PrimaryKey | Identity + } +} diff --git a/Migrator.net/Migrator.Framework/ForeignKeyConstraint.cs b/Migrator.net/Migrator.Framework/ForeignKeyConstraint.cs new file mode 100644 index 000000000..26d29fbcd --- /dev/null +++ b/Migrator.net/Migrator.Framework/ForeignKeyConstraint.cs @@ -0,0 +1,11 @@ +namespace Migrator.Framework +{ + public enum ForeignKeyConstraint + { + Cascade, + SetNull, + NoAction, + Restrict, + SetDefault + } +} diff --git a/Migrator.net/Migrator.Framework/IColumn.cs b/Migrator.net/Migrator.Framework/IColumn.cs new file mode 100644 index 000000000..aa2a4d183 --- /dev/null +++ b/Migrator.net/Migrator.Framework/IColumn.cs @@ -0,0 +1,34 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework +{ + public interface IColumn + { + ColumnProperty ColumnProperty { get; set; } + + string Name { get; set; } + + DbType Type { get; set; } + + int Size { get; set; } + + bool IsIdentity { get; } + + bool IsPrimaryKey { get; } + + object DefaultValue { get; set; } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/ILogger.cs b/Migrator.net/Migrator.Framework/ILogger.cs new file mode 100644 index 000000000..d6b0cee0e --- /dev/null +++ b/Migrator.net/Migrator.Framework/ILogger.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; + +namespace Migrator.Framework +{ + public interface ILogger + { + /// + /// Log that we have started a migration + /// + /// Start list of versions + /// Final Version + void Started(List currentVersion, long finalVersion); + + /// + /// Log that we are migrating up + /// + /// Version we are migrating to + /// Migration name + void MigrateUp(long version, string migrationName); + + /// + /// Log that we are migrating down + /// + /// Version we are migrating to + /// Migration name + void MigrateDown(long version, string migrationName); + + /// + /// Inform that a migration corresponding to the number of + /// version is untraceable (not found?) and will be ignored. + /// + /// Version we couldnt find + void Skipping(long version); + + /// + /// Log that we are rolling back to version + /// + /// + /// version + /// + void RollingBack(long originalVersion); + + /// + /// Log a Sql statement that changes the schema or content of the database as part of a migration + /// + /// + /// SELECT statements should not be logged using this method as they do not alter the data or schema of the + /// database. + /// + /// The Sql statement to log + void ApplyingDBChange(string sql); + + /// + /// Log that we had an exception on a migration + /// + /// The version of the migration that caused the exception. + /// The name of the migration that caused the exception. + /// The exception itself + void Exception(long version, string migrationName, Exception ex); + + /// + /// Log that we had an exception on a migration + /// + /// An informative message to show to the user. + /// The exception itself + void Exception(string message, Exception ex); + + /// + /// Log that we have finished a migration + /// + /// List of versions with which we started + /// Final Version + void Finished(List currentVersion, long finalVersion); + + /// + /// Log a message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Log(string format, params object[] args); + + /// + /// Log a Warning + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Warn(string format, params object[] args); + + /// + /// Log a Trace Message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Trace(string format, params object[] args); + } +} diff --git a/Migrator.net/Migrator.Framework/IMigration.cs b/Migrator.net/Migrator.Framework/IMigration.cs new file mode 100644 index 000000000..eb7a77509 --- /dev/null +++ b/Migrator.net/Migrator.Framework/IMigration.cs @@ -0,0 +1,39 @@ +namespace Migrator.Framework +{ + public interface IMigration + { + string Name { get; } + + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + ITransformationProvider Database { get; set; } + + /// + /// Defines tranformations to port the database to the current version. + /// + void Up(); + + /// + /// This is run after the Up transaction has been committed + /// + void AfterUp(); + + /// + /// Defines transformations to revert things done in Up. + /// + void Down(); + + /// + /// This is run after the Down transaction has been committed + /// + void AfterDown(); + + /// + /// This gets called once on the first migration object. + /// + void InitializeOnce(string[] args); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/ITransformationProvider.cs b/Migrator.net/Migrator.Framework/ITransformationProvider.cs new file mode 100644 index 000000000..46d77199f --- /dev/null +++ b/Migrator.net/Migrator.Framework/ITransformationProvider.cs @@ -0,0 +1,469 @@ +using System; +using System.Data; +using System.Collections.Generic; + +namespace Migrator.Framework +{ + /// + /// The main interface to use in Migrations to make changes on a database schema. + /// + public interface ITransformationProvider : IDisposable + { + + /// + /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. + /// + ITransformationProvider this[string provider] { get;} + + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } + + ILogger Logger { get; set; } + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, DbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, DbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, ColumnProperty property); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties + void AddColumn(string table, Column column); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraint constraint); + + /// + /// Add a foreign key constraint + /// + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraint constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraint constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, + ForeignKeyConstraint constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + void GenerateForeignKey(string foreignTable, string primaryTable); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// + void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraint constraint); + + /// + /// Add a primary key to a table + /// + /// The name of the primary key to add. + /// The name of the table that will get the primary key. + /// The name of the column or columns that are in the primary key. + void AddPrimaryKey(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The name of the column or columns that will get the constraint. + void AddUniqueConstraint(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The check constraint definition. + void AddCheckConstraint(string name, string table, string checkSql); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The columns that are part of the table. + void AddTable(string name, params Column[] columns); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The name of the database engine to use. (MySQL) + /// The columns that are part of the table. + void AddTable(string name, string engine, params Column[] columns); + + /// + /// Start a transction + /// + void BeginTransaction(); + + /// + /// Change the definition of an existing column. + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties and the name of an existing column + void ChangeColumn(string table, Column column); + + /// + /// Check to see if a column exists + /// + /// + /// + /// + bool ColumnExists(string table, string column); + + /// + /// Commit the running transction + /// + void Commit(); + + /// + /// Check to see if a constraint exists + /// + /// The name of the constraint + /// The table that the constraint lives on. + /// + bool ConstraintExists(string table, string name); + + /// + /// Check to see if a primary key constraint exists on the table + /// + /// The name of the primary key + /// The table that the constraint lives on. + /// + bool PrimaryKeyExists(string table, string name); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// + int ExecuteNonQuery(string sql); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// + IDataReader ExecuteQuery(string sql); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// A single value that is returned. + object ExecuteScalar(string sql); + + /// + /// Get the information about the columns in a table + /// + /// The table name that you want the columns for. + /// + Column[] GetColumns(string table); + + /// + /// Get information about a single column in a table + /// + /// The table name that you want the columns for. + /// The column name for which you want information. + /// + Column GetColumnByName(string table, string column); + + /// + /// Get the names of all of the tables + /// + /// The names of all the tables. + string[] GetTables(); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, string[] values); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] columns, string[] values); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The name of the column used in a where clause + /// The value for the where clause + /// + int Delete(string table, string whereColumn, string whereValue); + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + void MigrationApplied(long version); + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + void MigrationUnApplied(long version); + + /// + /// Remove an existing column from a table + /// + /// The name of the table to remove the column from + /// The column to remove + void RemoveColumn(string table, string column); + + /// + /// Remove an existing foreign key constraint + /// + /// The table that contains the foreign key. + /// The name of the foreign key to remove + void RemoveForeignKey(string table, string name); + + /// + /// Remove an existing constraint + /// + /// The table that contains the foreign key. + /// The name of the constraint to remove + void RemoveConstraint(string table, string name); + + /// + /// Remove an existing table + /// + /// The name of the table + void RemoveTable(string tableName); + + /// + /// Rename an existing table + /// + /// The old name of the table + /// The new name of the table + void RenameTable(string oldName, string newName); + + /// + /// Rename an existing table + /// + /// The name of the table + /// The old name of the column + /// The new name of the column + void RenameColumn(string tableName, string oldColumnName, string newColumnName); + + /// + /// Rollback the currently running transaction. + /// + void Rollback(); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// The where clause to limit the selection + /// + IDataReader Select(string what, string from, string where); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(string what, string from); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + /// + object SelectScalar(string what, string from, string where); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + object SelectScalar(string what, string from); + + /// + /// Check if a table already exists + /// + /// The name of the table that you want to check on. + /// + bool TableExists(string tableName); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// + int Update(string table, string[] columns, string[] columnValues); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// A where clause to limit the update + /// + int Update(string table, string[] columns, string[] values, string where); + + IDbCommand GetCommand(); + + void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/all-wcprops b/Migrator.net/Migrator.Framework/Loggers/.svn/all-wcprops new file mode 100644 index 000000000..1d7a4067b --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 54 +/svn/!svn/ver/120/trunk/src/Migrator.Framework/Loggers +END +Logger.cs +K 25 +svn:wc:ra_dav:version-url +V 64 +/svn/!svn/ver/120/trunk/src/Migrator.Framework/Loggers/Logger.cs +END +ConsoleWriter.cs +K 25 +svn:wc:ra_dav:version-url +V 70 +/svn/!svn/ver/73/trunk/src/Migrator.Framework/Loggers/ConsoleWriter.cs +END +IAttachableLogger.cs +K 25 +svn:wc:ra_dav:version-url +V 75 +/svn/!svn/ver/120/trunk/src/Migrator.Framework/Loggers/IAttachableLogger.cs +END +SqlScriptFileLogger.cs +K 25 +svn:wc:ra_dav:version-url +V 77 +/svn/!svn/ver/120/trunk/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs +END +ILogWriter.cs +K 25 +svn:wc:ra_dav:version-url +V 68 +/svn/!svn/ver/120/trunk/src/Migrator.Framework/Loggers/ILogWriter.cs +END diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/entries b/Migrator.net/Migrator.Framework/Loggers/.svn/entries new file mode 100644 index 000000000..ebffeac65 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +147 +http://migratordotnet.googlecode.com/svn/trunk/src/Migrator.Framework/Loggers +http://migratordotnet.googlecode.com/svn + + + +2008-09-11T21:48:32.631850Z +120 +geofflane + + + + + + + + + + + + + + +8c3eb3c4-eb3a-0410-862c-73fa8ce6028b + +Logger.cs +file + + + + +2011-05-23T18:17:16.585003Z +24718815685110ea98d3f4207a358907 +2008-09-11T21:48:32.631850Z +120 +geofflane + + + + + + + + + + + + + + + + + + + + + +4456 + +ConsoleWriter.cs +file + + + + +2011-05-23T18:17:16.587003Z +32bbf60aa8f07bbc281ac3be2da2a214 +2008-04-24T03:58:41.677562Z +43 +dkode8 + + + + + + + + + + + + + + + + + + + + + +838 + +IAttachableLogger.cs +file + + + + +2011-05-23T18:17:16.587003Z +e0226db3d0d21f0b59d7593f76835e9f +2008-09-11T21:48:32.631850Z +120 +geofflane + + + + + + + + + + + + + + + + + + + + + +1114 + +SqlScriptFileLogger.cs +file + + + + +2011-05-23T18:17:16.589003Z +bb2a95971af988525878e60b8cdb21a7 +2008-09-11T21:48:32.631850Z +120 +geofflane + + + + + + + + + + + + + + + + + + + + + +2527 + +ILogWriter.cs +file + + + + +2011-05-23T18:17:16.590003Z +53fd3ec26d0d191e9d4ae77530e5d928 +2008-09-11T21:48:32.631850Z +120 +geofflane + + + + + + + + + + + + + + + + + + + + + +1088 + diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ConsoleWriter.cs.svn-base b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ConsoleWriter.cs.svn-base new file mode 100644 index 000000000..8c93ec371 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ConsoleWriter.cs.svn-base @@ -0,0 +1,28 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; + +namespace Migrator.Framework.Loggers +{ + public class ConsoleWriter : ILogWriter + { + public void Write(string message, params object[] args) + { + Console.Write(message, args); + } + + public void WriteLine(string message, params object[] args) + { + Console.WriteLine(message, args); + } + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/IAttachableLogger.cs.svn-base b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/IAttachableLogger.cs.svn-base new file mode 100644 index 000000000..24b09a352 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/IAttachableLogger.cs.svn-base @@ -0,0 +1,33 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +namespace Migrator.Framework.Loggers +{ + /// + /// ILogger interface. + /// Implicit in this interface is that the logger will delegate actual + /// logging to the (s) that have been attached + /// + public interface IAttachableLogger: ILogger + { + /// + /// Attach an + /// + /// + void Attach(ILogWriter writer); + + /// + /// Detach an + /// + /// + void Detach(ILogWriter writer); + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ILogWriter.cs.svn-base b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ILogWriter.cs.svn-base new file mode 100644 index 000000000..298f53dce --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/ILogWriter.cs.svn-base @@ -0,0 +1,33 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +namespace Migrator.Framework.Loggers +{ + /// + /// Handles writing a message to the log medium (i.e. file, console) + /// + public interface ILogWriter + { + /// + /// Write this message + /// + /// + /// + void Write(string message, params object[] args); + + /// + /// Write this message, as a line + /// + /// + /// + void WriteLine(string message, params object[] args); + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/Logger.cs.svn-base b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/Logger.cs.svn-base new file mode 100644 index 000000000..4f27b1a7d --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/Logger.cs.svn-base @@ -0,0 +1,169 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; +using System.Collections.Generic; + +namespace Migrator.Framework.Loggers +{ + /// + /// Text logger for the migration mediator + /// + public class Logger : IAttachableLogger + { + private readonly bool _trace; + private readonly List _writers = new List(); + + public Logger(bool trace) + { + _trace = trace; + } + + public Logger(bool trace, params ILogWriter[] writers) + : this(trace) + { + _writers.AddRange(writers); + } + + public void Attach(ILogWriter writer) + { + _writers.Add(writer); + } + + public void Detach(ILogWriter writer) + { + _writers.Remove(writer); + } + + public void Started(long currentVersion, long finalVersion) + { + WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); + } + + public void Started(List currentVersions, long finalVersion) + { + WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + WriteLine("Applying {0}: {1}", version.ToString(), migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + WriteLine("Removing {0}: {1}", version.ToString(), migrationName); + } + + public void Skipping(long version) + { + WriteLine("{0} {1}", version.ToString(), ""); + } + + public void RollingBack(long originalVersion) + { + WriteLine("Rolling back to migration {0}", originalVersion); + } + + public void ApplyingDBChange(string sql) + { + Log(sql); + } + + public void Exception(long version, string migrationName, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error in migration: {0}", version); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + public void Exception(string message, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error: {0}", message); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + private void LogExceptionDetails(Exception ex) + { + WriteLine("{0}", ex.Message); + WriteLine("{0}", ex.StackTrace); + Exception iex = ex.InnerException; + while (iex != null) + { + WriteLine("Caused by: {0}", iex); + WriteLine("{0}", ex.StackTrace); + iex = iex.InnerException; + } + } + + public void Finished(long originalVersion, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + public void Finished(List originalVersions, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + public void Log(string format, params object[] args) + { + WriteLine(format, args); + } + + public void Warn(string format, params object[] args) + { + Write("Warning! : "); + WriteLine(format, args); + } + + public void Trace(string format, params object[] args) + { + if (_trace) + { + Log(format, args); + } + } + + private void Write(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.Write(message, args); + } + } + + private void WriteLine(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.WriteLine(message, args); + } + } + + public static ILogger ConsoleLogger() + { + return new Logger(false, new ConsoleWriter()); + } + + private string LatestVersion(List versions) + { + if (versions.Count > 0) + { + return versions[versions.Count - 1].ToString(); + } + return "No migrations applied yet!"; + } + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/SqlScriptFileLogger.cs.svn-base b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/SqlScriptFileLogger.cs.svn-base new file mode 100644 index 000000000..de70868f4 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/.svn/text-base/SqlScriptFileLogger.cs.svn-base @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Migrator.Framework.Loggers +{ + public class SqlScriptFileLogger : ILogger, IDisposable + { + private readonly ILogger _innerLogger; + private TextWriter _streamWriter; + + public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) + { + _innerLogger = logger; + _streamWriter = streamWriter; + } + + #region IDisposable Members + + public void Dispose() + { + if (_streamWriter != null) + { + _streamWriter.Dispose(); + _streamWriter = null; + } + } + + #endregion + + public void Log(string format, params object[] args) + { + _innerLogger.Log(format, args); + } + + public void Warn(string format, params object[] args) + { + _innerLogger.Warn(format, args); + } + + public void Trace(string format, params object[] args) + { + _innerLogger.Trace(format, args); + } + + public void ApplyingDBChange(string sql) + { + _innerLogger.ApplyingDBChange(sql); + _streamWriter.WriteLine(sql); + } + + public void Started(List appliedVersions, long finalVersion) + { + _innerLogger.Started(appliedVersions, finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + _innerLogger.MigrateUp(version, migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + _innerLogger.MigrateDown(version, migrationName); + } + + public void Skipping(long version) + { + _innerLogger.Skipping(version); + } + + public void RollingBack(long originalVersion) + { + _innerLogger.RollingBack(originalVersion); + } + + public void Exception(long version, string migrationName, Exception ex) + { + _innerLogger.Exception(version, migrationName, ex); + } + + public void Exception(string message, Exception ex) + { + _innerLogger.Exception(message, ex); + } + + public void Finished(List appliedVersions, long currentVersion) + { + _innerLogger.Finished(appliedVersions, currentVersion); + _streamWriter.Close(); + } + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/ConsoleWriter.cs b/Migrator.net/Migrator.Framework/Loggers/ConsoleWriter.cs new file mode 100644 index 000000000..8c93ec371 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/ConsoleWriter.cs @@ -0,0 +1,28 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; + +namespace Migrator.Framework.Loggers +{ + public class ConsoleWriter : ILogWriter + { + public void Write(string message, params object[] args) + { + Console.Write(message, args); + } + + public void WriteLine(string message, params object[] args) + { + Console.WriteLine(message, args); + } + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/IAttachableLogger.cs b/Migrator.net/Migrator.Framework/Loggers/IAttachableLogger.cs new file mode 100644 index 000000000..24b09a352 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/IAttachableLogger.cs @@ -0,0 +1,33 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +namespace Migrator.Framework.Loggers +{ + /// + /// ILogger interface. + /// Implicit in this interface is that the logger will delegate actual + /// logging to the (s) that have been attached + /// + public interface IAttachableLogger: ILogger + { + /// + /// Attach an + /// + /// + void Attach(ILogWriter writer); + + /// + /// Detach an + /// + /// + void Detach(ILogWriter writer); + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/ILogWriter.cs b/Migrator.net/Migrator.Framework/Loggers/ILogWriter.cs new file mode 100644 index 000000000..298f53dce --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/ILogWriter.cs @@ -0,0 +1,33 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +namespace Migrator.Framework.Loggers +{ + /// + /// Handles writing a message to the log medium (i.e. file, console) + /// + public interface ILogWriter + { + /// + /// Write this message + /// + /// + /// + void Write(string message, params object[] args); + + /// + /// Write this message, as a line + /// + /// + /// + void WriteLine(string message, params object[] args); + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/Logger.cs b/Migrator.net/Migrator.Framework/Loggers/Logger.cs new file mode 100644 index 000000000..4f27b1a7d --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/Logger.cs @@ -0,0 +1,169 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; +using System.Collections.Generic; + +namespace Migrator.Framework.Loggers +{ + /// + /// Text logger for the migration mediator + /// + public class Logger : IAttachableLogger + { + private readonly bool _trace; + private readonly List _writers = new List(); + + public Logger(bool trace) + { + _trace = trace; + } + + public Logger(bool trace, params ILogWriter[] writers) + : this(trace) + { + _writers.AddRange(writers); + } + + public void Attach(ILogWriter writer) + { + _writers.Add(writer); + } + + public void Detach(ILogWriter writer) + { + _writers.Remove(writer); + } + + public void Started(long currentVersion, long finalVersion) + { + WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); + } + + public void Started(List currentVersions, long finalVersion) + { + WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + WriteLine("Applying {0}: {1}", version.ToString(), migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + WriteLine("Removing {0}: {1}", version.ToString(), migrationName); + } + + public void Skipping(long version) + { + WriteLine("{0} {1}", version.ToString(), ""); + } + + public void RollingBack(long originalVersion) + { + WriteLine("Rolling back to migration {0}", originalVersion); + } + + public void ApplyingDBChange(string sql) + { + Log(sql); + } + + public void Exception(long version, string migrationName, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error in migration: {0}", version); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + public void Exception(string message, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error: {0}", message); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + private void LogExceptionDetails(Exception ex) + { + WriteLine("{0}", ex.Message); + WriteLine("{0}", ex.StackTrace); + Exception iex = ex.InnerException; + while (iex != null) + { + WriteLine("Caused by: {0}", iex); + WriteLine("{0}", ex.StackTrace); + iex = iex.InnerException; + } + } + + public void Finished(long originalVersion, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + public void Finished(List originalVersions, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + public void Log(string format, params object[] args) + { + WriteLine(format, args); + } + + public void Warn(string format, params object[] args) + { + Write("Warning! : "); + WriteLine(format, args); + } + + public void Trace(string format, params object[] args) + { + if (_trace) + { + Log(format, args); + } + } + + private void Write(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.Write(message, args); + } + } + + private void WriteLine(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.WriteLine(message, args); + } + } + + public static ILogger ConsoleLogger() + { + return new Logger(false, new ConsoleWriter()); + } + + private string LatestVersion(List versions) + { + if (versions.Count > 0) + { + return versions[versions.Count - 1].ToString(); + } + return "No migrations applied yet!"; + } + } +} diff --git a/Migrator.net/Migrator.Framework/Loggers/SqlScriptFileLogger.cs b/Migrator.net/Migrator.Framework/Loggers/SqlScriptFileLogger.cs new file mode 100644 index 000000000..de70868f4 --- /dev/null +++ b/Migrator.net/Migrator.Framework/Loggers/SqlScriptFileLogger.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Migrator.Framework.Loggers +{ + public class SqlScriptFileLogger : ILogger, IDisposable + { + private readonly ILogger _innerLogger; + private TextWriter _streamWriter; + + public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) + { + _innerLogger = logger; + _streamWriter = streamWriter; + } + + #region IDisposable Members + + public void Dispose() + { + if (_streamWriter != null) + { + _streamWriter.Dispose(); + _streamWriter = null; + } + } + + #endregion + + public void Log(string format, params object[] args) + { + _innerLogger.Log(format, args); + } + + public void Warn(string format, params object[] args) + { + _innerLogger.Warn(format, args); + } + + public void Trace(string format, params object[] args) + { + _innerLogger.Trace(format, args); + } + + public void ApplyingDBChange(string sql) + { + _innerLogger.ApplyingDBChange(sql); + _streamWriter.WriteLine(sql); + } + + public void Started(List appliedVersions, long finalVersion) + { + _innerLogger.Started(appliedVersions, finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + _innerLogger.MigrateUp(version, migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + _innerLogger.MigrateDown(version, migrationName); + } + + public void Skipping(long version) + { + _innerLogger.Skipping(version); + } + + public void RollingBack(long originalVersion) + { + _innerLogger.RollingBack(originalVersion); + } + + public void Exception(long version, string migrationName, Exception ex) + { + _innerLogger.Exception(version, migrationName, ex); + } + + public void Exception(string message, Exception ex) + { + _innerLogger.Exception(message, ex); + } + + public void Finished(List appliedVersions, long currentVersion) + { + _innerLogger.Finished(appliedVersions, currentVersion); + _streamWriter.Close(); + } + } +} diff --git a/Migrator.net/Migrator.Framework/Migration.cs b/Migrator.net/Migrator.Framework/Migration.cs new file mode 100644 index 000000000..5150e1cef --- /dev/null +++ b/Migrator.net/Migrator.Framework/Migration.cs @@ -0,0 +1,119 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework +{ + /// + /// A migration is a group of transformation applied to the database schema + /// (or sometimes data) to port the database from one version to another. + /// The Up() method must apply the modifications (eg.: create a table) + /// and the Down() method must revert, or rollback the modifications + /// (eg.: delete a table). + /// + /// Each migration must be decorated with the [Migration(0)] attribute. + /// Each migration number (0) must be unique, or else a + /// DuplicatedVersionException will be trown. + /// + /// + /// All migrations are executed inside a transaction. If an exception is + /// thrown, the transaction will be rolledback and transformations wont be + /// applied. + /// + /// + /// It is best to keep a limited number of transformation inside a migration + /// so you can easely move from one version of to another with fine grain + /// modifications. + /// You should give meaningful name to the migration class and prepend the + /// migration number to the filename so they keep ordered, eg.: + /// 002_CreateTableTest.cs. + /// + /// + /// Use the Database property to apply transformation and the + /// Logger property to output informations in the console (or other). + /// For more details on transformations see + /// ITransformationProvider. + /// + /// + /// + /// The following migration creates a new Customer table. + /// (File 003_AddCustomerTable.cs) + /// + /// [Migration(3)] + /// public class AddCustomerTable : Migration + /// { + /// public override void Up() + /// { + /// Database.AddTable("Customer", + /// new Column("Name", typeof(string), 50), + /// new Column("Address", typeof(string), 100) + /// ); + /// } + /// public override void Down() + /// { + /// Database.RemoveTable("Customer"); + /// } + /// } + /// + /// + public abstract class Migration : IMigration + { + private ITransformationProvider _transformationProvider; + + public string Name + { + get { return StringUtils.ToHumanName(GetType().Name); } + } + + /// + /// Defines tranformations to port the database to the current version. + /// + public abstract void Up(); + + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } + + /// + /// Defines transformations to revert things done in Up. + /// + public abstract void Down(); + + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } + + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database + { + get { return _transformationProvider; } + set { _transformationProvider = value; } + } + + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { + } + } +} diff --git a/Migrator.net/Migrator.Framework/MigrationAttribute.cs b/Migrator.net/Migrator.Framework/MigrationAttribute.cs new file mode 100644 index 000000000..c424dac14 --- /dev/null +++ b/Migrator.net/Migrator.Framework/MigrationAttribute.cs @@ -0,0 +1,53 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; + +namespace Migrator.Framework +{ + /// + /// Describe a migration + /// + public class MigrationAttribute : Attribute + { + private long _version; + private bool _ignore = false; + + /// + /// Describe the migration + /// + /// The unique version of the migration. + public MigrationAttribute(long version) + { + Version = version; + } + + /// + /// The version reflected by the migration + /// + public long Version + { + get { return _version; } + private set { _version = value; } + } + + /// + /// Set to true to ignore this migration. + /// + public bool Ignore + { + get { return _ignore; } + set { _ignore = value; } + } + } +} diff --git a/Migrator.net/Migrator.Framework/MigrationException.cs b/Migrator.net/Migrator.Framework/MigrationException.cs new file mode 100644 index 000000000..e88ea4a8c --- /dev/null +++ b/Migrator.net/Migrator.Framework/MigrationException.cs @@ -0,0 +1,30 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; + +namespace Migrator.Framework +{ + /// + /// Base class for migration errors. + /// + public class MigrationException : Exception + { + public MigrationException(string message) + : base(message) {} + + public MigrationException(string message, Exception cause) + : base(message, cause) {} + + public MigrationException(string migration, int version, Exception innerException) + : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) {} + } +} diff --git a/Migrator.net/Migrator.Framework/Migrator.Framework.csproj b/Migrator.net/Migrator.Framework/Migrator.Framework.csproj new file mode 100644 index 000000000..bf6c4d3eb --- /dev/null +++ b/Migrator.net/Migrator.Framework/Migrator.Framework.csproj @@ -0,0 +1,83 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {5270F048-E580-486C-B14C-E5B9F6E539D4} + Library + Migrator.Framework + Migrator.Framework + + + 3.5 + + + true + MigratorDotNet.snk + v2.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/MigratorDotNet.snk b/Migrator.net/Migrator.Framework/MigratorDotNet.snk new file mode 100644 index 0000000000000000000000000000000000000000..5032d709b5f932cf07ddd8f648e48be997070eca GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< literal 0 HcmV?d00001 diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/all-wcprops b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/all-wcprops new file mode 100644 index 000000000..ea94932b1 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/all-wcprops @@ -0,0 +1,77 @@ +K 25 +svn:wc:ra_dav:version-url +V 60 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder +END +FluentColumn.cs +K 25 +svn:wc:ra_dav:version-url +V 76 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/FluentColumn.cs +END +IDeleteTableOptions.cs +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/!svn/ver/122/trunk/src/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs +END +RenameTableExpression.cs +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs +END +AddTableExpression.cs +K 25 +svn:wc:ra_dav:version-url +V 82 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/AddTableExpression.cs +END +ISchemaBuilderExpression.cs +K 25 +svn:wc:ra_dav:version-url +V 88 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs +END +IColumnOptions.cs +K 25 +svn:wc:ra_dav:version-url +V 78 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/IColumnOptions.cs +END +ForeignKey.cs +K 25 +svn:wc:ra_dav:version-url +V 74 +/svn/!svn/ver/122/trunk/src/Migrator.Framework/SchemaBuilder/ForeignKey.cs +END +IFluentColumn.cs +K 25 +svn:wc:ra_dav:version-url +V 77 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/IFluentColumn.cs +END +AddColumnExpression.cs +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs +END +SchemaBuilder.cs +K 25 +svn:wc:ra_dav:version-url +V 77 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs +END +IForeignKeyOptions.cs +K 25 +svn:wc:ra_dav:version-url +V 82 +/svn/!svn/ver/122/trunk/src/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs +END +DeleteTableExpression.cs +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/!svn/ver/124/trunk/src/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs +END diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/entries b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/entries new file mode 100644 index 000000000..4b47ae201 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/entries @@ -0,0 +1,436 @@ +10 + +dir +147 +http://migratordotnet.googlecode.com/svn/trunk/src/Migrator.Framework/SchemaBuilder +http://migratordotnet.googlecode.com/svn + + + +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + +8c3eb3c4-eb3a-0410-862c-73fa8ce6028b + +FluentColumn.cs +file + + + + +2011-05-23T18:17:16.661007Z +530a5a0d558d87b32e4a9681f0066bfb +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +1746 + +IDeleteTableOptions.cs +file + + + + +2011-05-23T18:17:16.662007Z +ca7d7dcec6bf029e9d68f797d12a0b23 +2008-12-17T03:32:49.850862Z +122 +dkode8 + + + + + + + + + + + + + + + + + + + + + +748 + +RenameTableExpression.cs +file + + + + +2011-05-23T18:17:16.663007Z +09ce9cc03039ba2986e97bf91babb390 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +927 + +AddTableExpression.cs +file + + + + +2011-05-23T18:17:16.665007Z +5021cf7ddfeaf239e49f0cc34d912972 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +843 + +ISchemaBuilderExpression.cs +file + + + + +2011-05-23T18:17:16.665007Z +5edc417b65a8294e9c701da78a2a0fd0 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +665 + +IColumnOptions.cs +file + + + + +2011-05-23T18:17:16.666007Z +725aafda14fca858a75392468e46912d +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +231 + +ForeignKey.cs +file + + + + +2011-05-23T18:17:16.668007Z +dfb33fc890b6aaabfcbfbb9a55c8f628 +2008-12-17T03:32:49.850862Z +122 +dkode8 +has-props + + + + + + + + + + + + + + + + + + + + +1014 + +IFluentColumn.cs +file + + + + +2011-05-23T18:17:16.670007Z +0da0bc3bfc129443966847f12f24fec4 +2008-12-22T16:27:00.481752Z +124 +geofflane +has-props + + + + + + + + + + + + + + + + + + + + +706 + +AddColumnExpression.cs +file + + + + +2011-05-23T18:17:16.671007Z +a28232c3bc6fe16fe65fff83b1327ac3 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +1334 + +SchemaBuilder.cs +file + + + + +2011-05-23T18:17:16.672008Z +28742d9b060cf61f51534d162246e764 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +4441 + +IForeignKeyOptions.cs +file + + + + +2011-05-23T18:17:16.673008Z +67796061d9ed8701e6df79e76657ab92 +2008-12-17T03:32:49.850862Z +122 +dkode8 + + + + + + + + + + + + + + + + + + + + + +689 + +DeleteTableExpression.cs +file + + + + +2011-05-23T18:17:16.674008Z +99d55609a1311b914534e6d16d0064b2 +2008-12-22T16:27:00.481752Z +124 +geofflane + + + + + + + + + + + + + + + + + + + + + +857 + diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/ForeignKey.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/ForeignKey.cs.svn-base new file mode 100644 index 000000000..316065866 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/ForeignKey.cs.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mergeinfo +V 0 + +END diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/IFluentColumn.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/IFluentColumn.cs.svn-base new file mode 100644 index 000000000..316065866 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/prop-base/IFluentColumn.cs.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mergeinfo +V 0 + +END diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddColumnExpression.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddColumnExpression.cs.svn-base new file mode 100644 index 000000000..0bcbc9433 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddColumnExpression.cs.svn-base @@ -0,0 +1,40 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class AddColumnExpression : ISchemaBuilderExpression + { + private IFluentColumn _column; + private string _toTable; + + + public AddColumnExpression(string toTable, IFluentColumn column) + { + _column = column; + _toTable = toTable; + } + public void Create(ITransformationProvider provider) + { + provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); + + if (_column.ForeignKey != null) + { + provider.AddForeignKey( + "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + + _column.ForeignKey.PrimaryKey, + _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); + } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddTableExpression.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddTableExpression.cs.svn-base new file mode 100644 index 000000000..1bb3360c5 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/AddTableExpression.cs.svn-base @@ -0,0 +1,28 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class AddTableExpression : ISchemaBuilderExpression + { + private string _newTable; + public AddTableExpression(string newTable) + { + _newTable = newTable; + } + public void Create(ITransformationProvider provider) + { + provider.AddTable(_newTable); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/DeleteTableExpression.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/DeleteTableExpression.cs.svn-base new file mode 100644 index 000000000..82666ee5d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/DeleteTableExpression.cs.svn-base @@ -0,0 +1,28 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class DeleteTableExpression : ISchemaBuilderExpression + { + private string _tableName; + public DeleteTableExpression(string tableName) + { + _tableName = tableName; + } + public void Create(ITransformationProvider provider) + { + provider.RemoveTable(_tableName); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/FluentColumn.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/FluentColumn.cs.svn-base new file mode 100644 index 000000000..e1cc1ca02 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/FluentColumn.cs.svn-base @@ -0,0 +1,80 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public class FluentColumn : IFluentColumn + { + private Column _inner; + private ForeignKeyConstraint _constraint; + private ForeignKey _fk; + + public FluentColumn(string columnName) + { + _inner = new Column(columnName); + } + + public ColumnProperty ColumnProperty + { + get { return _inner.ColumnProperty; } + set { _inner.ColumnProperty = value; } + } + + public string Name + { + get { return _inner.Name; } + set { _inner.Name = value; } + } + + public DbType Type + { + get { return _inner.Type; } + set { _inner.Type = value; } + } + + public int Size + { + get { return _inner.Size; } + set { _inner.Size = value; } + } + + public bool IsIdentity + { + get { return _inner.IsIdentity; } + } + + public bool IsPrimaryKey + { + get { return _inner.IsPrimaryKey; } + } + + public object DefaultValue + { + get { return _inner.DefaultValue; } + set { _inner.DefaultValue = value; } + } + + public ForeignKeyConstraint Constraint + { + get { return _constraint; } + set { _constraint = value; } + } + public ForeignKey ForeignKey + { + get { return _fk; } + set { _fk = value; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ForeignKey.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ForeignKey.cs.svn-base new file mode 100644 index 000000000..095b0948a --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ForeignKey.cs.svn-base @@ -0,0 +1,39 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class ForeignKey + { + private string _primaryTable; + private string _primaryKey; + + public ForeignKey(string primaryTable, string primaryKey) + { + _primaryTable = primaryTable; + _primaryKey = primaryKey; + } + + public string PrimaryTable + { + get { return _primaryTable; } + set { _primaryTable = value; } + } + + public string PrimaryKey + { + get { return _primaryKey; } + set { _primaryKey = value; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IColumnOptions.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IColumnOptions.cs.svn-base new file mode 100644 index 000000000..8fd8cb32d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IColumnOptions.cs.svn-base @@ -0,0 +1,13 @@ +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IColumnOptions + { + SchemaBuilder OfType(DbType dbType); + + SchemaBuilder WithSize(int size); + + IForeignKeyOptions AsForeignKey(); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IDeleteTableOptions.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IDeleteTableOptions.cs.svn-base new file mode 100644 index 000000000..4d4152519 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IDeleteTableOptions.cs.svn-base @@ -0,0 +1,24 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IDeleteTableOptions + { + SchemaBuilder WithTable(string name); + + SchemaBuilder AddTable(string name); + + IDeleteTableOptions DeleteTable(string name); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IFluentColumn.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IFluentColumn.cs.svn-base new file mode 100644 index 000000000..6500ba948 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IFluentColumn.cs.svn-base @@ -0,0 +1,22 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IFluentColumn : IColumn + { + ForeignKeyConstraint Constraint { get; set; } + + ForeignKey ForeignKey { get; set; } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IForeignKeyOptions.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IForeignKeyOptions.cs.svn-base new file mode 100644 index 000000000..3cb52cbf1 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/IForeignKeyOptions.cs.svn-base @@ -0,0 +1,20 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IForeignKeyOptions + { + SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ISchemaBuilderExpression.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ISchemaBuilderExpression.cs.svn-base new file mode 100644 index 000000000..0db89f886 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/ISchemaBuilderExpression.cs.svn-base @@ -0,0 +1,20 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface ISchemaBuilderExpression + { + void Create(ITransformationProvider provider); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/RenameTableExpression.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/RenameTableExpression.cs.svn-base new file mode 100644 index 000000000..7880618a9 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/RenameTableExpression.cs.svn-base @@ -0,0 +1,31 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class RenameTableExpression : ISchemaBuilderExpression + { + private string _oldName; + private string _newName; + + public RenameTableExpression(string oldName, string newName) + { + _oldName = oldName; + _newName = newName; + } + public void Create(ITransformationProvider provider) + { + provider.RenameTable(_oldName, _newName); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/SchemaBuilder.cs.svn-base b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/SchemaBuilder.cs.svn-base new file mode 100644 index 000000000..a02c4fe6d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/.svn/text-base/SchemaBuilder.cs.svn-base @@ -0,0 +1,169 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions + { + private string _currentTable; + private IFluentColumn _currentColumn; + private IList _exprs; + + public SchemaBuilder() + { + _exprs = new List(); + } + + public IEnumerable Expressions + { + get { return _exprs; } + } + + /// + /// Adds a Table to be created to the Schema + /// + /// Table name to be created + /// SchemaBuilder for chaining + public SchemaBuilder AddTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _exprs.Add(new AddTableExpression(name)); + _currentTable = name; + + return this; + } + + public IDeleteTableOptions DeleteTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + _currentTable = ""; + _currentColumn = null; + + _exprs.Add(new DeleteTableExpression(name)); + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder RenameTable(string newName) + { + if (string.IsNullOrEmpty(newName)) + throw new ArgumentNullException("newName"); + + _exprs.Add(new RenameTableExpression(_currentTable, newName)); + _currentTable = newName; + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder WithTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _currentTable = name; + + return this; + } + + /// + /// Adds a Column to be created + /// + /// Column name to be added + /// IColumnOptions to restrict chaining + public IColumnOptions AddColumn(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(_currentTable)) + throw new ArgumentException("missing referenced table"); + + IFluentColumn column = new FluentColumn(name); + _currentColumn = column; + + _exprs.Add(new AddColumnExpression(_currentTable, column)); + return this; + } + + public SchemaBuilder OfType(DbType columnType) + { + _currentColumn.Type = columnType; + + return this; + } + + public SchemaBuilder WithProperty(ColumnProperty columnProperty) + { + _currentColumn.ColumnProperty = columnProperty; + + return this; + } + + public SchemaBuilder WithSize(int size) + { + if (size == 0) + throw new ArgumentNullException("size", "Size must be greater than zero"); + + _currentColumn.Size = size; + + return this; + } + + public SchemaBuilder WithDefaultValue(object defaultValue) + { + if (defaultValue == null) + throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); + + _currentColumn.DefaultValue = defaultValue; + + return this; + } + + public IForeignKeyOptions AsForeignKey() + { + _currentColumn.ColumnProperty = ColumnProperty.ForeignKey; + + return this; + } + + public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) + { + _currentColumn.Constraint = ForeignKeyConstraint.NoAction; + _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); + return this; + } + + public SchemaBuilder WithConstraint(ForeignKeyConstraint action) + { + _currentColumn.Constraint = action; + + return this; + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs new file mode 100644 index 000000000..0bcbc9433 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs @@ -0,0 +1,40 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class AddColumnExpression : ISchemaBuilderExpression + { + private IFluentColumn _column; + private string _toTable; + + + public AddColumnExpression(string toTable, IFluentColumn column) + { + _column = column; + _toTable = toTable; + } + public void Create(ITransformationProvider provider) + { + provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); + + if (_column.ForeignKey != null) + { + provider.AddForeignKey( + "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + + _column.ForeignKey.PrimaryKey, + _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); + } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/AddTableExpression.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/AddTableExpression.cs new file mode 100644 index 000000000..1bb3360c5 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/AddTableExpression.cs @@ -0,0 +1,28 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class AddTableExpression : ISchemaBuilderExpression + { + private string _newTable; + public AddTableExpression(string newTable) + { + _newTable = newTable; + } + public void Create(ITransformationProvider provider) + { + provider.AddTable(_newTable); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs new file mode 100644 index 000000000..82666ee5d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs @@ -0,0 +1,28 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class DeleteTableExpression : ISchemaBuilderExpression + { + private string _tableName; + public DeleteTableExpression(string tableName) + { + _tableName = tableName; + } + public void Create(ITransformationProvider provider) + { + provider.RemoveTable(_tableName); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/FluentColumn.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/FluentColumn.cs new file mode 100644 index 000000000..e1cc1ca02 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/FluentColumn.cs @@ -0,0 +1,80 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public class FluentColumn : IFluentColumn + { + private Column _inner; + private ForeignKeyConstraint _constraint; + private ForeignKey _fk; + + public FluentColumn(string columnName) + { + _inner = new Column(columnName); + } + + public ColumnProperty ColumnProperty + { + get { return _inner.ColumnProperty; } + set { _inner.ColumnProperty = value; } + } + + public string Name + { + get { return _inner.Name; } + set { _inner.Name = value; } + } + + public DbType Type + { + get { return _inner.Type; } + set { _inner.Type = value; } + } + + public int Size + { + get { return _inner.Size; } + set { _inner.Size = value; } + } + + public bool IsIdentity + { + get { return _inner.IsIdentity; } + } + + public bool IsPrimaryKey + { + get { return _inner.IsPrimaryKey; } + } + + public object DefaultValue + { + get { return _inner.DefaultValue; } + set { _inner.DefaultValue = value; } + } + + public ForeignKeyConstraint Constraint + { + get { return _constraint; } + set { _constraint = value; } + } + public ForeignKey ForeignKey + { + get { return _fk; } + set { _fk = value; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/ForeignKey.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/ForeignKey.cs new file mode 100644 index 000000000..095b0948a --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/ForeignKey.cs @@ -0,0 +1,39 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class ForeignKey + { + private string _primaryTable; + private string _primaryKey; + + public ForeignKey(string primaryTable, string primaryKey) + { + _primaryTable = primaryTable; + _primaryKey = primaryKey; + } + + public string PrimaryTable + { + get { return _primaryTable; } + set { _primaryTable = value; } + } + + public string PrimaryKey + { + get { return _primaryKey; } + set { _primaryKey = value; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/IColumnOptions.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/IColumnOptions.cs new file mode 100644 index 000000000..8fd8cb32d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/IColumnOptions.cs @@ -0,0 +1,13 @@ +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IColumnOptions + { + SchemaBuilder OfType(DbType dbType); + + SchemaBuilder WithSize(int size); + + IForeignKeyOptions AsForeignKey(); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs new file mode 100644 index 000000000..4d4152519 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs @@ -0,0 +1,24 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IDeleteTableOptions + { + SchemaBuilder WithTable(string name); + + SchemaBuilder AddTable(string name); + + IDeleteTableOptions DeleteTable(string name); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/IFluentColumn.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/IFluentColumn.cs new file mode 100644 index 000000000..6500ba948 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/IFluentColumn.cs @@ -0,0 +1,22 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IFluentColumn : IColumn + { + ForeignKeyConstraint Constraint { get; set; } + + ForeignKey ForeignKey { get; set; } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs new file mode 100644 index 000000000..3cb52cbf1 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs @@ -0,0 +1,20 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface IForeignKeyOptions + { + SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs new file mode 100644 index 000000000..0db89f886 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs @@ -0,0 +1,20 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public interface ISchemaBuilderExpression + { + void Create(ITransformationProvider provider); + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs new file mode 100644 index 000000000..7880618a9 --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs @@ -0,0 +1,31 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework.SchemaBuilder +{ + public class RenameTableExpression : ISchemaBuilderExpression + { + private string _oldName; + private string _newName; + + public RenameTableExpression(string oldName, string newName) + { + _oldName = oldName; + _newName = newName; + } + public void Create(ITransformationProvider provider) + { + provider.RenameTable(_oldName, _newName); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs b/Migrator.net/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs new file mode 100644 index 000000000..a02c4fe6d --- /dev/null +++ b/Migrator.net/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs @@ -0,0 +1,169 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Data; + +namespace Migrator.Framework.SchemaBuilder +{ + public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions + { + private string _currentTable; + private IFluentColumn _currentColumn; + private IList _exprs; + + public SchemaBuilder() + { + _exprs = new List(); + } + + public IEnumerable Expressions + { + get { return _exprs; } + } + + /// + /// Adds a Table to be created to the Schema + /// + /// Table name to be created + /// SchemaBuilder for chaining + public SchemaBuilder AddTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _exprs.Add(new AddTableExpression(name)); + _currentTable = name; + + return this; + } + + public IDeleteTableOptions DeleteTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + _currentTable = ""; + _currentColumn = null; + + _exprs.Add(new DeleteTableExpression(name)); + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder RenameTable(string newName) + { + if (string.IsNullOrEmpty(newName)) + throw new ArgumentNullException("newName"); + + _exprs.Add(new RenameTableExpression(_currentTable, newName)); + _currentTable = newName; + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder WithTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _currentTable = name; + + return this; + } + + /// + /// Adds a Column to be created + /// + /// Column name to be added + /// IColumnOptions to restrict chaining + public IColumnOptions AddColumn(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(_currentTable)) + throw new ArgumentException("missing referenced table"); + + IFluentColumn column = new FluentColumn(name); + _currentColumn = column; + + _exprs.Add(new AddColumnExpression(_currentTable, column)); + return this; + } + + public SchemaBuilder OfType(DbType columnType) + { + _currentColumn.Type = columnType; + + return this; + } + + public SchemaBuilder WithProperty(ColumnProperty columnProperty) + { + _currentColumn.ColumnProperty = columnProperty; + + return this; + } + + public SchemaBuilder WithSize(int size) + { + if (size == 0) + throw new ArgumentNullException("size", "Size must be greater than zero"); + + _currentColumn.Size = size; + + return this; + } + + public SchemaBuilder WithDefaultValue(object defaultValue) + { + if (defaultValue == null) + throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); + + _currentColumn.DefaultValue = defaultValue; + + return this; + } + + public IForeignKeyOptions AsForeignKey() + { + _currentColumn.ColumnProperty = ColumnProperty.ForeignKey; + + return this; + } + + public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) + { + _currentColumn.Constraint = ForeignKeyConstraint.NoAction; + _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); + return this; + } + + public SchemaBuilder WithConstraint(ForeignKeyConstraint action) + { + _currentColumn.Constraint = action; + + return this; + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Framework/StringUtils.cs b/Migrator.net/Migrator.Framework/StringUtils.cs new file mode 100644 index 000000000..4d91d4305 --- /dev/null +++ b/Migrator.net/Migrator.Framework/StringUtils.cs @@ -0,0 +1,43 @@ +using System.Text; +using System.Text.RegularExpressions; + +namespace Migrator.Framework +{ + public class StringUtils + { + /// + /// Convert a classname to something more readable. + /// ex.: CreateATable => Create a table + /// + /// + /// + public static string ToHumanName(string className) + { + string name = Regex.Replace(className, "([A-Z])", " $1").Substring(1); + return name.Substring(0, 1).ToUpper() + name.Substring(1).ToLower(); + } + + /// + /// + /// + /// + /// + /// + /// + public static string ReplaceOnce(string template, string placeholder, string replacement) + { + int loc = template.IndexOf(placeholder); + if (loc < 0) + { + return template; + } + else + { + return new StringBuilder(template.Substring(0, loc)) + .Append(replacement) + .Append(template.Substring(loc + placeholder.Length)) + .ToString(); + } + } + } +} diff --git a/Migrator.net/Migrator.Providers/ColumnPropertiesMapper.cs b/Migrator.net/Migrator.Providers/ColumnPropertiesMapper.cs new file mode 100644 index 000000000..8682a2c29 --- /dev/null +++ b/Migrator.net/Migrator.Providers/ColumnPropertiesMapper.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Migrator.Framework; + +namespace Migrator.Providers +{ + /// + /// This is basically a just a helper base class + /// per-database implementors may want to override ColumnSql + /// + public class ColumnPropertiesMapper + { + protected Dialect dialect; + + /// The SQL type + protected string type; + + /// The name of the column + protected string name; + + /// + /// the type of the column + /// + protected string columnSql; + + /// + /// Sql if This column is Indexed + /// + protected bool indexed = false; + + /// + /// Sql if this column has a default value + /// + protected object defaultVal; + + public ColumnPropertiesMapper(Dialect dialect, string type) + { + this.dialect = dialect; + this.type = type; + } + + /// + /// The sql for this column, override in database-specific implementation classes + /// + public virtual string ColumnSql + { + get { return columnSql; } + } + + public string Name + { + get { return name; } + set { name = value; } + } + + public object Default + { + get { return defaultVal; } + set { defaultVal = value; } + } + + public string QuotedName + { + get { return dialect.Quote(Name); } + } + + public string IndexSql + { + get + { + if (dialect.SupportsIndex && indexed) + return String.Format("INDEX({0})", dialect.Quote(name)); + return null; + } + } + + public void MapColumnProperties(Column column) + { + Name = column.Name; + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + + List vals = new List(); + vals.Add(dialect.ColumnNameNeedsQuote ? QuotedName : Name); + + vals.Add(type); + + if (! dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + + AddValueIfSelected(column, ColumnProperty.Unsigned, vals); + if (! PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity) + AddValueIfSelected(column, ColumnProperty.NotNull, vals); + + AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); + + if (dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + + AddValueIfSelected(column, ColumnProperty.Unique, vals); + AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); + + if (column.DefaultValue != null) + vals.Add(dialect.Default(column.DefaultValue)); + + columnSql = String.Join(" ", vals.ToArray()); + } + + private void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + { + if (PropertySelected(column.ColumnProperty, property)) + vals.Add(dialect.SqlForProperty(property)); + } + + public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) + { + return (source & comparison) == comparison; + } + } +} diff --git a/Migrator.net/Migrator.Providers/Dialect.cs b/Migrator.net/Migrator.Providers/Dialect.cs new file mode 100644 index 000000000..11df04dde --- /dev/null +++ b/Migrator.net/Migrator.Providers/Dialect.cs @@ -0,0 +1,181 @@ + +using System; +using System.Data; +using System.Collections.Generic; +using Migrator.Framework; + +namespace Migrator.Providers +{ + /// + /// Defines the implementations specific details for a particular database. + /// + public abstract class Dialect + { + private readonly Dictionary propertyMap = new Dictionary(); + private readonly TypeNames typeNames = new TypeNames(); + + protected Dialect() + { + RegisterProperty(ColumnProperty.Null, "NULL"); + RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); + RegisterProperty(ColumnProperty.Unique, "UNIQUE"); + RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); + } + + public abstract Type TransformationProvider { get; } + + public ITransformationProvider NewProviderForDialect(string connectionString) + { + return (ITransformationProvider) Activator.CreateInstance(TransformationProvider, this, connectionString); + } + + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(DbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } + + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(DbType code, string name) + { + typeNames.Put(code, name); + } + + public ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (! IdentityNeedsType && column.IsIdentity) + type = String.Empty; + + return new ColumnPropertiesMapper(this, type); + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + public virtual string GetTypeName(DbType type) + { + string result = typeNames.Get(type); + if (result == null) + { + throw new Exception(string.Format("No default type mapping for DbType {0}", type)); + } + + return result; + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + public virtual string GetTypeName(DbType type, int length) + { + return GetTypeName(type, length, 0, 0); + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeName(DbType type, int length, int precision, int scale) + { + string resultWithLength = typeNames.Get(type, length, precision, scale); + if (resultWithLength != null) + return resultWithLength; + + return GetTypeName(type); + } + + public void RegisterProperty(ColumnProperty property, string sql) + { + if (! propertyMap.ContainsKey(property)) + { + propertyMap.Add(property, sql); + } + propertyMap[property] = sql; + } + + public string SqlForProperty(ColumnProperty property) + { + if (propertyMap.ContainsKey(property)) + { + return propertyMap[property]; + } + return String.Empty; + } + + public virtual bool ColumnNameNeedsQuote + { + get { return false; } + } + + public virtual bool TableNameNeedsQuote + { + get { return false; } + } + + public virtual bool ConstraintNameNeedsQuote + { + get { return false; } + } + + public virtual bool IdentityNeedsType + { + get { return true; } + } + + public virtual bool NeedsNotNullForIdentity + { + get { return true; } + } + + public virtual bool SupportsIndex + { + get { return true; } + } + + public virtual string Quote(string value) + { + return String.Format(QuoteTemplate, value); + } + + public virtual string QuoteTemplate + { + get { return "\"{0}\""; } + } + + public virtual string Default(object defaultValue) + { + return String.Format("DEFAULT {0}", defaultValue); + } + + public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) + { + ColumnPropertiesMapper mapper = GetColumnMapper(column); + mapper.MapColumnProperties(column); + if (column.DefaultValue != null) + mapper.Default = column.DefaultValue; + return mapper; + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/ForeignKeyConstraintMapper.cs b/Migrator.net/Migrator.Providers/ForeignKeyConstraintMapper.cs new file mode 100644 index 000000000..35c4a8e93 --- /dev/null +++ b/Migrator.net/Migrator.Providers/ForeignKeyConstraintMapper.cs @@ -0,0 +1,24 @@ +using Migrator.Framework; + +namespace Migrator.Providers +{ + public class ForeignKeyConstraintMapper + { + public string SqlForConstraint(ForeignKeyConstraint constraint) + { + switch(constraint) + { + case ForeignKeyConstraint.Cascade: + return "CASCADE"; + case ForeignKeyConstraint.Restrict: + return "RESTRICT"; + case ForeignKeyConstraint.SetDefault: + return "SET DEFAULT"; + case ForeignKeyConstraint.SetNull: + return "SET NULL"; + default: + return "NO ACTION"; + } + } + } +} diff --git a/Migrator.net/Migrator.Providers/Impl/.svn/all-wcprops b/Migrator.net/Migrator.Providers/Impl/.svn/all-wcprops new file mode 100644 index 000000000..2ad37dc87 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/.svn/all-wcprops @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 51 +/svn/!svn/ver/144/trunk/src/Migrator.Providers/Impl +END diff --git a/Migrator.net/Migrator.Providers/Impl/.svn/entries b/Migrator.net/Migrator.Providers/Impl/.svn/entries new file mode 100644 index 000000000..2b80596b8 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/.svn/entries @@ -0,0 +1,43 @@ +10 + +dir +147 +http://migratordotnet.googlecode.com/svn/trunk/src/Migrator.Providers/Impl +http://migratordotnet.googlecode.com/svn + + + +2010-03-25T22:27:09.529568Z +144 +geofflane + + + + + + + + + + + + + + +8c3eb3c4-eb3a-0410-862c-73fa8ce6028b + +SQLite +dir + +PostgreSQL +dir + +Oracle +dir + +Mysql +dir + +SqlServer +dir + diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/all-wcprops b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/all-wcprops new file mode 100644 index 000000000..cd10a5fe9 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/108/trunk/src/Migrator.Providers/Impl/SQLite +END +SQLiteTransformationProvider.cs +K 25 +svn:wc:ra_dav:version-url +V 90 +/svn/!svn/ver/108/trunk/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +END +SQLiteDialect.cs +K 25 +svn:wc:ra_dav:version-url +V 74 +/svn/!svn/ver/87/trunk/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs +END diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/entries b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/entries new file mode 100644 index 000000000..bbb0295b3 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +147 +http://migratordotnet.googlecode.com/svn/trunk/src/Migrator.Providers/Impl/SQLite +http://migratordotnet.googlecode.com/svn + + + +2008-08-04T22:56:23.283456Z +108 +geofflane + + + + + + + + + + + + + + +8c3eb3c4-eb3a-0410-862c-73fa8ce6028b + +SQLiteTransformationProvider.cs +file + + + + +2011-05-23T18:17:16.308987Z +1a5895030f84893a6051489dcd1958d2 +2008-08-04T22:56:23.283456Z +108 +geofflane + + + + + + + + + + + + + + + + + + + + + +8486 + +SQLiteDialect.cs +file + + + + +2011-05-23T18:17:16.309987Z +4dc0c91dddefbb5ec3c85037f025f3f3 +2008-06-12T19:25:48.586161Z +87 +geofflane + + + + + + + + + + + + + + + + + + + + + +1786 + diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteDialect.cs.svn-base b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteDialect.cs.svn-base new file mode 100644 index 000000000..0731f79ef --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteDialect.cs.svn-base @@ -0,0 +1,44 @@ + +using System; +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.SQLite +{ + public class SQLiteDialect : Dialect + { + public SQLiteDialect() + { + RegisterColumnType(DbType.Binary, "BLOB"); + RegisterColumnType(DbType.Byte, "INTEGER"); + RegisterColumnType(DbType.Int16, "INTEGER"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "INTEGER"); + RegisterColumnType(DbType.SByte, "INTEGER"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "INTEGER"); + RegisterColumnType(DbType.UInt64, "INTEGER"); + RegisterColumnType(DbType.Currency, "NUMERIC"); + RegisterColumnType(DbType.Decimal, "NUMERIC"); + RegisterColumnType(DbType.Double, "NUMERIC"); + RegisterColumnType(DbType.Single, "NUMERIC"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC"); + RegisterColumnType(DbType.String, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, "TEXT"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.Time, "DATETIME"); + RegisterColumnType(DbType.Boolean, "INTEGER"); + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + + RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); + } + + public override Type TransformationProvider { get { return typeof(SQLiteTransformationProvider); } } + + public override bool NeedsNotNullForIdentity + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteTransformationProvider.cs.svn-base b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteTransformationProvider.cs.svn-base new file mode 100644 index 000000000..ad6f3cc31 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/.svn/text-base/SQLiteTransformationProvider.cs.svn-base @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Data; +using Migrator.Framework; +using ForeignKeyConstraint=Migrator.Framework.ForeignKeyConstraint; +#if DOTNET2 +using SqliteConnection=System.Data.SQLite.SQLiteConnection; +#else +using Mono.Data.Sqlite; +#endif + +namespace Migrator.Providers.SQLite +{ + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteTransformationProvider : TransformationProvider + { + public SQLiteTransformationProvider(Dialect dialect, string connectionString) + : base(dialect, connectionString) + { + _connection = new SqliteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + // NOOP Because SQLite doesn't support foreign keys + } + + public override void RemoveForeignKey(string name, string table) + { + // NOOP Because SQLite doesn't support foreign keys + } + + public override void RemoveColumn(string table, string column) + { + if (! (TableExists(table) && ColumnExists(table, column))) + return; + + string[] origColDefs = GetColumnDefs(table); + List colDefs = new List(); + + foreach (string origdef in origColDefs) + { + if (! ColumnMatch(column, origdef)) + colDefs.Add(origdef); + } + + string[] newColDefs = colDefs.ToArray(); + string colDefsSql = String.Join(",", newColDefs); + + string[] colNames = ParseSqlForColumnNames(newColDefs); + string colNamesSql = String.Join(",", colNames); + + AddTable(table + "_temp", null, colDefsSql); + ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + RemoveTable(table); + ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + { + string[] columnDefs = GetColumnDefs(tableName); + string columnDef = Array.Find(columnDefs, delegate(string col) { return ColumnMatch(oldColumnName, col); }); + + string newColumnDef = columnDef.Replace(oldColumnName, newColumnName); + + AddColumn(tableName, newColumnDef); + ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); + RemoveColumn(tableName, oldColumnName); + } + } + + public override void ChangeColumn(string table, Column column) + { + if (! ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + string tempColumn = "temp_" + column.Name; + RenameColumn(table, column.Name, tempColumn); + AddColumn(table, column); + ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + RemoveColumn(table, tempColumn); + } + + public override bool TableExists(string table) + { + using (IDataReader reader = + ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='table' and name='{0}'",table))) + { + return reader.Read(); + } + } + + public override bool ConstraintExists(string table, string name) + { + return false; + } + + public override string[] GetTables() + { + List tables = new List(); + + using (IDataReader reader = ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + { + while (reader.Read()) + { + tables.Add((string) reader[0]); + } + } + + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + List columns = new List(); + foreach (string columnDef in GetColumnDefs(table)) + { + string name = ExtractNameFromColumnDef(columnDef); + // FIXME: Need to get the real type information + Column column = new Column(name, DbType.String); + bool isNullable = IsNullable(columnDef); + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + columns.Add(column); + } + return columns.ToArray(); + } + + public string GetSqlDefString(string table) + { + string sqldef = null; + using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'",table))) + { + if (reader.Read()) + { + sqldef = (string) reader[0]; + } + } + return sqldef; + } + + public string[] GetColumnNames(string table) + { + return ParseSqlForColumnNames(GetSqlDefString(table)); + } + + public string[] GetColumnDefs(string table) + { + return ParseSqlColumnDefs(GetSqlDefString(table)); + } + + /// + /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + /// + public string[] ParseSqlForColumnNames(string sqldef) + { + string[] parts = ParseSqlColumnDefs(sqldef); + return ParseSqlForColumnNames(parts); + } + + public string[] ParseSqlForColumnNames(string[] parts) + { + if (null == parts) + return null; + + for (int i = 0; i < parts.Length; i ++) + { + parts[i] = ExtractNameFromColumnDef(parts[i]); + } + return parts; + } + + /// + /// Name is the first value before the space. + /// + /// + /// + public string ExtractNameFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" "); + if (idx > 0) + { + return columnDef.Substring(0, idx); + } + return null; + } + + public bool IsNullable(string columnDef) + { + return ! columnDef.Contains("NOT NULL"); + } + + public string[] ParseSqlColumnDefs(string sqldef) + { + if (String.IsNullOrEmpty(sqldef)) + { + return null; + } + + sqldef = sqldef.Replace(Environment.NewLine, " "); + int start = sqldef.IndexOf("("); + int end = sqldef.IndexOf(")"); + + sqldef = sqldef.Substring(0, end); + sqldef = sqldef.Substring(start + 1); + + string[] cols = sqldef.Split(new char[]{','}); + for (int i = 0; i < cols.Length; i ++) + { + cols[i] = cols[i].Trim(); + } + return cols; + } + + public bool ColumnMatch(string column, string columnDef) + { + return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs new file mode 100644 index 000000000..0731f79ef --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs @@ -0,0 +1,44 @@ + +using System; +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.SQLite +{ + public class SQLiteDialect : Dialect + { + public SQLiteDialect() + { + RegisterColumnType(DbType.Binary, "BLOB"); + RegisterColumnType(DbType.Byte, "INTEGER"); + RegisterColumnType(DbType.Int16, "INTEGER"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "INTEGER"); + RegisterColumnType(DbType.SByte, "INTEGER"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "INTEGER"); + RegisterColumnType(DbType.UInt64, "INTEGER"); + RegisterColumnType(DbType.Currency, "NUMERIC"); + RegisterColumnType(DbType.Decimal, "NUMERIC"); + RegisterColumnType(DbType.Double, "NUMERIC"); + RegisterColumnType(DbType.Single, "NUMERIC"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC"); + RegisterColumnType(DbType.String, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, "TEXT"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.Time, "DATETIME"); + RegisterColumnType(DbType.Boolean, "INTEGER"); + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + + RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); + } + + public override Type TransformationProvider { get { return typeof(SQLiteTransformationProvider); } } + + public override bool NeedsNotNullForIdentity + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs new file mode 100644 index 000000000..d4731d218 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Data; +using Migrator.Framework; +using ForeignKeyConstraint=Migrator.Framework.ForeignKeyConstraint; +#if DOTNET2 +using SqliteConnection=System.Data.SQLite.SQLiteConnection; +#else +using Mono.Data.Sqlite; +#endif + +namespace Migrator.Providers.SQLite +{ + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteTransformationProvider : TransformationProvider + { + public SQLiteTransformationProvider(Dialect dialect, string connectionString) + : base(dialect, connectionString) + { + _connection = new SqliteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + // NOOP Because SQLite doesn't support foreign keys + } + + public override void RemoveForeignKey(string name, string table) + { + // NOOP Because SQLite doesn't support foreign keys + } + + public override void RemoveColumn(string table, string column) + { + if (! (TableExists(table) && ColumnExists(table, column))) + return; + + string[] origColDefs = GetColumnDefs(table); + List colDefs = new List(); + + foreach (string origdef in origColDefs) + { + if (! ColumnMatch(column, origdef)) + colDefs.Add(origdef); + } + + string[] newColDefs = colDefs.ToArray(); + string colDefsSql = String.Join(",", newColDefs); + + string[] colNames = ParseSqlForColumnNames(newColDefs); + string colNamesSql = String.Join(",", colNames); + + AddTable(table + "_temp", null, colDefsSql); + ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + RemoveTable(table); + ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + { + string[] columnDefs = GetColumnDefs(tableName); + string columnDef = Array.Find(columnDefs, delegate(string col) { return ColumnMatch(oldColumnName, col); }); + + string newColumnDef = columnDef.Replace(oldColumnName, newColumnName); + + AddColumn(tableName, newColumnDef); + ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); + RemoveColumn(tableName, oldColumnName); + } + } + + public override void ChangeColumn(string table, Column column) + { + if (! ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + string tempColumn = "temp_" + column.Name; + RenameColumn(table, column.Name, tempColumn); + AddColumn(table, column); + ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + RemoveColumn(table, tempColumn); + } + + public override bool TableExists(string table) + { + using (IDataReader reader = + ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='table' and name='{0}'",table))) + { + return reader.Read(); + } + } + + public override bool ConstraintExists(string table, string name) + { + return false; + } + + public override string[] GetTables() + { + List tables = new List(); + + using (IDataReader reader = ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + { + while (reader.Read()) + { + tables.Add((string) reader[0]); + } + } + + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + List columns = new List(); + foreach (string columnDef in GetColumnDefs(table)) + { + string name = ExtractNameFromColumnDef(columnDef); + // FIXME: Need to get the real type information + Column column = new Column(name, DbType.String); + bool isNullable = IsNullable(columnDef); + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + columns.Add(column); + } + return columns.ToArray(); + } + + public string GetSqlDefString(string table) + { + string sqldef = null; + using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'",table))) + { + if (reader.Read()) + { + sqldef = (string) reader[0]; + } + } + return sqldef; + } + + public string[] GetColumnNames(string table) + { + return ParseSqlForColumnNames(GetSqlDefString(table)); + } + + public string[] GetColumnDefs(string table) + { + return ParseSqlColumnDefs(GetSqlDefString(table)); + } + + /// + /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + /// + public string[] ParseSqlForColumnNames(string sqldef) + { + string[] parts = ParseSqlColumnDefs(sqldef); + return ParseSqlForColumnNames(parts); + } + + public string[] ParseSqlForColumnNames(string[] parts) + { + if (null == parts) + return null; + + for (int i = 0; i < parts.Length; i ++) + { + parts[i] = ExtractNameFromColumnDef(parts[i]); + } + return parts; + } + + /// + /// Name is the first value before the space. + /// + /// + /// + public string ExtractNameFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" "); + if (idx > 0) + { + return columnDef.Substring(0, idx); + } + return null; + } + + public bool IsNullable(string columnDef) + { + return ! columnDef.Contains("NOT NULL"); + } + + public string[] ParseSqlColumnDefs(string sqldef) + { + if (String.IsNullOrEmpty(sqldef)) + { + return null; + } + + sqldef = sqldef.Replace(Environment.NewLine, " "); + int start = sqldef.IndexOf("("); + int end = sqldef.LastIndexOf(")"); + + sqldef = sqldef.Substring(0, end); + sqldef = sqldef.Substring(start + 1); + + string[] cols = sqldef.Split(new char[]{','}); + for (int i = 0; i < cols.Length; i ++) + { + cols[i] = cols[i].Trim(); + } + return cols; + } + + public bool ColumnMatch(string column, string columnDef) + { + return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/Migrator.Providers.csproj b/Migrator.net/Migrator.Providers/Migrator.Providers.csproj new file mode 100644 index 000000000..b6290d3c2 --- /dev/null +++ b/Migrator.net/Migrator.Providers/Migrator.Providers.csproj @@ -0,0 +1,118 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {D58C68E4-D789-40F7-9078-C9F587D4363C} + Library + Migrator.Providers + Migrator.Providers + + + 3.5 + + + false + true + MigratorDotNet.snk + v2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;DOTNET2 + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + ..\..\NzbDrone.Core\Libraries\System.Data.SQLite.dll + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + {5270F048-E580-486C-B14C-E5B9F6E539D4} + Migrator.Framework + + + + + \ No newline at end of file diff --git a/Migrator.net/Migrator.Providers/MigratorDotNet.snk b/Migrator.net/Migrator.Providers/MigratorDotNet.snk new file mode 100644 index 0000000000000000000000000000000000000000..5032d709b5f932cf07ddd8f648e48be997070eca GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< literal 0 HcmV?d00001 diff --git a/Migrator.net/Migrator.Providers/NoOpTransformationProvider.cs b/Migrator.net/Migrator.Providers/NoOpTransformationProvider.cs new file mode 100644 index 000000000..48f666658 --- /dev/null +++ b/Migrator.net/Migrator.Providers/NoOpTransformationProvider.cs @@ -0,0 +1,336 @@ +using System.Data; +using Migrator.Framework; +using ForeignKeyConstraint=Migrator.Framework.ForeignKeyConstraint; +using System.Collections.Generic; + +namespace Migrator.Providers +{ + /// + /// No Op (Null Object Pattern) implementation of the ITransformationProvider + /// + public class NoOpTransformationProvider : ITransformationProvider + { + + public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); + + private NoOpTransformationProvider() + { + + } + + public virtual ILogger Logger + { + get { return null; } + set { } + } + + public Dialect Dialect + { + get { return null; } + } + + public string[] GetTables() + { + return null; + } + + public Column[] GetColumns(string table) + { + return null; + } + + public Column GetColumnByName(string table, string column) + { + return null; + } + + public void RemoveForeignKey(string table, string name) + { + // No Op + } + + public void RemoveConstraint(string table, string name) + { + // No Op + } + + public void AddTable(string name, params Column[] columns) + { + // No Op + } + + public void AddTable(string name, string engine, params Column[] columns) + { + // No Op + } + + public void RemoveTable(string name) + { + // No Op + } + + public void RenameTable(string oldName, string newName) + { + // No Op + } + + public void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + // No Op + } + + public void AddColumn(string table, string sqlColumn) + { + // No Op + } + + public void RemoveColumn(string table, string column) + { + // No Op + } + + public bool ColumnExists(string table, string column) + { + return false; + } + + public bool TableExists(string table) + { + return false; + } + + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, object defaultValue) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, int size) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + // No Op + } + + public void AddPrimaryKey(string name, string table, params string[] columns) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraint constraint) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, + string refColumn) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraint constraint) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + // No Op + } + + public void AddUniqueConstraint(string name, string table, params string[] columns) + { + // No Op + } + + public void AddCheckConstraint(string name, string table, string checkSql) + { + // No Op + } + + public bool ConstraintExists(string table, string name) + { + return false; + } + + public void ChangeColumn(string table, Column column) + { + // No Op + } + + + public bool PrimaryKeyExists(string table, string name) + { + return false; + } + + public int ExecuteNonQuery(string sql) + { + return 0; + } + + public IDataReader ExecuteQuery(string sql) + { + return null; + } + + public object ExecuteScalar(string sql) + { + return null; + } + + public IDataReader Select(string what, string from) + { + return null; + } + + public IDataReader Select(string what, string from, string where) + { + return null; + } + + public object SelectScalar(string what, string from) + { + return null; + } + + public object SelectScalar(string what, string from, string where) + { + return null; + } + + public int Update(string table, string[] columns, string[] columnValues) + { + return 0; + } + + public int Update(string table, string[] columns, string[] columnValues, string where) + { + return 0; + } + + public int Insert(string table, string[] columns, string[] columnValues) + { + return 0; + } + + public int Delete(string table, string[] columns, string[] columnValues) + { + return 0; + } + + public int Delete(string table, string column, string value) + { + return 0; + } + + public void BeginTransaction() + { + // No Op + } + + public void Rollback() + { + // No Op + } + + public void Commit() + { + // No Op + } + + public ITransformationProvider this[string provider] + { + get { return this; } + } + + public void MigrationApplied(long version) + { + //no op + } + + public void MigrationUnApplied(long version) + { + //no op + } + + public List AppliedMigrations + { + get { return new List(); } + } + + protected void CreateSchemaInfoTable() + { + + } + + public void AddColumn(string table, Column column) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string refTable) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraint constraint) + { + // No Op + } + + public IDbCommand GetCommand() + { + return null; + } + + public void ExecuteSchemaBuilder(Migrator.Framework.SchemaBuilder.SchemaBuilder schemaBuilder) + { + // No Op + } + + public void Dispose() + { + //No Op + } + } +} diff --git a/Migrator.net/Migrator.Providers/TransformationProvider.cs b/Migrator.net/Migrator.Providers/TransformationProvider.cs new file mode 100644 index 000000000..964780746 --- /dev/null +++ b/Migrator.net/Migrator.Providers/TransformationProvider.cs @@ -0,0 +1,853 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Data; +using Migrator.Framework; +using Migrator.Framework.SchemaBuilder; +using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using Migrator.Framework.Loggers; + +namespace Migrator.Providers +{ + /// + /// Base class for every transformation providers. + /// A 'tranformation' is an operation that modifies the database. + /// + public abstract class TransformationProvider : ITransformationProvider + { + private ILogger _logger; + protected IDbConnection _connection; + private IDbTransaction _transaction; + private List _appliedMigrations; + + protected readonly string _connectionString; + protected Dialect _dialect; + + private readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + + protected TransformationProvider(Dialect dialect, string connectionString) + { + _dialect = dialect; + _connectionString = connectionString; + _logger = new Logger(false); + } + + /// + /// Returns the event logger + /// + public virtual ILogger Logger + { + get { return _logger; } + set { _logger = value; } + } + + public Dialect Dialect + { + get { return _dialect; } + } + + public ITransformationProvider this[string provider] + { + get + { + if (null != provider && IsThisProvider(provider)) + return this; + + return NoOpTransformationProvider.Instance; + } + } + + public bool IsThisProvider(string provider) + { + // XXX: This might need to be more sophisticated. Currently just a convention + return GetType().Name.ToLower().StartsWith(provider.ToLower()); + } + + public virtual Column[] GetColumns(string table) + { + List columns = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("select COLUMN_NAME, IS_NULLABLE from information_schema.columns where table_name = '{0}'", table))) + { + while (reader.Read()) + { + Column column = new Column(reader.GetString(0), DbType.String); + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "YES"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public virtual Column GetColumnByName(string table, string columnName) + { + return Array.Find(GetColumns(table), + delegate(Column column) + { + return column.Name == columnName; + }); + } + + public virtual string[] GetTables() + { + List tables = new List(); + using (IDataReader reader = ExecuteQuery("SELECT table_name FROM information_schema.tables")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + return tables.ToArray(); + } + + public virtual void RemoveForeignKey(string table, string name) + { + RemoveConstraint(table, name); + } + + public virtual void RemoveConstraint(string table, string name) + { + if (TableExists(table) && ConstraintExists(table, name)) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + name = _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", table, name)); + } + } + + public virtual void AddTable(string table, string engine, string columns) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + ExecuteNonQuery(sqlCreate); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, params Column[] columns) + { + // Most databases don't have the concept of a storage engine, so default is to not use it. + AddTable(name, null, columns); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// the database storage engine to use + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", "INNODB", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, string engine, params Column[] columns) + { + + if (TableExists(name)) + { + Logger.Warn("Table {0} already exists", name); + return; + } + + List pks = GetPrimaryKeys(columns); + bool compoundPrimaryKey = pks.Count > 1; + + List columnProviders = new List(columns.Length); + foreach (Column column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) + column.ColumnProperty = ColumnProperty.Unsigned | ColumnProperty.NotNull; + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } + + string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + AddTable(name, engine, columnsAndIndexes); + + if (compoundPrimaryKey) + { + AddPrimaryKey(String.Format("PK_{0}", name), name, pks.ToArray()); + } + } + + public List GetPrimaryKeys(IEnumerable columns) + { + List pks = new List(); + foreach (Column col in columns) + { + if (col.IsPrimaryKey) + pks.Add(col.Name); + } + return pks; + } + + public virtual void RemoveTable(string name) + { + if (TableExists(name)) + ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); + } + + public virtual void RenameTable(string oldName, string newName) + { + if (TableExists(newName)) + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + + if (TableExists(oldName)) + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } + + public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); + } + + public virtual void AddColumn(string table, string sqlColumn) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + } + + public virtual void RemoveColumn(string table, string column) + { + if (ColumnExists(table, column)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, column)); + } + } + + public virtual bool ColumnExists(string table, string column) + { + try + { + ExecuteNonQuery(String.Format("SELECT {0} FROM {1}", column, table)); + return true; + } + catch (Exception) + { + return false; + } + } + + public virtual void ChangeColumn(string table, Column column) + { + if (!ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + ChangeColumn(table, mapper.ColumnSql); + } + + public virtual void ChangeColumn(string table, string sqlColumn) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + } + + public virtual bool TableExists(string table) + { + try + { + ExecuteNonQuery("SELECT COUNT(*) FROM " + table); + return true; + } + catch (Exception) + { + return false; + } + } + + protected virtual string JoinColumnsAndIndexes(IEnumerable columns) + { + string indexes = JoinIndexes(columns); + string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + return columnsAndIndexes; + } + + protected virtual string JoinIndexes(IEnumerable columns) + { + List indexes = new List(); + foreach (ColumnPropertiesMapper column in columns) + { + string indexSql = column.IndexSql; + if (indexSql != null) + indexes.Add(indexSql); + } + + if (indexes.Count == 0) + return null; + + return String.Join(", ", indexes.ToArray()); + } + + protected virtual string JoinColumns(IEnumerable columns) + { + List columnStrings = new List(); + foreach (ColumnPropertiesMapper column in columns) + columnStrings.Add(column.ColumnSql); + return String.Join(", ", columnStrings.ToArray()); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + object defaultValue) + { + if (ColumnExists(table, column)) + { + Logger.Warn("Column {0}.{1} already exists", table, column); + return; + } + + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + public void AddColumn(string table, string column, DbType type, object defaultValue) + { + if (ColumnExists(table, column)) + { + Logger.Warn("Column {0}.{1} already exists", table, column); + return; + } + + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } + + /// + /// Append a primary key to a table. + /// + /// Constraint name + /// Table name + /// Primary column names + public virtual void AddPrimaryKey(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Primary key {0} already exists", name); + return; + } + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, + String.Join(",", columns))); + } + + public virtual void AddUniqueConstraint(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + } + + public virtual void AddCheckConstraint(string name, string table, string checkSql) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, + string refColumn, ForeignKeyConstraint constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, + constraint); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, + constraint); + } + + /// + /// Append a foreign key (relation) between two tables. + /// tables. + /// + /// Constraint name + /// Table name containing the primary key + /// Primary key column name + /// Foreign table name + /// Foreign column name + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, + string refColumn) + { + AddForeignKey(name, primaryTable, new string[] { primaryColumn }, refTable, new string[] { refColumn }); + } + + /// + /// + /// AddForeignKey(string, string, string, string, string) + /// + /// + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraint.NoAction); + } + + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraint constraint) + { + AddForeignKey(name, primaryTable, new string[] { primaryColumn }, refTable, new string[] { refColumn }, + constraint); + } + + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraint constraint) + { + if (ConstraintExists(primaryTable, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + + string constraintResolved = constraintMapper.SqlForConstraint(constraint); + ExecuteNonQuery( + String.Format( + "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", + primaryTable, name, String.Join(",", primaryColumns), + refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); + } + + /// + /// Determines if a constraint exists. + /// + /// Constraint name + /// Table owning the constraint + /// true if the constraint exists. + public abstract bool ConstraintExists(string table, string name); + + public virtual bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public int ExecuteNonQuery(string sql) + { + Logger.Trace(sql); + Logger.ApplyingDBChange(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Logger.Warn(ex.Message); + throw; + } + } } + + private IDbCommand BuildCommand(string sql) + { + IDbCommand cmd = _connection.CreateCommand(); + cmd.CommandText = sql; + cmd.CommandType = CommandType.Text; + if (_transaction != null) + { + cmd.Transaction = _transaction; + } + return cmd; + } + + /// + /// Execute an SQL query returning results. + /// + /// The SQL command. + /// A data iterator, IDataReader. + public IDataReader ExecuteQuery(string sql) + { + Logger.Trace(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteReader(); + } + catch + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw; + } + } } + + public object ExecuteScalar(string sql) + { + Logger.Trace(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteScalar(); + } + catch + { + Logger.Warn("Query failed: {0}", cmd.CommandText); + throw; + } + } } + + public IDataReader Select(string what, string from) + { + return Select(what, from, "1=1"); + } + + public virtual IDataReader Select(string what, string from, string where) + { + return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public object SelectScalar(string what, string from) + { + return SelectScalar(what, from, "1=1"); + } + + public virtual object SelectScalar(string what, string from, string where) + { + return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual int Update(string table, string[] columns, string[] values) + { + return Update(table, columns, values, null); + } + + public virtual int Update(string table, string[] columns, string[] values, string where) + { + string namesAndValues = JoinColumnsAndValues(columns, values); + + string query = "UPDATE {0} SET {1}"; + if (!String.IsNullOrEmpty(where)) + { + query += " WHERE " + where; + } + + return ExecuteNonQuery(String.Format(query, table, namesAndValues)); + } + + public virtual int Insert(string table, string[] columns, string[] values) + { + return ExecuteNonQuery(String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, String.Join(", ", columns), String.Join(", ", QuoteValues(values)))); + } + + public virtual int Delete(string table) + { + return Delete(table, (string[])null, (string[]) null); + } + + public virtual int Delete(string table, string[] columns, string[] values) + { + if (null == columns || null == values) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + } + else + { + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE ({1})", table, JoinColumnsAndValues(columns, values))); + } + } + + public virtual int Delete(string table, string wherecolumn, string wherevalue) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); + } + + /// + /// Starts a transaction. Called by the migration mediator. + /// + public void BeginTransaction() + { + if (_transaction == null && _connection != null) + { + EnsureHasConnection(); + _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); + } + } + + protected void EnsureHasConnection() + { + if (_connection.State != ConnectionState.Open) + { + _connection.Open(); + } + } + + /// + /// Rollback the current migration. Called by the migration mediator. + /// + public virtual void Rollback() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Rollback(); + } + finally + { + _connection.Close(); + } + } + _transaction = null; + } + + /// + /// Commit the current transaction. Called by the migrations mediator. + /// + public void Commit() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Commit(); + } + finally + { + _connection.Close(); + } + } + _transaction = null; + } + + /// + /// The list of Migrations currently applied to the database. + /// + public List AppliedMigrations + { + get + { + if(_appliedMigrations == null) + { + _appliedMigrations = new List(); + CreateSchemaInfoTable(); + using(IDataReader reader = Select("version","SchemaInfo")){ + while(reader.Read()){ + _appliedMigrations.Add(Convert.ToInt64(reader.GetValue(0))); + } + } + } + return _appliedMigrations; + } + } + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + public void MigrationApplied(long version) + { + CreateSchemaInfoTable(); + Insert("SchemaInfo",new string[]{"version"},new string[]{version.ToString()}); + _appliedMigrations.Add(version); + } + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + public void MigrationUnApplied(long version) + { + CreateSchemaInfoTable(); + Delete("SchemaInfo", "version", version.ToString()); + _appliedMigrations.Remove(version); + } + + protected void CreateSchemaInfoTable() + { + EnsureHasConnection(); + if (!TableExists("SchemaInfo")) + { + AddTable("SchemaInfo", new Column("Version", DbType.Int64, ColumnProperty.PrimaryKey)); + } + } + + public void AddColumn(string table, Column column) + { + AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); + } + + public void GenerateForeignKey(string primaryTable, string refTable) + { + GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraint.NoAction); + } + + public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraint constraint) + { + GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); + } + + public IDbCommand GetCommand() + { + return BuildCommand(null); + } + + public void ExecuteSchemaBuilder(SchemaBuilder builder) + { + foreach (ISchemaBuilderExpression expr in builder.Expressions) + expr.Create(this); + } + + public virtual string QuoteValues(string values) + { + return QuoteValues(new string[] {values})[0]; + } + + public virtual string[] QuoteValues(string[] values) + { + return Array.ConvertAll(values, + delegate(string val) { + if (null == val) + return "null"; + else + return String.Format("'{0}'", val.Replace("'", "''")); + }); + } + + public string JoinColumnsAndValues(string[] columns, string[] values) + { + string[] quotedValues = QuoteValues(values); + string[] namesAndValues = new string[columns.Length]; + for (int i = 0; i < columns.Length; i++) + { + namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); + } + + return String.Join(", ", namesAndValues); + } + + public void Dispose() + { + if (_connection != null && _connection.State == ConnectionState.Open) + { + _connection.Close(); + } + } + } +} diff --git a/Migrator.net/Migrator.Providers/TypeNames.cs b/Migrator.net/Migrator.Providers/TypeNames.cs new file mode 100644 index 000000000..60d11603d --- /dev/null +++ b/Migrator.net/Migrator.Providers/TypeNames.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers +{ + /// + /// This class maps a DbType to names. + /// + /// + /// Associations may be marked with a capacity. Calling the Get() + /// method with a type and actual size n will return the associated + /// name with smallest capacity >= n, if available and an unmarked + /// default type otherwise. + /// Eg, setting + /// + /// Names.Put(DbType, "TEXT" ); + /// Names.Put(DbType, 255, "VARCHAR($l)" ); + /// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); + /// + /// will give you back the following: + /// + /// Names.Get(DbType) // --> "TEXT" (default) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) + /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) + /// Names.Get(DbType,100000) // --> "TEXT" (default) + /// + /// On the other hand, simply putting + /// + /// Names.Put(DbType, "VARCHAR($l)" ); + /// + /// would result in + /// + /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" + /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" + /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" + /// + /// + public class TypeNames + { + public const string LengthPlaceHolder = "$l"; + public const string PrecisionPlaceHolder = "$p"; + public const string ScalePlaceHolder = "$s"; + + private readonly Dictionary> weighted = + new Dictionary>(); + + private readonly Dictionary defaults = new Dictionary(); + + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string Get(DbType typecode) + { + string result; + if (!defaults.TryGetValue(typecode, out result)) + { + throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); + } + return result; + } + + /// + /// Get the type name specified type and size + /// + /// the type key + /// the SQL length + /// the SQL scale + /// the SQL precision + /// + /// The associated name with smallest capacity >= size if available and the + /// default type name otherwise + /// + public string Get(DbType typecode, int size, int precision, int scale) + { + SortedList map; + weighted.TryGetValue(typecode, out map); + if (map != null && map.Count > 0) + { + foreach (KeyValuePair entry in map) + { + if (size <= entry.Key) + { + return Replace(entry.Value, size, precision, scale); + } + } + } + //Could not find a specific type for the size, using the default + return Replace(Get(typecode), size, precision, scale); + } + + private static string Replace(string type, int size, int precision, int scale) + { + type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); + type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); + return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); + } + + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(DbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue(typecode, out map)) + { + // add new ordered map + weighted[typecode] = map = new SortedList(); + } + map[capacity] = value; + } + + /// + /// + /// + /// + /// + public void Put(DbType typecode, string value) + { + defaults[typecode] = value; + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator/BaseMigrate.cs b/Migrator.net/Migrator/BaseMigrate.cs new file mode 100644 index 000000000..5d1847c48 --- /dev/null +++ b/Migrator.net/Migrator/BaseMigrate.cs @@ -0,0 +1,110 @@ +using Migrator.Framework; +using System.Collections.Generic; + +namespace Migrator +{ + public abstract class BaseMigrate + { + protected readonly ITransformationProvider _provider; + protected ILogger _logger; + protected List _availableMigrations; + protected List _original; + protected long _current; + protected bool _dryrun; + + protected BaseMigrate(List availableMigrations, ITransformationProvider provider, ILogger logger) + { + _provider = provider; + _availableMigrations = availableMigrations; + _original = new List (_provider.AppliedMigrations.ToArray()); //clone + _logger = logger; + } + + public static BaseMigrate GetInstance(List availableMigrations, ITransformationProvider provider, ILogger logger) + { + return new MigrateAnywhere(availableMigrations, provider, logger); + } + + public List AppliedVersions + { + get { return _original; } + } + + public virtual long Current + { + get { return _current; } + protected set { _current = value; } + } + + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + public abstract long Previous { get; } + public abstract long Next { get; } + + public void Iterate() + { + Current = Next; + } + + public abstract bool Continue(long targetVersion); + + public abstract void Migrate(IMigration migration); + + /// + /// Finds the next migration available to be applied. Only returns + /// migrations that have NOT already been applied. + /// + /// The migration number of the next available Migration. + protected long NextMigration() + { + // Start searching at the current index + int migrationSearch = _availableMigrations.IndexOf(Current)+1; + + // See if we can find a migration that matches the requirement + while(migrationSearch < _availableMigrations.Count + && _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) + { + migrationSearch++; + } + + // did we exhaust the list? + if(migrationSearch == _availableMigrations.Count){ + // we're at the last one. Done! + return _availableMigrations[migrationSearch-1]+1; + } + // found one. + return _availableMigrations[migrationSearch]; + } + + /// + /// Finds the previous migration that has been applied. Only returns + /// migrations that HAVE already been applied. + /// + /// The most recently applied Migration. + protected long PreviousMigration() + { + // Start searching at the current index + int migrationSearch = _availableMigrations.IndexOf(Current)-1; + + // See if we can find a migration that matches the requirement + while(migrationSearch > -1 + && !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) + { + migrationSearch--; + } + + // did we exhaust the list? + if(migrationSearch < 0){ + // we're at the first one. Done! + return 0; + } + + // found one. + return _availableMigrations[migrationSearch]; + } + } +} diff --git a/Migrator.net/Migrator/Compile/ScriptEngine.cs b/Migrator.net/Migrator/Compile/ScriptEngine.cs new file mode 100644 index 000000000..f9629ba48 --- /dev/null +++ b/Migrator.net/Migrator/Compile/ScriptEngine.cs @@ -0,0 +1,118 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Migrator.Framework; + +namespace Migrator.Compile +{ + public class ScriptEngine + { + public readonly string[] extraReferencedAssemblies; + + private readonly CodeDomProvider _provider; + private string _codeType = "csharp"; + + public ScriptEngine() : this(null, null) + { + } + + public ScriptEngine(string[] extraReferencedAssemblies) + : this(null, extraReferencedAssemblies) + { + } + + public ScriptEngine(string codeType, string[] extraReferencedAssemblies) + { + if (!String.IsNullOrEmpty(codeType)) + _codeType = codeType; + this.extraReferencedAssemblies = extraReferencedAssemblies; + + // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 + _provider = CodeDomProvider.CreateProvider(_codeType); + } + + public Assembly Compile(string directory) + { + string[] files = GetFilesRecursive(directory); + Console.Out.WriteLine("Compiling:"); + Array.ForEach(files, delegate(String file) { Console.Out.WriteLine(file); }); + + return Compile(files); + } + + private string[] GetFilesRecursive(string directory) + { + FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory)); + string[] fileNames = new string[files.Length]; + for (int i = 0; i < files.Length; i ++) + { + fileNames[i] = files[i].FullName; + } + return fileNames; + } + + private FileInfo[] GetFilesRecursive(DirectoryInfo d) + { + List files = new List(); + files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); + DirectoryInfo[] subDirs = d.GetDirectories(); + if (subDirs.Length > 0) + { + foreach (DirectoryInfo subDir in subDirs) + { + files.AddRange(GetFilesRecursive(subDir)); + } + } + + return files.ToArray(); + } + + public Assembly Compile(params string[] files) + { + CompilerParameters parms = SetupCompilerParams(); + + CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files); + if (compileResult.Errors.Count != 0) + { + foreach (CompilerError err in compileResult.Errors) + { + Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); + } + } + return compileResult.CompiledAssembly; + } + + private CompilerParameters SetupCompilerParams() + { + string migrationFrameworkPath = FrameworkAssemblyPath(); + CompilerParameters parms = new CompilerParameters(); + parms.CompilerOptions = "/t:library"; + parms.GenerateInMemory = true; + parms.IncludeDebugInformation = true; + parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); + + Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); + + // Add Default referenced assemblies + parms.ReferencedAssemblies.Add("mscorlib.dll"); + parms.ReferencedAssemblies.Add("System.dll"); + parms.ReferencedAssemblies.Add("System.Data.dll"); + parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); + if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) + { + Array.ForEach(extraReferencedAssemblies, + delegate(String assemb) { parms.ReferencedAssemblies.Add(assemb); }); + } + return parms; + } + + private static string FrameworkAssemblyPath() + { + string path = typeof (MigrationAttribute).Module.FullyQualifiedName; + Console.Out.WriteLine("Framework DLL: " + path); + return path; + } + } +} \ No newline at end of file diff --git a/Migrator.net/Migrator/DuplicatedVersionException.cs b/Migrator.net/Migrator/DuplicatedVersionException.cs new file mode 100644 index 000000000..511888fee --- /dev/null +++ b/Migrator.net/Migrator/DuplicatedVersionException.cs @@ -0,0 +1,26 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; + +namespace Migrator +{ + /// + /// Exception thrown when a migration number is not unique. + /// + public class DuplicatedVersionException : Exception + { + public DuplicatedVersionException(long version) + : base(String.Format("Migration version #{0} is duplicated", version)) + { + } + } +} diff --git a/Migrator.net/Migrator/IrreversibleMigrationException.cs b/Migrator.net/Migrator/IrreversibleMigrationException.cs new file mode 100644 index 000000000..06b960763 --- /dev/null +++ b/Migrator.net/Migrator/IrreversibleMigrationException.cs @@ -0,0 +1,26 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; + +namespace Migrator +{ + /// + /// Exception thrown in a migration Down() method + /// when changes can't be undone. + /// + public class IrreversibleMigrationException : Exception + { + public IrreversibleMigrationException() : base("Irreversible migration") + { + } + } +} diff --git a/Migrator.net/Migrator/MigrateAnywhere.cs b/Migrator.net/Migrator/MigrateAnywhere.cs new file mode 100644 index 000000000..eb1bde01e --- /dev/null +++ b/Migrator.net/Migrator/MigrateAnywhere.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using Migrator.Framework; + +namespace Migrator +{ + /// + /// Description of MigrateAnywhere. + /// + public class MigrateAnywhere : BaseMigrate + { + private bool _goForward; + + public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) + : base(availableMigrations, provider, logger) + { + _current = 0; + if (provider.AppliedMigrations.Count > 0) { + _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; + } + _goForward = false; + } + + public override long Next + { + get + { + return _goForward + ? NextMigration() + : PreviousMigration(); + } + } + + public override long Previous + { + get + { + return _goForward + ? PreviousMigration() + : NextMigration(); + } + } + + public override bool Continue(long version) + { + // If we're going backwards and our current is less than the target, + // reverse direction. Also, start over at zero to make sure we catch + // any merged migrations that are less than the current target. + if (!_goForward && version >= Current) + { + _goForward = true; + Current = 0; + Iterate(); + } + + // We always finish on going forward. So continue if we're still + // going backwards, or if there are no migrations left in the forward direction. + return !_goForward || Current <= version; + } + + public override void Migrate(IMigration migration) + { + _provider.BeginTransaction(); + MigrationAttribute attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute)); + + if (_provider.AppliedMigrations.Contains(attr.Version)) { + RemoveMigration(migration, attr); + } else { + ApplyMigration(migration, attr); + } + } + + private void ApplyMigration(IMigration migration, MigrationAttribute attr) + { + // we're adding this one + _logger.MigrateUp(Current, migration.Name); + if(! DryRun) + { + migration.Up(); + _provider.MigrationApplied(attr.Version); + _provider.Commit(); + migration.AfterUp(); + } + } + + private void RemoveMigration(IMigration migration, MigrationAttribute attr) + { + // we're removing this one + _logger.MigrateDown(Current, migration.Name); + if (! DryRun) + { + migration.Down(); + _provider.MigrationUnApplied(attr.Version); + _provider.Commit(); + migration.AfterDown(); + } + } + } +} diff --git a/Migrator.net/Migrator/MigrateDown.cs b/Migrator.net/Migrator/MigrateDown.cs new file mode 100644 index 000000000..e69de29bb diff --git a/Migrator.net/Migrator/MigrateUp.cs b/Migrator.net/Migrator/MigrateUp.cs new file mode 100644 index 000000000..e69de29bb diff --git a/Migrator.net/Migrator/MigrationComparer.cs b/Migrator.net/Migrator/MigrationComparer.cs new file mode 100644 index 000000000..a1f7281f3 --- /dev/null +++ b/Migrator.net/Migrator/MigrationComparer.cs @@ -0,0 +1,43 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System; +using System.Collections.Generic; +using Migrator.Framework; + +namespace Migrator +{ + /// + /// Comparer of Migration by their version attribute. + /// + public class MigrationTypeComparer : IComparer + { + private readonly bool _ascending = true; + + public MigrationTypeComparer(bool ascending) + { + _ascending = ascending; + } + + public int Compare(Type x, Type y) + { + MigrationAttribute attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); + MigrationAttribute attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); + + if (_ascending) + return attribOfX.Version.CompareTo(attribOfY.Version); + else + return attribOfY.Version.CompareTo(attribOfX.Version); + + + } + } +} diff --git a/Migrator.net/Migrator/MigrationLoader.cs b/Migrator.net/Migrator/MigrationLoader.cs new file mode 100644 index 000000000..397ed43c7 --- /dev/null +++ b/Migrator.net/Migrator/MigrationLoader.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Migrator.Framework; + +namespace Migrator +{ + /// + /// Handles inspecting code to find all of the Migrations in assemblies and reading + /// other metadata such as the last revision, etc. + /// + public class MigrationLoader + { + private readonly ITransformationProvider _provider; + private readonly List _migrationsTypes = new List(); + + public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + { + _provider = provider; + AddMigrations(migrationAssembly); + + if (trace) + { + provider.Logger.Trace("Loaded migrations:"); + foreach (Type t in _migrationsTypes) + { + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); + } + } + } + + public void AddMigrations(Assembly migrationAssembly) + { + if (migrationAssembly != null) + _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); + } + + /// + /// Returns registered migration types. + /// + public List MigrationsTypes + { + get { return _migrationsTypes; } + } + + /// + /// Returns the last version of the migrations. + /// + public long LastVersion + { + get + { + if (_migrationsTypes.Count == 0) + return 0; + return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); + } + } + + /// + /// Check for duplicated version in migrations. + /// + /// CheckForDuplicatedVersion + public void CheckForDuplicatedVersion() + { + List versions = new List(); + foreach (Type t in _migrationsTypes) + { + long version = GetMigrationVersion(t); + + if (versions.Contains(version)) + throw new DuplicatedVersionException(version); + + versions.Add(version); + } + } + + /// + /// Collect migrations in one Assembly. + /// + /// The Assembly to browse. + /// The migrations collection + public static List GetMigrationTypes(Assembly asm) + { + List migrations = new List(); + foreach (Type t in asm.GetExportedTypes()) + { + MigrationAttribute attrib = + (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); + + if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } + } + + migrations.Sort(new MigrationTypeComparer(true)); + return migrations; + } + + /// + /// Returns the version of the migration + /// MigrationAttribute. + /// + /// Migration type. + /// Version number sepcified in the attribute + public static long GetMigrationVersion(Type t) + { + MigrationAttribute attrib = (MigrationAttribute) + Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); + + return attrib.Version; + } + + public List GetAvailableMigrations() + { + //List availableMigrations = new List(); + _migrationsTypes.Sort(new MigrationTypeComparer(true)); + return _migrationsTypes.ConvertAll(new Converter(GetMigrationVersion)); + } + + public IMigration GetMigration(long version) + { + foreach (Type t in _migrationsTypes) + { + if (GetMigrationVersion(t) == version) + { + IMigration migration = (IMigration)Activator.CreateInstance(t); + migration.Database = _provider; + return migration; + } + } + + return null; + } + } +} diff --git a/Migrator.net/Migrator/Migrator.cs b/Migrator.net/Migrator/Migrator.cs new file mode 100644 index 000000000..c41c204e1 --- /dev/null +++ b/Migrator.net/Migrator/Migrator.cs @@ -0,0 +1,177 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; +using Migrator.Framework; +using Migrator.Framework.Loggers; + +namespace Migrator +{ + /// + /// Migrations mediator. + /// + public class Migrator + { + private readonly ITransformationProvider _provider; + + private readonly MigrationLoader _migrationLoader; + + private ILogger _logger = new Logger(false); + protected bool _dryrun; + private string[] _args; + + public string[] args + { + get { return _args; } + set { _args = value; } + } + + public Migrator(string provider, string connectionString, Assembly migrationAssembly) + : this(provider, connectionString, migrationAssembly, false) + { + } + + public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace) + : this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace) + { + } + + public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace, ILogger logger) + : this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace, logger) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) + { + _provider = provider; + Logger = logger; + + _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); + _migrationLoader.CheckForDuplicatedVersion(); + } + + + /// + /// Returns registered migration types. + /// + public List MigrationsTypes + { + get { return _migrationLoader.MigrationsTypes; } + } + + /// + /// Run all migrations up to the latest. Make no changes to database if + /// dryrun is true. + /// + public void MigrateToLastVersion() + { + MigrateTo(_migrationLoader.LastVersion); + } + + /// + /// Returns the current migrations applied to the database. + /// + public List AppliedMigrations + { + get { return _provider.AppliedMigrations; } + } + + /// + /// Get or set the event logger. + /// + public ILogger Logger + { + get { return _logger; } + set + { + _logger = value; + _provider.Logger = value; + } + } + + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + /// + /// Migrate the database to a specific version. + /// Runs all migration between the actual version and the + /// specified version. + /// If version is greater then the current version, + /// the Up() method will be invoked. + /// If version lower then the current version, + /// the Down() method of previous migration will be invoked. + /// If dryrun is set, don't write any changes to the database. + /// + /// The version that must became the current one + public void MigrateTo(long version) + { + + if (_migrationLoader.MigrationsTypes.Count == 0) + { + _logger.Warn("No public classes with the Migration attribute were found."); + return; + } + + bool firstRun = true; + BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); + migrate.DryRun = DryRun; + Logger.Started(migrate.AppliedVersions, version); + + while (migrate.Continue(version)) + { + IMigration migration = _migrationLoader.GetMigration(migrate.Current); + if (null == migration) + { + _logger.Skipping(migrate.Current); + migrate.Iterate(); + continue; + } + + try + { + if (firstRun) + { + migration.InitializeOnce(_args); + firstRun = false; + } + + migrate.Migrate(migration); + } + catch (Exception ex) + { + Logger.Exception(migrate.Current, migration.Name, ex); + + // Oho! error! We rollback changes. + Logger.RollingBack(migrate.Previous); + _provider.Rollback(); + + throw; + } + + migrate.Iterate(); + } + + Logger.Finished(migrate.AppliedVersions, version); + } + } +} diff --git a/Migrator.net/Migrator/Migrator.csproj b/Migrator.net/Migrator/Migrator.csproj new file mode 100644 index 000000000..c2915327f --- /dev/null +++ b/Migrator.net/Migrator/Migrator.csproj @@ -0,0 +1,76 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} + Library + Properties + Migrator + Migrator + + + 3.5 + + + true + MigratorDotNet.snk + v2.0 + + + true + full + false + bin\Migrator\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Migrator\Release\ + TRACE + prompt + 4 + + + + + + + + + AssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + {5270F048-E580-486C-B14C-E5B9F6E539D4} + Migrator.Framework + + + {D58C68E4-D789-40F7-9078-C9F587D4363C} + Migrator.Providers + + + + \ No newline at end of file diff --git a/Migrator.net/Migrator/MigratorDotNet.snk b/Migrator.net/Migrator/MigratorDotNet.snk new file mode 100644 index 0000000000000000000000000000000000000000..5032d709b5f932cf07ddd8f648e48be997070eca GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< literal 0 HcmV?d00001 diff --git a/Migrator.net/Migrator/ProviderFactory.cs b/Migrator.net/Migrator/ProviderFactory.cs new file mode 100644 index 000000000..c9f45f9d8 --- /dev/null +++ b/Migrator.net/Migrator/ProviderFactory.cs @@ -0,0 +1,75 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; +using Migrator.Framework; +using Migrator.Providers; + +namespace Migrator +{ + /// + /// Handles loading Provider implementations + /// + public class ProviderFactory + { + private static readonly Assembly providerAssembly; + private static readonly Dictionary dialects = new Dictionary(); + static ProviderFactory() + { + + //string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); + //string fullPath = Path.Combine(directory, "Migrator.Providers.dll"); + //if (fullPath.StartsWith("file:\\")) + // fullPath = fullPath.Substring(6); + //else if (fullPath.StartsWith("file:")) + // fullPath = fullPath.Substring(5); + providerAssembly = Assembly.GetAssembly(typeof(TransformationProvider)); + //providerAssembly = Assembly.LoadFrom("Migrator.Providers.dll"); + LoadDialects(); + } + + public static ITransformationProvider Create(string providerName, string connectionString) + { + object dialectInstance = DialectForProvider(providerName); + MethodInfo mi = dialectInstance.GetType().GetMethod("NewProviderForDialect", new Type[] {typeof (String)}); + return (ITransformationProvider)mi.Invoke(dialectInstance, new object[] { connectionString }); + } + + public static object DialectForProvider(string providerName) + { + if (String.IsNullOrEmpty(providerName)) + return null; + + foreach (string key in dialects.Keys) + { + if (0 < key.IndexOf(providerName, StringComparison.InvariantCultureIgnoreCase)) + return dialects[key]; + } + return null; + } + + public static void LoadDialects() + { + Type dialectType = providerAssembly.GetType("Migrator.Providers.Dialect"); + foreach (Type t in providerAssembly.GetTypes()) + { + if (t.IsSubclassOf(dialectType)) + { + dialects.Add(t.FullName, Activator.CreateInstance(t, null)); + } + } + } + } +} diff --git a/Migrator.net/Migrator/Tools/SchemaDumper.cs b/Migrator.net/Migrator/Tools/SchemaDumper.cs new file mode 100644 index 000000000..ee6195d41 --- /dev/null +++ b/Migrator.net/Migrator/Tools/SchemaDumper.cs @@ -0,0 +1,70 @@ +#region License +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. +#endregion + +using System.IO; +using Migrator.Framework; + +namespace Migrator.Tools +{ + public class SchemaDumper + { + private readonly ITransformationProvider _provider; + + public SchemaDumper(string provider, string connectionString) + { + _provider = ProviderFactory.Create(provider, connectionString); + } + + public string Dump() + { + StringWriter writer = new StringWriter(); + + writer.WriteLine("using Migrator;\n"); + writer.WriteLine("[Migration(1)]"); + writer.WriteLine("public class SchemaDump : Migration"); + writer.WriteLine("{"); + writer.WriteLine("\tpublic override void Up()"); + writer.WriteLine("\t{"); + + foreach (string table in _provider.GetTables()) + { + writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table); + foreach (Column column in _provider.GetColumns(table)) + { + writer.WriteLine("\t\t\tnew Column(\"{0}\", typeof({1})),", column.Name, column.Type); + } + writer.WriteLine("\t\t);"); + } + + writer.WriteLine("\t}\n"); + writer.WriteLine("\tpublic override void Down()"); + writer.WriteLine("\t{"); + + foreach (string table in _provider.GetTables()) + { + writer.WriteLine("\t\tDatabase.RemoveTable(\"{0}\");", table); + } + + writer.WriteLine("\t}"); + writer.WriteLine("}"); + + return writer.ToString(); + } + + public void DumpTo(string file) + { + using (StreamWriter writer = new StreamWriter(file)) + { + writer.Write(Dump()); + } + } + } +} \ No newline at end of file diff --git a/Migrator.net/config/AssemblyInfo.cs b/Migrator.net/config/AssemblyInfo.cs new file mode 100644 index 000000000..1f0e5aa7a --- /dev/null +++ b/Migrator.net/config/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Migrator")] +[assembly: AssemblyDescription("Database migration for .NET")] +[assembly: AssemblyProduct("Migrator")] +[assembly: AssemblyCopyright("Copyright © 2006")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a5f0077a-d124-449a-a684-453576551f43")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.9.1.*")] diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 2a5407133..64bf6f0b3 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -59,18 +59,6 @@ ..\packages\Unity.2.0\lib\20\Microsoft.Practices.Unity.Interception.Configuration.dll - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.dll - - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.Framework.dll - - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.Providers.dll - ..\packages\Moq.4.0.10827\lib\NET40\Moq.dll @@ -130,6 +118,18 @@ + + {5270F048-E580-486C-B14C-E5B9F6E539D4} + Migrator.Framework + + + {D58C68E4-D789-40F7-9078-C9F587D4363C} + Migrator.Providers + + + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} + Migrator + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205} NzbDrone.Core diff --git a/NzbDrone.Core.Test/RepositoryProviderTest.cs b/NzbDrone.Core.Test/RepositoryProviderTest.cs index f2bd21428..0374b7cbd 100644 --- a/NzbDrone.Core.Test/RepositoryProviderTest.cs +++ b/NzbDrone.Core.Test/RepositoryProviderTest.cs @@ -6,6 +6,7 @@ using Gallio.Framework; using MbUnit.Framework; using MbUnit.Framework.ContractVerifiers; using Migrator.Framework; +using Migrator.Providers.SQLite; using NzbDrone.Core.Datastore; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Repository; @@ -86,11 +87,12 @@ namespace NzbDrone.Core.Test string connectionString = "Data Source=" + Guid.NewGuid() + ".db;Version=3;New=True"; var dbProvider = ProviderFactory.GetProvider(connectionString, "System.Data.SQLite"); var repo = new SimpleRepository(dbProvider, SimpleRepositoryOptions.RunMigrations); + var sqliteDatabase = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString); repo.Add(new TestRepoType(){Value = "Dummy"}); var repositoryProvider = new RepositoryProvider(); - var columns = repositoryProvider.GetColumnsFromDatabase(connectionString, "TestRepoTypes"); + var columns = repositoryProvider.GetColumnsFromDatabase(sqliteDatabase, "TestRepoTypes"); Assert.Count(3, columns); @@ -102,13 +104,14 @@ namespace NzbDrone.Core.Test { string connectionString = "Data Source=" + Guid.NewGuid() + ".db;Version=3;New=True"; var dbProvider = ProviderFactory.GetProvider(connectionString, "System.Data.SQLite"); + var sqliteDatabase = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString); var repo = new SimpleRepository(dbProvider, SimpleRepositoryOptions.RunMigrations); repo.Add(new TestRepoType(){Value = "Dummy"}); var repositoryProvider = new RepositoryProvider(); var typeSchema = repositoryProvider.GetSchemaFromType(typeof(TestRepoType2)); - var columns = repositoryProvider.GetColumnsFromDatabase(connectionString, "TestRepoTypes"); + var columns = repositoryProvider.GetColumnsFromDatabase(sqliteDatabase, "TestRepoTypes"); var deletedColumns = repositoryProvider.GetDeletedColumns(typeSchema, columns); @@ -125,12 +128,13 @@ namespace NzbDrone.Core.Test string connectionString = "Data Source=" + Guid.NewGuid() + ".db;Version=3;New=True"; var dbProvider = ProviderFactory.GetProvider(connectionString, "System.Data.SQLite"); var repo = new SimpleRepository(dbProvider, SimpleRepositoryOptions.RunMigrations); + var sqliteDatabase = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString); repo.Add(new TestRepoType2() { Value = "dummy" }); var repositoryProvider = new RepositoryProvider(); var typeSchema = repositoryProvider.GetSchemaFromType(typeof(TestRepoType)); - var columns = repositoryProvider.GetColumnsFromDatabase(connectionString, "TestRepoType2s"); + var columns = repositoryProvider.GetColumnsFromDatabase(sqliteDatabase, "TestRepoType2s"); var deletedColumns = repositoryProvider.GetNewColumns(typeSchema, columns); diff --git a/NzbDrone.Core/Datastore/Migrations.cs b/NzbDrone.Core/Datastore/Migrations.cs index a3e27791a..09e361954 100644 --- a/NzbDrone.Core/Datastore/Migrations.cs +++ b/NzbDrone.Core/Datastore/Migrations.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Text; using Migrator.Framework; using NLog; +using NzbDrone.Core.Repository; using SubSonic.Extensions; using SubSonic.Schema; @@ -43,16 +44,19 @@ namespace NzbDrone.Core.Datastore foreach (var repoType in repoTypes) { var typeSchema = provider.GetSchemaFromType(repoType); - var dbColumns = provider.GetColumnsFromDatabase(Connection.MainConnectionString, typeSchema.Name); - var deletedColumns = provider.GetDeletedColumns(typeSchema, dbColumns); - - foreach (var deletedColumn in deletedColumns) + if (transformationProvider.TableExists(typeSchema.Name)) { - Logger.Info("Removing column '{0}' from '{1}'", deletedColumn.Name, repoType.Name); - transformationProvider.RemoveColumn(typeSchema.Name, deletedColumn.Name); - } + var dbColumns = provider.GetColumnsFromDatabase(transformationProvider, typeSchema.Name); + var deletedColumns = provider.GetDeletedColumns(typeSchema, dbColumns); + + foreach (var deletedColumn in deletedColumns) + { + Logger.Info("Removing column '{0}' from '{1}'", deletedColumn.Name, repoType.Name); + transformationProvider.RemoveColumn(typeSchema.Name, deletedColumn.Name); + } + } } } @@ -65,14 +69,17 @@ namespace NzbDrone.Core.Datastore foreach (var repoType in repoTypes) { var typeSchema = provider.GetSchemaFromType(repoType); - var dbColumns = provider.GetColumnsFromDatabase(Connection.MainConnectionString, typeSchema.Name); + if (transformationProvider.TableExists(typeSchema.Name)) + { + var dbColumns = provider.GetColumnsFromDatabase(transformationProvider, typeSchema.Name); - var newColumns = provider.GetNewColumns(typeSchema, dbColumns); + var newColumns = provider.GetNewColumns(typeSchema, dbColumns); - foreach (var newColumn in newColumns) - { - Logger.Info("Adding column '{0}' to '{1}'", newColumn.Name, repoType.Name); - transformationProvider.AddColumn(typeSchema.Name, newColumn); + foreach (var newColumn in newColumns) + { + Logger.Info("Adding column '{0}' to '{1}'", newColumn.Name, repoType.Name); + transformationProvider.AddColumn(typeSchema.Name, newColumn); + } } } @@ -86,6 +93,12 @@ namespace NzbDrone.Core.Datastore { public override void Up() { + //Remove jobs table forcing it to repopulate + var repoProvider = new RepositoryProvider(); + var jobTable = repoProvider.GetSchemaFromType(typeof(JobSetting)); + + Database.RemoveTable(jobTable.Name); + Migrations.RemoveDeletedColumns(Database); Migrations.AddNewColumns(Database); } diff --git a/NzbDrone.Core/Datastore/RepositoryProvider.cs b/NzbDrone.Core/Datastore/RepositoryProvider.cs index c4cc3da67..7861b9526 100644 --- a/NzbDrone.Core/Datastore/RepositoryProvider.cs +++ b/NzbDrone.Core/Datastore/RepositoryProvider.cs @@ -29,12 +29,9 @@ namespace NzbDrone.Core.Datastore return type.ToSchemaTable(Connection.MainDataProvider); } - public virtual Column[] GetColumnsFromDatabase(string connectionString, string tableName) + public virtual Column[] GetColumnsFromDatabase(ITransformationProvider database, string tableName) { - var dialact = new SQLiteDialect(); - var mig = new SQLiteTransformationProvider(dialact, connectionString); - - return mig.GetColumns(tableName); + return database.GetColumns(tableName); } diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 5d9c058b9..636beec98 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -128,18 +128,6 @@ False Libraries\Exceptioneer.WindowsFormsClient.dll - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.dll - - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.Framework.dll - - - False - ..\packages\MigratorDotNet.0.9.0.28138\lib\Net40\Migrator.Providers.dll - False ..\packages\Ninject.2.2.1.0\lib\.NetFramework 4.0\Ninject.dll @@ -276,6 +264,20 @@ + + + {5270F048-E580-486C-B14C-E5B9F6E539D4} + Migrator.Framework + + + {D58C68E4-D789-40F7-9078-C9F587D4363C} + Migrator.Providers + + + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} + Migrator + +