parent
180da4c82a
commit
ce63f05512
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a table column.
|
||||||
|
/// </summary>
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a table column properties.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum ColumnProperty
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Null is allowable
|
||||||
|
/// </summary>
|
||||||
|
Null = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Null is not allowable
|
||||||
|
/// </summary>
|
||||||
|
NotNull = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Identity column, autoinc
|
||||||
|
/// </summary>
|
||||||
|
Identity = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// Unique Column
|
||||||
|
/// </summary>
|
||||||
|
Unique = 8,
|
||||||
|
/// <summary>
|
||||||
|
/// Indexed Column
|
||||||
|
/// </summary>
|
||||||
|
Indexed = 16,
|
||||||
|
/// <summary>
|
||||||
|
/// Unsigned Column
|
||||||
|
/// </summary>
|
||||||
|
Unsigned = 32,
|
||||||
|
/// <summary>
|
||||||
|
/// Foreign Key
|
||||||
|
/// </summary>
|
||||||
|
ForeignKey = Unsigned | Null,
|
||||||
|
/// <summary>
|
||||||
|
/// Primary Key
|
||||||
|
/// </summary>
|
||||||
|
PrimaryKey = 64 | Unsigned | NotNull,
|
||||||
|
/// <summary>
|
||||||
|
/// Primary key. Make the column a PrimaryKey and unsigned
|
||||||
|
/// </summary>
|
||||||
|
PrimaryKeyWithIdentity = PrimaryKey | Identity
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
public enum ForeignKeyConstraint
|
||||||
|
{
|
||||||
|
Cascade,
|
||||||
|
SetNull,
|
||||||
|
NoAction,
|
||||||
|
Restrict,
|
||||||
|
SetDefault
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we have started a migration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentVersion">Start list of versions</param>
|
||||||
|
/// <param name="finalVersion">Final Version</param>
|
||||||
|
void Started(List<long> currentVersion, long finalVersion);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we are migrating up
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">Version we are migrating to</param>
|
||||||
|
/// <param name="migrationName">Migration name</param>
|
||||||
|
void MigrateUp(long version, string migrationName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we are migrating down
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">Version we are migrating to</param>
|
||||||
|
/// <param name="migrationName">Migration name</param>
|
||||||
|
void MigrateDown(long version, string migrationName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inform that a migration corresponding to the number of
|
||||||
|
/// version is untraceable (not found?) and will be ignored.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">Version we couldnt find</param>
|
||||||
|
void Skipping(long version);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we are rolling back to version
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="originalVersion">
|
||||||
|
/// version
|
||||||
|
/// </param>
|
||||||
|
void RollingBack(long originalVersion);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log a Sql statement that changes the schema or content of the database as part of a migration
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// SELECT statements should not be logged using this method as they do not alter the data or schema of the
|
||||||
|
/// database.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="sql">The Sql statement to log</param>
|
||||||
|
void ApplyingDBChange(string sql);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we had an exception on a migration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version of the migration that caused the exception.</param>
|
||||||
|
/// <param name="migrationName">The name of the migration that caused the exception.</param>
|
||||||
|
/// <param name="ex">The exception itself</param>
|
||||||
|
void Exception(long version, string migrationName, Exception ex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we had an exception on a migration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">An informative message to show to the user.</param>
|
||||||
|
/// <param name="ex">The exception itself</param>
|
||||||
|
void Exception(string message, Exception ex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log that we have finished a migration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentVersion">List of versions with which we started</param>
|
||||||
|
/// <param name="finalVersion">Final Version</param>
|
||||||
|
void Finished(List<long> currentVersion, long finalVersion);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log a message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format string ("{0}, blabla {1}").</param>
|
||||||
|
/// <param name="args">Parameters to apply to the format string.</param>
|
||||||
|
void Log(string format, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log a Warning
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format string ("{0}, blabla {1}").</param>
|
||||||
|
/// <param name="args">Parameters to apply to the format string.</param>
|
||||||
|
void Warn(string format, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log a Trace Message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format string ("{0}, blabla {1}").</param>
|
||||||
|
/// <param name="args">Parameters to apply to the format string.</param>
|
||||||
|
void Trace(string format, params object[] args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
public interface IMigration
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the database.
|
||||||
|
/// <see cref="ITransformationProvider"></see>.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ITransformationProvider">Migration.Framework.ITransformationProvider</seealso>
|
||||||
|
ITransformationProvider Database { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines tranformations to port the database to the current version.
|
||||||
|
/// </summary>
|
||||||
|
void Up();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is run after the Up transaction has been committed
|
||||||
|
/// </summary>
|
||||||
|
void AfterUp();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines transformations to revert things done in <c>Up</c>.
|
||||||
|
/// </summary>
|
||||||
|
void Down();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is run after the Down transaction has been committed
|
||||||
|
/// </summary>
|
||||||
|
void AfterDown();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This gets called once on the first migration object.
|
||||||
|
/// </summary>
|
||||||
|
void InitializeOnce(string[] args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,469 @@
|
|||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main interface to use in Migrations to make changes on a database schema.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITransformationProvider : IDisposable
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get this provider or a NoOp provider if you are not running in the context of 'provider'.
|
||||||
|
/// </summary>
|
||||||
|
ITransformationProvider this[string provider] { get;}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of Migrations currently applied to the database.
|
||||||
|
/// </summary>
|
||||||
|
List<long> AppliedMigrations { get; }
|
||||||
|
|
||||||
|
ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
/// <param name="size">The precision or size of the column</param>
|
||||||
|
/// <param name="property">Properties that can be ORed together</param>
|
||||||
|
/// <param name="defaultValue">The default value of the column if no value is given in a query</param>
|
||||||
|
void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
void AddColumn(string table, string column, DbType type);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
/// <param name="size">The precision or size of the column</param>
|
||||||
|
void AddColumn(string table, string column, DbType type, int size);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
/// <param name="size">The precision or size of the column</param>
|
||||||
|
/// <param name="property">Properties that can be ORed together</param>
|
||||||
|
void AddColumn(string table, string column, DbType type, int size, ColumnProperty property);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
/// <param name="property">Properties that can be ORed together</param>
|
||||||
|
void AddColumn(string table, string column, DbType type, ColumnProperty property);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table with the default column size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">The name of the new column</param>
|
||||||
|
/// <param name="type">The data type for the new columnd</param>
|
||||||
|
/// <param name="defaultValue">The default value of the column if no value is given in a query</param>
|
||||||
|
void AddColumn(string table, string column, DbType type, object defaultValue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a column to an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">An instance of a <see cref="Column">Column</see> with the specified properties</param>
|
||||||
|
void AddColumn(string table, Column column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a foreign key constraint
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the foreign key. e.g. FK_TABLE_REF</param>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumns">The columns that are the foreign keys (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary keys (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumns">The columns that are the primary keys (eg. PK_id)</param>
|
||||||
|
void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a foreign key constraint
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the foreign key. e.g. FK_TABLE_REF</param>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumns">The columns that are the foreign keys (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary keys (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumns">The columns that are the primary keys (eg. PK_id)</param>
|
||||||
|
/// <param name="constraint">Constraint parameters</param>
|
||||||
|
void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraint constraint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a foreign key constraint
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
/// <param name="name">The name of the foreign key. e.g. FK_TABLE_REF</param>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumn">The column that is the foreign key (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary keys (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumn">The column that is the primary key (eg. PK_id)</param>
|
||||||
|
void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a foreign key constraint
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the foreign key. e.g. FK_TABLE_REF</param>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumn">The column that is the foreign key (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumn">The column that is the primary key (eg. PK_id)</param>
|
||||||
|
/// <param name="constraint">Constraint parameters</param>
|
||||||
|
void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraint constraint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumn">The column that is the foreign key (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumn">The column that is the primary key (eg. PK_id)</param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumns">The columns that are the foreign keys (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumns">The column that is the primary key (eg. PK_id)</param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumns">The columns that are the foreign keys (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumns">The columns that are the primary keys (eg. PK_id)</param>
|
||||||
|
/// <param name="constraint">Constraint parameters</param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraint constraint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="foreignColumn">The columns that are the foreign keys (eg. FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="primaryColumn">The column that is the primary key (eg. PK_id)</param>
|
||||||
|
/// <param name="constraint">Constraint parameters</param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn,
|
||||||
|
ForeignKeyConstraint constraint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string primaryTable);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignTable">The table that the foreign key will be created in (eg. Table.FK_id)</param>
|
||||||
|
/// <param name="primaryTable">The table that holds the primary key (eg. Table.PK_id)</param>
|
||||||
|
/// <param name="constraint"></param>
|
||||||
|
void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraint constraint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a primary key to a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the primary key to add.</param>
|
||||||
|
/// <param name="table">The name of the table that will get the primary key.</param>
|
||||||
|
/// <param name="columns">The name of the column or columns that are in the primary key.</param>
|
||||||
|
void AddPrimaryKey(string name, string table, params string[] columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a constraint to a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constraint to add.</param>
|
||||||
|
/// <param name="table">The name of the table that will get the constraint</param>
|
||||||
|
/// <param name="columns">The name of the column or columns that will get the constraint.</param>
|
||||||
|
void AddUniqueConstraint(string name, string table, params string[] columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a constraint to a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constraint to add.</param>
|
||||||
|
/// <param name="table">The name of the table that will get the constraint</param>
|
||||||
|
/// <param name="checkSql">The check constraint definition.</param>
|
||||||
|
void AddCheckConstraint(string name, string table, string checkSql);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the table to add.</param>
|
||||||
|
/// <param name="columns">The columns that are part of the table.</param>
|
||||||
|
void AddTable(string name, params Column[] columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the table to add.</param>
|
||||||
|
/// <param name="engine">The name of the database engine to use. (MySQL)</param>
|
||||||
|
/// <param name="columns">The columns that are part of the table.</param>
|
||||||
|
void AddTable(string name, string engine, params Column[] columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start a transction
|
||||||
|
/// </summary>
|
||||||
|
void BeginTransaction();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change the definition of an existing column.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table that will get the new column</param>
|
||||||
|
/// <param name="column">An instance of a <see cref="Column">Column</see> with the specified properties and the name of an existing column</param>
|
||||||
|
void ChangeColumn(string table, Column column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check to see if a column exists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table"></param>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool ColumnExists(string table, string column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commit the running transction
|
||||||
|
/// </summary>
|
||||||
|
void Commit();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check to see if a constraint exists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the constraint</param>
|
||||||
|
/// <param name="table">The table that the constraint lives on.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool ConstraintExists(string table, string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check to see if a primary key constraint exists on the table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the primary key</param>
|
||||||
|
/// <param name="table">The table that the constraint lives on.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool PrimaryKeyExists(string table, string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute an arbitrary SQL query
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">The SQL to execute.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int ExecuteNonQuery(string sql);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute an arbitrary SQL query
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">The SQL to execute.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDataReader ExecuteQuery(string sql);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute an arbitrary SQL query
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">The SQL to execute.</param>
|
||||||
|
/// <returns>A single value that is returned.</returns>
|
||||||
|
object ExecuteScalar(string sql);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the information about the columns in a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table name that you want the columns for.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Column[] GetColumns(string table);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get information about a single column in a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table name that you want the columns for.</param>
|
||||||
|
/// <param name="column">The column name for which you want information.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Column GetColumnByName(string table, string column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the names of all of the tables
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The names of all the tables.</returns>
|
||||||
|
string[] GetTables();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert data into a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table that will get the new data</param>
|
||||||
|
/// <param name="columns">The names of the columns</param>
|
||||||
|
/// <param name="values">The values in the same order as the columns</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int Insert(string table, string[] columns, string[] values);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete data from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table that will have the data deleted</param>
|
||||||
|
/// <param name="columns">The names of the columns used in a where clause</param>
|
||||||
|
/// <param name="values">The values in the same order as the columns</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int Delete(string table, string[] columns, string[] values);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete data from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table that will have the data deleted</param>
|
||||||
|
/// <param name="whereColumn">The name of the column used in a where clause</param>
|
||||||
|
/// <param name="whereValue">The value for the where clause</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int Delete(string table, string whereColumn, string whereValue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a Migration version number as having been applied
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version number of the migration that was applied</param>
|
||||||
|
void MigrationApplied(long version);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a Migration version number as having been rolled back from the database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version number of the migration that was removed</param>
|
||||||
|
void MigrationUnApplied(long version);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an existing column from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table to remove the column from</param>
|
||||||
|
/// <param name="column">The column to remove</param>
|
||||||
|
void RemoveColumn(string table, string column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an existing foreign key constraint
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table that contains the foreign key.</param>
|
||||||
|
/// <param name="name">The name of the foreign key to remove</param>
|
||||||
|
void RemoveForeignKey(string table, string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an existing constraint
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table that contains the foreign key.</param>
|
||||||
|
/// <param name="name">The name of the constraint to remove</param>
|
||||||
|
void RemoveConstraint(string table, string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tableName">The name of the table</param>
|
||||||
|
void RemoveTable(string tableName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rename an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oldName">The old name of the table</param>
|
||||||
|
/// <param name="newName">The new name of the table</param>
|
||||||
|
void RenameTable(string oldName, string newName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rename an existing table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tableName">The name of the table</param>
|
||||||
|
/// <param name="oldColumnName">The old name of the column</param>
|
||||||
|
/// <param name="newColumnName">The new name of the column</param>
|
||||||
|
void RenameColumn(string tableName, string oldColumnName, string newColumnName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rollback the currently running transaction.
|
||||||
|
/// </summary>
|
||||||
|
void Rollback();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get values from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="what">The columns to select</param>
|
||||||
|
/// <param name="from">The table to select from</param>
|
||||||
|
/// <param name="where">The where clause to limit the selection</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDataReader Select(string what, string from, string where);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get values from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="what">The columns to select</param>
|
||||||
|
/// <param name="from">The table to select from</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDataReader Select(string what, string from);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a single value from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="what">The columns to select</param>
|
||||||
|
/// <param name="from">The table to select from</param>
|
||||||
|
/// <param name="where"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
object SelectScalar(string what, string from, string where);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a single value from a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="what">The columns to select</param>
|
||||||
|
/// <param name="from">The table to select from</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
object SelectScalar(string what, string from);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if a table already exists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tableName">The name of the table that you want to check on.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool TableExists(string tableName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the values in a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table to update</param>
|
||||||
|
/// <param name="columns">The names of the columns.</param>
|
||||||
|
/// <param name="columnValues">The values for the columns in the same order as the names.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int Update(string table, string[] columns, string[] columnValues);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the values in a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The name of the table to update</param>
|
||||||
|
/// <param name="columns">The names of the columns.</param>
|
||||||
|
/// <param name="values">The values for the columns in the same order as the names.</param>
|
||||||
|
/// <param name="where">A where clause to limit the update</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int Update(string table, string[] columns, string[] values, string where);
|
||||||
|
|
||||||
|
IDbCommand GetCommand();
|
||||||
|
|
||||||
|
void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ILogger interface.
|
||||||
|
/// Implicit in this interface is that the logger will delegate actual
|
||||||
|
/// logging to the <see cref="ILogWriter"/>(s) that have been attached
|
||||||
|
/// </summary>
|
||||||
|
public interface IAttachableLogger: ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Attach an <see cref="ILogWriter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer"></param>
|
||||||
|
void Attach(ILogWriter writer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Detach an <see cref="ILogWriter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer"></param>
|
||||||
|
void Detach(ILogWriter writer);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles writing a message to the log medium (i.e. file, console)
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogWriter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Write this message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Write(string message, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write this message, as a line
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void WriteLine(string message, params object[] args);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Text logger for the migration mediator
|
||||||
|
/// </summary>
|
||||||
|
public class Logger : IAttachableLogger
|
||||||
|
{
|
||||||
|
private readonly bool _trace;
|
||||||
|
private readonly List<ILogWriter> _writers = new List<ILogWriter>();
|
||||||
|
|
||||||
|
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<long> 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(), "<Migration not found>");
|
||||||
|
}
|
||||||
|
|
||||||
|
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<long> 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<long> versions)
|
||||||
|
{
|
||||||
|
if (versions.Count > 0)
|
||||||
|
{
|
||||||
|
return versions[versions.Count - 1].ToString();
|
||||||
|
}
|
||||||
|
return "No migrations applied yet!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<long> 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<long> appliedVersions, long currentVersion)
|
||||||
|
{
|
||||||
|
_innerLogger.Finished(appliedVersions, currentVersion);
|
||||||
|
_streamWriter.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ILogger interface.
|
||||||
|
/// Implicit in this interface is that the logger will delegate actual
|
||||||
|
/// logging to the <see cref="ILogWriter"/>(s) that have been attached
|
||||||
|
/// </summary>
|
||||||
|
public interface IAttachableLogger: ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Attach an <see cref="ILogWriter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer"></param>
|
||||||
|
void Attach(ILogWriter writer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Detach an <see cref="ILogWriter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer"></param>
|
||||||
|
void Detach(ILogWriter writer);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles writing a message to the log medium (i.e. file, console)
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogWriter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Write this message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Write(string message, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write this message, as a line
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void WriteLine(string message, params object[] args);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Text logger for the migration mediator
|
||||||
|
/// </summary>
|
||||||
|
public class Logger : IAttachableLogger
|
||||||
|
{
|
||||||
|
private readonly bool _trace;
|
||||||
|
private readonly List<ILogWriter> _writers = new List<ILogWriter>();
|
||||||
|
|
||||||
|
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<long> 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(), "<Migration not found>");
|
||||||
|
}
|
||||||
|
|
||||||
|
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<long> 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<long> versions)
|
||||||
|
{
|
||||||
|
if (versions.Count > 0)
|
||||||
|
{
|
||||||
|
return versions[versions.Count - 1].ToString();
|
||||||
|
}
|
||||||
|
return "No migrations applied yet!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<long> 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<long> appliedVersions, long currentVersion)
|
||||||
|
{
|
||||||
|
_innerLogger.Finished(appliedVersions, currentVersion);
|
||||||
|
_streamWriter.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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 <c>Up()</c> method must apply the modifications (eg.: create a table)
|
||||||
|
/// and the <c>Down()</c> method must revert, or rollback the modifications
|
||||||
|
/// (eg.: delete a table).
|
||||||
|
/// <para>
|
||||||
|
/// Each migration must be decorated with the <c>[Migration(0)]</c> attribute.
|
||||||
|
/// Each migration number (0) must be unique, or else a
|
||||||
|
/// <c>DuplicatedVersionException</c> will be trown.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// All migrations are executed inside a transaction. If an exception is
|
||||||
|
/// thrown, the transaction will be rolledback and transformations wont be
|
||||||
|
/// applied.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// 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.:
|
||||||
|
/// <c>002_CreateTableTest.cs</c>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Use the <c>Database</c> property to apply transformation and the
|
||||||
|
/// <c>Logger</c> property to output informations in the console (or other).
|
||||||
|
/// For more details on transformations see
|
||||||
|
/// <see cref="ITransformationProvider">ITransformationProvider</see>.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// The following migration creates a new Customer table.
|
||||||
|
/// (File <c>003_AddCustomerTable.cs</c>)
|
||||||
|
/// <code>
|
||||||
|
/// [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");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public abstract class Migration : IMigration
|
||||||
|
{
|
||||||
|
private ITransformationProvider _transformationProvider;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return StringUtils.ToHumanName(GetType().Name); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines tranformations to port the database to the current version.
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Up();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is run after the Up transaction has been committed
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AfterUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines transformations to revert things done in <c>Up</c>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Down();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is run after the Down transaction has been committed
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AfterDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the database.
|
||||||
|
/// <see cref="ITransformationProvider"></see>.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ITransformationProvider">Migration.Framework.ITransformationProvider</seealso>
|
||||||
|
public ITransformationProvider Database
|
||||||
|
{
|
||||||
|
get { return _transformationProvider; }
|
||||||
|
set { _transformationProvider = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This gets called once on the first migration object.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void InitializeOnce(string[] args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describe a migration
|
||||||
|
/// </summary>
|
||||||
|
public class MigrationAttribute : Attribute
|
||||||
|
{
|
||||||
|
private long _version;
|
||||||
|
private bool _ignore = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describe the migration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The unique version of the migration.</param>
|
||||||
|
public MigrationAttribute(long version)
|
||||||
|
{
|
||||||
|
Version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The version reflected by the migration
|
||||||
|
/// </summary>
|
||||||
|
public long Version
|
||||||
|
{
|
||||||
|
get { return _version; }
|
||||||
|
private set { _version = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set to <c>true</c> to ignore this migration.
|
||||||
|
/// </summary>
|
||||||
|
public bool Ignore
|
||||||
|
{
|
||||||
|
get { return _ignore; }
|
||||||
|
set { _ignore = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for migration errors.
|
||||||
|
/// </summary>
|
||||||
|
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) {}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
@ -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
|
@ -0,0 +1,5 @@
|
|||||||
|
K 13
|
||||||
|
svn:mergeinfo
|
||||||
|
V 0
|
||||||
|
|
||||||
|
END
|
@ -0,0 +1,5 @@
|
|||||||
|
K 13
|
||||||
|
svn:mergeinfo
|
||||||
|
V 0
|
||||||
|
|
||||||
|
END
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Migrator.Framework.SchemaBuilder
|
||||||
|
{
|
||||||
|
public interface IColumnOptions
|
||||||
|
{
|
||||||
|
SchemaBuilder OfType(DbType dbType);
|
||||||
|
|
||||||
|
SchemaBuilder WithSize(int size);
|
||||||
|
|
||||||
|
IForeignKeyOptions AsForeignKey();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<ISchemaBuilderExpression> _exprs;
|
||||||
|
|
||||||
|
public SchemaBuilder()
|
||||||
|
{
|
||||||
|
_exprs = new List<ISchemaBuilderExpression>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ISchemaBuilderExpression> Expressions
|
||||||
|
{
|
||||||
|
get { return _exprs; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Table to be created to the Schema
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table name to be created</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newName">Table to reference</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
public SchemaBuilder RenameTable(string newName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newName))
|
||||||
|
throw new ArgumentNullException("newName");
|
||||||
|
|
||||||
|
_exprs.Add(new RenameTableExpression(_currentTable, newName));
|
||||||
|
_currentTable = newName;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table to reference</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
public SchemaBuilder WithTable(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
throw new ArgumentNullException("name");
|
||||||
|
|
||||||
|
_currentTable = name;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Column to be created
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Column name to be added</param>
|
||||||
|
/// <returns>IColumnOptions to restrict chaining</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Migrator.Framework.SchemaBuilder
|
||||||
|
{
|
||||||
|
public interface IColumnOptions
|
||||||
|
{
|
||||||
|
SchemaBuilder OfType(DbType dbType);
|
||||||
|
|
||||||
|
SchemaBuilder WithSize(int size);
|
||||||
|
|
||||||
|
IForeignKeyOptions AsForeignKey();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<ISchemaBuilderExpression> _exprs;
|
||||||
|
|
||||||
|
public SchemaBuilder()
|
||||||
|
{
|
||||||
|
_exprs = new List<ISchemaBuilderExpression>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ISchemaBuilderExpression> Expressions
|
||||||
|
{
|
||||||
|
get { return _exprs; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Table to be created to the Schema
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table name to be created</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newName">Table to reference</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
public SchemaBuilder RenameTable(string newName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newName))
|
||||||
|
throw new ArgumentNullException("newName");
|
||||||
|
|
||||||
|
_exprs.Add(new RenameTableExpression(_currentTable, newName));
|
||||||
|
_currentTable = newName;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table to reference</param>
|
||||||
|
/// <returns>SchemaBuilder for chaining</returns>
|
||||||
|
public SchemaBuilder WithTable(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
throw new ArgumentNullException("name");
|
||||||
|
|
||||||
|
_currentTable = name;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Column to be created
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Column name to be added</param>
|
||||||
|
/// <returns>IColumnOptions to restrict chaining</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Migrator.Framework
|
||||||
|
{
|
||||||
|
public class StringUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a classname to something more readable.
|
||||||
|
/// ex.: CreateATable => Create a table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="className"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="template"></param>
|
||||||
|
/// <param name="placeholder"></param>
|
||||||
|
/// <param name="replacement"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace Migrator.Providers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is basically a just a helper base class
|
||||||
|
/// per-database implementors may want to override ColumnSql
|
||||||
|
/// </summary>
|
||||||
|
public class ColumnPropertiesMapper
|
||||||
|
{
|
||||||
|
protected Dialect dialect;
|
||||||
|
|
||||||
|
/// <summary>The SQL type</summary>
|
||||||
|
protected string type;
|
||||||
|
|
||||||
|
/// <summary>The name of the column</summary>
|
||||||
|
protected string name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the type of the column
|
||||||
|
/// </summary>
|
||||||
|
protected string columnSql;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sql if This column is Indexed
|
||||||
|
/// </summary>
|
||||||
|
protected bool indexed = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sql if this column has a default value
|
||||||
|
/// </summary>
|
||||||
|
protected object defaultVal;
|
||||||
|
|
||||||
|
public ColumnPropertiesMapper(Dialect dialect, string type)
|
||||||
|
{
|
||||||
|
this.dialect = dialect;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sql for this column, override in database-specific implementation classes
|
||||||
|
/// </summary>
|
||||||
|
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<string> vals = new List<string>();
|
||||||
|
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<string> vals)
|
||||||
|
{
|
||||||
|
if (PropertySelected(column.ColumnProperty, property))
|
||||||
|
vals.Add(dialect.SqlForProperty(property));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison)
|
||||||
|
{
|
||||||
|
return (source & comparison) == comparison;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace Migrator.Providers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the implementations specific details for a particular database.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Dialect
|
||||||
|
{
|
||||||
|
private readonly Dictionary<ColumnProperty, string> propertyMap = new Dictionary<ColumnProperty, string>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subclasses register a typename for the given type code and maximum
|
||||||
|
/// column length. <c>$l</c> in the type name will be replaced by the column
|
||||||
|
/// length (if appropriate)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code">The typecode</param>
|
||||||
|
/// <param name="capacity">Maximum length of database type</param>
|
||||||
|
/// <param name="name">The database type name</param>
|
||||||
|
protected void RegisterColumnType(DbType code, int capacity, string name)
|
||||||
|
{
|
||||||
|
typeNames.Put(code, capacity, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suclasses register a typename for the given type code. <c>$l</c> in the
|
||||||
|
/// typename will be replaced by the column length (if appropriate).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code">The typecode</param>
|
||||||
|
/// <param name="name">The database type name</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the name of the database type associated with the given
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The DbType</param>
|
||||||
|
/// <returns>The database type name used by ddl.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the name of the database type associated with the given
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The DbType</param>
|
||||||
|
/// <returns>The database type name used by ddl.</returns>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
public virtual string GetTypeName(DbType type, int length)
|
||||||
|
{
|
||||||
|
return GetTypeName(type, length, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the name of the database type associated with the given
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The DbType</param>
|
||||||
|
/// <returns>The database type name used by ddl.</returns>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <param name="precision"></param>
|
||||||
|
/// <param name="scale"></param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
K 25
|
||||||
|
svn:wc:ra_dav:version-url
|
||||||
|
V 51
|
||||||
|
/svn/!svn/ver/144/trunk/src/Migrator.Providers/Impl
|
||||||
|
END
|
@ -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
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
/// Summary description for SQLiteTransformationProvider.
|
||||||
|
/// </summary>
|
||||||
|
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<string> colDefs = new List<string>();
|
||||||
|
|
||||||
|
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<string> tables = new List<string>();
|
||||||
|
|
||||||
|
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<Column> columns = new List<Column>();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName'
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name is the first value before the space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columnDef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
/// Summary description for SQLiteTransformationProvider.
|
||||||
|
/// </summary>
|
||||||
|
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<string> colDefs = new List<string>();
|
||||||
|
|
||||||
|
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<string> tables = new List<string>();
|
||||||
|
|
||||||
|
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<Column> columns = new List<Column>();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName'
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name is the first value before the space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columnDef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
@ -0,0 +1,336 @@
|
|||||||
|
using System.Data;
|
||||||
|
using Migrator.Framework;
|
||||||
|
using ForeignKeyConstraint=Migrator.Framework.ForeignKeyConstraint;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Migrator.Providers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No Op (Null Object Pattern) implementation of the ITransformationProvider
|
||||||
|
/// </summary>
|
||||||
|
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<long> AppliedMigrations
|
||||||
|
{
|
||||||
|
get { return new List<long>(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for every transformation providers.
|
||||||
|
/// A 'tranformation' is an operation that modifies the database.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TransformationProvider : ITransformationProvider
|
||||||
|
{
|
||||||
|
private ILogger _logger;
|
||||||
|
protected IDbConnection _connection;
|
||||||
|
private IDbTransaction _transaction;
|
||||||
|
private List<long> _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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the event logger
|
||||||
|
/// </summary>
|
||||||
|
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<Column> columns = new List<Column>();
|
||||||
|
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<string> tables = new List<string>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a new table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table name</param>
|
||||||
|
/// <param name="columns">Columns</param>
|
||||||
|
/// <example>
|
||||||
|
/// Adds the Test table with two columns:
|
||||||
|
/// <code>
|
||||||
|
/// Database.AddTable("Test",
|
||||||
|
/// new Column("Id", typeof(int), ColumnProperty.PrimaryKey),
|
||||||
|
/// new Column("Title", typeof(string), 100)
|
||||||
|
/// );
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a new table
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Table name</param>
|
||||||
|
/// <param name="columns">Columns</param>
|
||||||
|
/// <param name="engine">the database storage engine to use</param>
|
||||||
|
/// <example>
|
||||||
|
/// Adds the Test table with two columns:
|
||||||
|
/// <code>
|
||||||
|
/// Database.AddTable("Test", "INNODB",
|
||||||
|
/// new Column("Id", typeof(int), ColumnProperty.PrimaryKey),
|
||||||
|
/// new Column("Title", typeof(string), 100)
|
||||||
|
/// );
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public virtual void AddTable(string name, string engine, params Column[] columns)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (TableExists(name))
|
||||||
|
{
|
||||||
|
Logger.Warn("Table {0} already exists", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> pks = GetPrimaryKeys(columns);
|
||||||
|
bool compoundPrimaryKey = pks.Count > 1;
|
||||||
|
|
||||||
|
List<ColumnPropertiesMapper> columnProviders = new List<ColumnPropertiesMapper>(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<string> GetPrimaryKeys(IEnumerable<Column> columns)
|
||||||
|
{
|
||||||
|
List<string> pks = new List<string>();
|
||||||
|
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<ColumnPropertiesMapper> columns)
|
||||||
|
{
|
||||||
|
string indexes = JoinIndexes(columns);
|
||||||
|
string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty);
|
||||||
|
return columnsAndIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string JoinIndexes(IEnumerable<ColumnPropertiesMapper> columns)
|
||||||
|
{
|
||||||
|
List<string> indexes = new List<string>();
|
||||||
|
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<ColumnPropertiesMapper> columns)
|
||||||
|
{
|
||||||
|
List<string> columnStrings = new List<string>();
|
||||||
|
foreach (ColumnPropertiesMapper column in columns)
|
||||||
|
columnStrings.Add(column.ColumnSql);
|
||||||
|
return String.Join(", ", columnStrings.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a new column to an existing table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">Table to which to add the column</param>
|
||||||
|
/// <param name="column">Column name</param>
|
||||||
|
/// <param name="type">Date type of the column</param>
|
||||||
|
/// <param name="size">Max length of the column</param>
|
||||||
|
/// <param name="property">Properties of the column, see <see cref="ColumnProperty">ColumnProperty</see>,</param>
|
||||||
|
/// <param name="defaultValue">Default value</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TransformationProvider.AddColumn(string, string, DbType, int, ColumnProperty, object)">
|
||||||
|
/// AddColumn(string, string, Type, int, ColumnProperty, object)
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AddColumn(string table, string column, DbType type)
|
||||||
|
{
|
||||||
|
AddColumn(table, column, type, 0, ColumnProperty.Null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TransformationProvider.AddColumn(string, string, DbType, int, ColumnProperty, object)">
|
||||||
|
/// AddColumn(string, string, Type, int, ColumnProperty, object)
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TransformationProvider.AddColumn(string, string, DbType, int, ColumnProperty, object)">
|
||||||
|
/// AddColumn(string, string, Type, int, ColumnProperty, object)
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property)
|
||||||
|
{
|
||||||
|
AddColumn(table, column, type, 0, property, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TransformationProvider.AddColumn(string, string, DbType, int, ColumnProperty, object)">
|
||||||
|
/// AddColumn(string, string, Type, int, ColumnProperty, object)
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property)
|
||||||
|
{
|
||||||
|
AddColumn(table, column, type, size, property, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Append a primary key to a table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Constraint name</param>
|
||||||
|
/// <param name="table">Table name</param>
|
||||||
|
/// <param name="columns">Primary column names</param>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guesses the name of the foreign key and add it
|
||||||
|
/// </summary>
|
||||||
|
public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn)
|
||||||
|
{
|
||||||
|
AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guesses the name of the foreign key and add it
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable,
|
||||||
|
string[] refColumns)
|
||||||
|
{
|
||||||
|
AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guesses the name of the foreign key and add it
|
||||||
|
/// </summary>
|
||||||
|
public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable,
|
||||||
|
string refColumn, ForeignKeyConstraint constraint)
|
||||||
|
{
|
||||||
|
AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn,
|
||||||
|
constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guesses the name of the foreign key and add it
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable,
|
||||||
|
string[] refColumns, ForeignKeyConstraint constraint)
|
||||||
|
{
|
||||||
|
AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns,
|
||||||
|
constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Append a foreign key (relation) between two tables.
|
||||||
|
/// tables.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Constraint name</param>
|
||||||
|
/// <param name="primaryTable">Table name containing the primary key</param>
|
||||||
|
/// <param name="primaryColumn">Primary key column name</param>
|
||||||
|
/// <param name="refTable">Foreign table name</param>
|
||||||
|
/// <param name="refColumn">Foreign column name</param>
|
||||||
|
public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable,
|
||||||
|
string refColumn)
|
||||||
|
{
|
||||||
|
AddForeignKey(name, primaryTable, new string[] { primaryColumn }, refTable, new string[] { refColumn });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="ITransformationProvider.AddForeignKey(string, string, string, string, string)">
|
||||||
|
/// AddForeignKey(string, string, string, string, string)
|
||||||
|
/// </see>
|
||||||
|
/// </summary>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a constraint exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Constraint name</param>
|
||||||
|
/// <param name="table">Table owning the constraint</param>
|
||||||
|
/// <returns><c>true</c> if the constraint exists.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute an SQL query returning results.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">The SQL command.</param>
|
||||||
|
/// <returns>A data iterator, <see cref="System.Data.IDataReader">IDataReader</see>.</returns>
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a transaction. Called by the migration mediator.
|
||||||
|
/// </summary>
|
||||||
|
public void BeginTransaction()
|
||||||
|
{
|
||||||
|
if (_transaction == null && _connection != null)
|
||||||
|
{
|
||||||
|
EnsureHasConnection();
|
||||||
|
_transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void EnsureHasConnection()
|
||||||
|
{
|
||||||
|
if (_connection.State != ConnectionState.Open)
|
||||||
|
{
|
||||||
|
_connection.Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rollback the current migration. Called by the migration mediator.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Rollback()
|
||||||
|
{
|
||||||
|
if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_transaction.Rollback();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_connection.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_transaction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commit the current transaction. Called by the migrations mediator.
|
||||||
|
/// </summary>
|
||||||
|
public void Commit()
|
||||||
|
{
|
||||||
|
if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_transaction.Commit();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_connection.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_transaction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of Migrations currently applied to the database.
|
||||||
|
/// </summary>
|
||||||
|
public List<long> AppliedMigrations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_appliedMigrations == null)
|
||||||
|
{
|
||||||
|
_appliedMigrations = new List<long>();
|
||||||
|
CreateSchemaInfoTable();
|
||||||
|
using(IDataReader reader = Select("version","SchemaInfo")){
|
||||||
|
while(reader.Read()){
|
||||||
|
_appliedMigrations.Add(Convert.ToInt64(reader.GetValue(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _appliedMigrations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a Migration version number as having been applied
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version number of the migration that was applied</param>
|
||||||
|
public void MigrationApplied(long version)
|
||||||
|
{
|
||||||
|
CreateSchemaInfoTable();
|
||||||
|
Insert("SchemaInfo",new string[]{"version"},new string[]{version.ToString()});
|
||||||
|
_appliedMigrations.Add(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a Migration version number as having been rolled back from the database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version number of the migration that was removed</param>
|
||||||
|
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<string, string>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace Migrator.Providers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class maps a DbType to names.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Associations may be marked with a capacity. Calling the <c>Get()</c>
|
||||||
|
/// 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
|
||||||
|
/// <code>
|
||||||
|
/// Names.Put(DbType, "TEXT" );
|
||||||
|
/// Names.Put(DbType, 255, "VARCHAR($l)" );
|
||||||
|
/// Names.Put(DbType, 65534, "LONGVARCHAR($l)" );
|
||||||
|
/// </code>
|
||||||
|
/// will give you back the following:
|
||||||
|
/// <code>
|
||||||
|
/// 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)
|
||||||
|
/// </code>
|
||||||
|
/// On the other hand, simply putting
|
||||||
|
/// <code>
|
||||||
|
/// Names.Put(DbType, "VARCHAR($l)" );
|
||||||
|
/// </code>
|
||||||
|
/// would result in
|
||||||
|
/// <code>
|
||||||
|
/// 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)"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
public class TypeNames
|
||||||
|
{
|
||||||
|
public const string LengthPlaceHolder = "$l";
|
||||||
|
public const string PrecisionPlaceHolder = "$p";
|
||||||
|
public const string ScalePlaceHolder = "$s";
|
||||||
|
|
||||||
|
private readonly Dictionary<DbType, SortedList<int, string>> weighted =
|
||||||
|
new Dictionary<DbType, SortedList<int, string>>();
|
||||||
|
|
||||||
|
private readonly Dictionary<DbType, string> defaults = new Dictionary<DbType, string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get default type name for specified type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typecode">the type key</param>
|
||||||
|
/// <returns>the default type name associated with the specified key</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the type name specified type and size
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typecode">the type key</param>
|
||||||
|
/// <param name="size">the SQL length </param>
|
||||||
|
/// <param name="scale">the SQL scale </param>
|
||||||
|
/// <param name="precision">the SQL precision </param>
|
||||||
|
/// <returns>
|
||||||
|
/// The associated name with smallest capacity >= size if available and the
|
||||||
|
/// default type name otherwise
|
||||||
|
/// </returns>
|
||||||
|
public string Get(DbType typecode, int size, int precision, int scale)
|
||||||
|
{
|
||||||
|
SortedList<int, string> map;
|
||||||
|
weighted.TryGetValue(typecode, out map);
|
||||||
|
if (map != null && map.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, string> 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set a type name for specified type key and capacity
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typecode">the type key</param>
|
||||||
|
/// <param name="capacity">the (maximum) type size/length</param>
|
||||||
|
/// <param name="value">The associated name</param>
|
||||||
|
public void Put(DbType typecode, int capacity, string value)
|
||||||
|
{
|
||||||
|
SortedList<int, string> map;
|
||||||
|
if (!weighted.TryGetValue(typecode, out map))
|
||||||
|
{
|
||||||
|
// add new ordered map
|
||||||
|
weighted[typecode] = map = new SortedList<int, string>();
|
||||||
|
}
|
||||||
|
map[capacity] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typecode"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
public void Put(DbType typecode, string value)
|
||||||
|
{
|
||||||
|
defaults[typecode] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<long> _availableMigrations;
|
||||||
|
protected List<long> _original;
|
||||||
|
protected long _current;
|
||||||
|
protected bool _dryrun;
|
||||||
|
|
||||||
|
protected BaseMigrate(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
_availableMigrations = availableMigrations;
|
||||||
|
_original = new List<long> (_provider.AppliedMigrations.ToArray()); //clone
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BaseMigrate GetInstance(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
|
||||||
|
{
|
||||||
|
return new MigrateAnywhere(availableMigrations, provider, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<long> 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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the next migration available to be applied. Only returns
|
||||||
|
/// migrations that have NOT already been applied.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The migration number of the next available Migration.</returns>
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the previous migration that has been applied. Only returns
|
||||||
|
/// migrations that HAVE already been applied.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The most recently applied Migration.</returns>
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<FileInfo> files = new List<FileInfo>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when a migration number is not unique.
|
||||||
|
/// </summary>
|
||||||
|
public class DuplicatedVersionException : Exception
|
||||||
|
{
|
||||||
|
public DuplicatedVersionException(long version)
|
||||||
|
: base(String.Format("Migration version #{0} is duplicated", version))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown in a migration <c>Down()</c> method
|
||||||
|
/// when changes can't be undone.
|
||||||
|
/// </summary>
|
||||||
|
public class IrreversibleMigrationException : Exception
|
||||||
|
{
|
||||||
|
public IrreversibleMigrationException() : base("Irreversible migration")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace Migrator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Description of MigrateAnywhere.
|
||||||
|
/// </summary>
|
||||||
|
public class MigrateAnywhere : BaseMigrate
|
||||||
|
{
|
||||||
|
private bool _goForward;
|
||||||
|
|
||||||
|
public MigrateAnywhere(List<long> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Comparer of Migration by their version attribute.
|
||||||
|
/// </summary>
|
||||||
|
public class MigrationTypeComparer : IComparer<Type>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace Migrator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles inspecting code to find all of the Migrations in assemblies and reading
|
||||||
|
/// other metadata such as the last revision, etc.
|
||||||
|
/// </summary>
|
||||||
|
public class MigrationLoader
|
||||||
|
{
|
||||||
|
private readonly ITransformationProvider _provider;
|
||||||
|
private readonly List<Type> _migrationsTypes = new List<Type>();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns registered migration <see cref="System.Type">types</see>.
|
||||||
|
/// </summary>
|
||||||
|
public List<Type> MigrationsTypes
|
||||||
|
{
|
||||||
|
get { return _migrationsTypes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the last version of the migrations.
|
||||||
|
/// </summary>
|
||||||
|
public long LastVersion
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_migrationsTypes.Count == 0)
|
||||||
|
return 0;
|
||||||
|
return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check for duplicated version in migrations.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="CheckForDuplicatedVersion">CheckForDuplicatedVersion</exception>
|
||||||
|
public void CheckForDuplicatedVersion()
|
||||||
|
{
|
||||||
|
List<long> versions = new List<long>();
|
||||||
|
foreach (Type t in _migrationsTypes)
|
||||||
|
{
|
||||||
|
long version = GetMigrationVersion(t);
|
||||||
|
|
||||||
|
if (versions.Contains(version))
|
||||||
|
throw new DuplicatedVersionException(version);
|
||||||
|
|
||||||
|
versions.Add(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collect migrations in one <c>Assembly</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="asm">The <c>Assembly</c> to browse.</param>
|
||||||
|
/// <returns>The migrations collection</returns>
|
||||||
|
public static List<Type> GetMigrationTypes(Assembly asm)
|
||||||
|
{
|
||||||
|
List<Type> migrations = new List<Type>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the version of the migration
|
||||||
|
/// <see cref="MigrationAttribute">MigrationAttribute</see>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="t">Migration type.</param>
|
||||||
|
/// <returns>Version number sepcified in the attribute</returns>
|
||||||
|
public static long GetMigrationVersion(Type t)
|
||||||
|
{
|
||||||
|
MigrationAttribute attrib = (MigrationAttribute)
|
||||||
|
Attribute.GetCustomAttribute(t, typeof(MigrationAttribute));
|
||||||
|
|
||||||
|
return attrib.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<long> GetAvailableMigrations()
|
||||||
|
{
|
||||||
|
//List<int> availableMigrations = new List<int>();
|
||||||
|
_migrationsTypes.Sort(new MigrationTypeComparer(true));
|
||||||
|
return _migrationsTypes.ConvertAll(new Converter<Type, long>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Migrations mediator.
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns registered migration <see cref="System.Type">types</see>.
|
||||||
|
/// </summary>
|
||||||
|
public List<Type> MigrationsTypes
|
||||||
|
{
|
||||||
|
get { return _migrationLoader.MigrationsTypes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run all migrations up to the latest. Make no changes to database if
|
||||||
|
/// dryrun is true.
|
||||||
|
/// </summary>
|
||||||
|
public void MigrateToLastVersion()
|
||||||
|
{
|
||||||
|
MigrateTo(_migrationLoader.LastVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current migrations applied to the database.
|
||||||
|
/// </summary>
|
||||||
|
public List<long> AppliedMigrations
|
||||||
|
{
|
||||||
|
get { return _provider.AppliedMigrations; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get or set the event logger.
|
||||||
|
/// </summary>
|
||||||
|
public ILogger Logger
|
||||||
|
{
|
||||||
|
get { return _logger; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_logger = value;
|
||||||
|
_provider.Logger = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool DryRun
|
||||||
|
{
|
||||||
|
get { return _dryrun; }
|
||||||
|
set { _dryrun = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Migrate the database to a specific version.
|
||||||
|
/// Runs all migration between the actual version and the
|
||||||
|
/// specified version.
|
||||||
|
/// If <c>version</c> is greater then the current version,
|
||||||
|
/// the <c>Up()</c> method will be invoked.
|
||||||
|
/// If <c>version</c> lower then the current version,
|
||||||
|
/// the <c>Down()</c> method of previous migration will be invoked.
|
||||||
|
/// If <c>dryrun</c> is set, don't write any changes to the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The version that must became the current one</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles loading Provider implementations
|
||||||
|
/// </summary>
|
||||||
|
public class ProviderFactory
|
||||||
|
{
|
||||||
|
private static readonly Assembly providerAssembly;
|
||||||
|
private static readonly Dictionary<String, object> dialects = new Dictionary<string, object>();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.*")]
|
Loading…
Reference in new issue