diff --git a/src/Orchard.Tests/DataMigration/DataMigrationCommandsTests.cs b/src/Orchard.Tests/DataMigration/DataMigrationCommandsTests.cs new file mode 100644 index 000000000..6d9fc665c --- /dev/null +++ b/src/Orchard.Tests/DataMigration/DataMigrationCommandsTests.cs @@ -0,0 +1,38 @@ +using System.Data; +using NUnit.Framework; +using Orchard.DataMigration.Schema; + +namespace Orchard.Tests.DataMigration { + [TestFixture] + public class DataMigrationCommandsTests { + + [Test] + public void AllMethodsShouldBeCalledSuccessfully() { + var schemaBuilder = new SchemaBuilder("TEST_"); + + schemaBuilder + .CreateTable("User", table => table + .ContentPartRecord() + .Column("Id", DbType.Int32, column => column.PrimaryKey()) + .Column("Firstname", DbType.String, column => column.Length(255)) + .Column("Lastname", DbType.String, column => column.Precision(0).Scale(1)) + .ForeignKey("User_Address", fk => fk.On("Id", "Address", "UserId"))) + .CreateTable("Address", table => table + .VersionedContentPartRecord() + .Column("City", DbType.String) + .Column("ZIP", DbType.Int32, column => column.Unique()) + .Column("UserId", DbType.Int32, column => column.NotNull())) + .AlterTable("User", table => table + .AddColumn("Age", DbType.Int32) + .AlterColumn("Lastname", column => column.Default("John")) + .AlterColumn("Lastname", column => column.Rename("John")) + .DropColumn("Lastname") + .CreateIndex("IDX_XYZ", "NickName") + .DropIndex("IDX_XYZ") + .AddForeignKey("FKL", fk => fk.On("Id", "A", "Id").On("Id", "B", "Id") ) + .DropForeignKey("FKL")) + .DropTable("Address") + .ExecuteSql("DROP DATABASE", statement => statement.ForDialect("SQLite").ForDialect("MsSqlServer2008")); + } + } +} diff --git a/src/Orchard.Tests/DataMigration/DataMigrationTests.cs b/src/Orchard.Tests/DataMigration/DataMigrationTests.cs index a12e2e58b..d44348414 100644 --- a/src/Orchard.Tests/DataMigration/DataMigrationTests.cs +++ b/src/Orchard.Tests/DataMigration/DataMigrationTests.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Linq; using Autofac; +using Moq; using NHibernate; using NUnit.Framework; using Orchard.ContentManagement.Records; using Orchard.Data; +using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Loaders; @@ -42,6 +44,9 @@ namespace Orchard.Tests.DataMigration { var builder = new ContainerBuilder(); _folders = new StubFolders(); + + builder.RegisterInstance(new ShellSettings { DataTablePrefix = "TEST_"}); + builder.RegisterInstance(_folders).As(); builder.RegisterType().As(); builder.RegisterType().As(); @@ -149,6 +154,17 @@ namespace Orchard.Tests.DataMigration { } } + public class DataMigrationWithSchemaBuilder : DataMigrationImpl { + public override string Feature { + get { return "Feature1"; } + } + + public int Create() { + Assert.That(SchemaBuilder, Is.Not.Null); + Assert.That(SchemaBuilder.TablePrefix, Is.EqualTo("TEST_")); + return 1; + } + } [Test] public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() { Init(new Type[] {typeof (DataMigrationEmpty)}); @@ -162,7 +178,7 @@ features: Description: Feature "); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(0)); } @@ -179,7 +195,7 @@ features: Description: Feature "); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(0)); } @@ -196,7 +212,7 @@ features: Description: Feature "); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(1)); Assert.That(_repository.Table.First().Current, Is.EqualTo(999)); Assert.That(_repository.Table.First().DataMigrationClass, Is.EqualTo("Orchard.Tests.DataMigration.DataMigrationTests+DataMigration11Create")); @@ -215,7 +231,7 @@ features: Description: Feature "); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(1)); Assert.That(_repository.Table.First().Current, Is.EqualTo(666)); } @@ -237,7 +253,7 @@ features: DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve" }); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(1)); Assert.That(_repository.Table.First().Current, Is.EqualTo(999)); } @@ -265,12 +281,28 @@ features: Feature2: Description: Feature "); - _dataMigrationManager.Upgrade("Feature1"); + _dataMigrationManager.Update("Feature1"); Assert.That(_repository.Table.Count(), Is.EqualTo(2)); Assert.That(_repository.Fetch(d => d.Current == 999).Count(), Is.EqualTo(2)); Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule1").Count(), Is.EqualTo(1)); Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule2").Count(), Is.EqualTo(1)); } + [Test] + public void DataMigrationImplShouldGetASchemaBuilder() { + Init(new Type[] { typeof(DataMigrationWithSchemaBuilder) }); + + _folders.Manifests.Add("Module1", @" +name: Module1 +version: 0.1 +orchardversion: 1 +features: + Feature1: + Description: Feature +"); + + _dataMigrationManager.Update("Feature1"); + Assert.That(_repository.Table.Count(), Is.EqualTo(1)); + } } } \ No newline at end of file diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index b6393e39a..89ab0f5a7 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -180,6 +180,7 @@ Code + diff --git a/src/Orchard/DataMigration/Commands/DataMigrationCommands.cs b/src/Orchard/DataMigration/Commands/DataMigrationCommands.cs index 4faca9604..2beb4a9d9 100644 --- a/src/Orchard/DataMigration/Commands/DataMigrationCommands.cs +++ b/src/Orchard/DataMigration/Commands/DataMigrationCommands.cs @@ -18,7 +18,7 @@ namespace Orchard.DataMigration.Commands { [OrchardSwitches("Feature")] public string UpgradeDatabase() { try { - _dataMigrationManager.Upgrade(Feature); + _dataMigrationManager.Update(Feature); } catch ( Exception ex ) { Context.Output.WriteLine(T("An error occured while upgrading the database: " + ex.Message)); diff --git a/src/Orchard/DataMigration/DataMigration.cs b/src/Orchard/DataMigration/DataMigration.cs index 469ec6556..8ae3769a7 100644 --- a/src/Orchard/DataMigration/DataMigration.cs +++ b/src/Orchard/DataMigration/DataMigration.cs @@ -1,5 +1,11 @@ -namespace Orchard.DataMigration { - public abstract class DataMigration : IDataMigration { +using Orchard.DataMigration.Schema; + +namespace Orchard.DataMigration { + /// + /// Data Migration classes can inherit from this class to get a SchemaBuilder instance configured with the current tenant database prefix + /// + public abstract class DataMigrationImpl : IDataMigration { public abstract string Feature { get; } + public SchemaBuilder SchemaBuilder { get; set; } } } diff --git a/src/Orchard/DataMigration/DataMigrationCoordinator.cs b/src/Orchard/DataMigration/DataMigrationCoordinator.cs new file mode 100644 index 000000000..f34954491 --- /dev/null +++ b/src/Orchard/DataMigration/DataMigrationCoordinator.cs @@ -0,0 +1,40 @@ +using Orchard.Environment; +using Orchard.Environment.Extensions.Models; + +namespace Orchard.DataMigration { + /// + /// Responsible for executing data migration tasks when a feature is enabled for the first time + /// 1) Initial install of a module: + /// Enable a feature for the first time => run data migration up to the latest version + /// Enable a feature on 2nd time => no data migration run + /// Disable a feature => no data migration + /// 2) Installing a newer version of a module + /// Don't do any data migration by default + /// 2 cases: + /// 1) feature wasn't not enabled when new code was installed + /// 2) feature was enabled when new code was installed + /// + public class DataMigrationCoordinator : IFeatureEventHandler { + private readonly IDataMigrationManager _dataMigrationManager; + + public DataMigrationCoordinator(IDataMigrationManager dataMigrationManager) { + _dataMigrationManager = dataMigrationManager; + } + + public void Install(Feature feature) { + var featureName = feature.Descriptor.Name; + if ( !_dataMigrationManager.IsFeatureAlreadyInstalled(featureName) ) { + _dataMigrationManager.Update(featureName); + } + } + + public void Enable(Feature feature) { + } + + public void Disable(Feature feature) { + } + + public void Uninstall(Feature feature) { + } + } +} diff --git a/src/Orchard/DataMigration/DataMigrationManager.cs b/src/Orchard/DataMigration/DataMigrationManager.cs index 035c543de..05c877a30 100644 --- a/src/Orchard/DataMigration/DataMigrationManager.cs +++ b/src/Orchard/DataMigration/DataMigrationManager.cs @@ -4,8 +4,10 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using Orchard.Data; +using Orchard.DataMigration.Schema; +using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; -using Orchard.Environment.Extensions.Models; +using Orchard.Environment.State; using Orchard.Logging; namespace Orchard.DataMigration { @@ -17,34 +19,46 @@ namespace Orchard.DataMigration { private readonly IRepository _dataMigrationRepository; private readonly IDataMigrationGenerator _dataMigrationGenerator; private readonly IExtensionManager _extensionManager; + private readonly ShellSettings _shellSettings; public DataMigrationManager( IEnumerable dataMigrations, IRepository dataMigrationRepository, IDataMigrationGenerator dataMigrationGenerator, - IExtensionManager extensionManager) { + IExtensionManager extensionManager, + ShellSettings shellSettings) { _dataMigrations = dataMigrations; _dataMigrationRepository = dataMigrationRepository; _dataMigrationGenerator = dataMigrationGenerator; _extensionManager = extensionManager; + _shellSettings = shellSettings; Logger = NullLogger.Instance; } public ILogger Logger { get; set; } - public void Upgrade(string feature) { + public IEnumerable GetFeaturesThatNeedUpdate() { + throw new NotImplementedException(); + } + public void Update(IEnumerable features) { + foreach(var feature in features) { + Update(feature); + } + } + + public void Update(string feature){ + // proceed with dependent features first, whatever the module it's in - var dependencies = _extensionManager - .AvailableExtensions() - .SelectMany(e => e.Features) + var dependencies = ShellStateCoordinator.OrderByDependencies(_extensionManager.AvailableExtensions() + .SelectMany(ext => ext.Features)) .Where(f => String.Equals(f.Name, feature, StringComparison.OrdinalIgnoreCase)) .Where(f => f.Dependencies != null) .SelectMany( f => f.Dependencies ) .ToList(); foreach(var dependency in dependencies) { - Upgrade(dependency); + Update(dependency); } var migrations = GetDataMigrations(feature); @@ -55,9 +69,7 @@ namespace Orchard.DataMigration { var tempMigration = migration; // get current version for this migration - var dataMigrationRecord = _dataMigrationRepository.Table - .Where(dm => dm.DataMigrationClass == tempMigration.GetType().FullName) - .FirstOrDefault(); + var dataMigrationRecord = GetDataMigrationRecord(tempMigration); var updateMethodNameRegex = new Regex(@"^UpdateFrom(?\d+)$", RegexOptions.Compiled); var current = 0; @@ -81,6 +93,7 @@ namespace Orchard.DataMigration { // update methods might also be called after Create() var lookupTable = new Dictionary(); + // construct a lookup table with all managed initial versions foreach(var methodInfo in migration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var match = updateMethodNameRegex.Match(methodInfo.Name); @@ -96,29 +109,50 @@ namespace Orchard.DataMigration { } catch (Exception ex) { Logger.Error(ex, "An unexpected error orccured while applying migration on {0} from version {1}", feature, current); + throw; } } // if current is 0, it means no upgrade/create method was found or succeeded - if ( current != 0 ) { - if (dataMigrationRecord == null) { - _dataMigrationRepository.Create(new DataMigrationRecord {Current = current, DataMigrationClass = migration.GetType().FullName}); - } - else { - dataMigrationRecord.Current = current; - _dataMigrationRepository.Update(dataMigrationRecord); - } + if (current == 0) { + continue; + } + if (dataMigrationRecord == null) { + _dataMigrationRepository.Create(new DataMigrationRecord {Current = current, DataMigrationClass = migration.GetType().FullName}); + } + else { + dataMigrationRecord.Current = current; + _dataMigrationRepository.Update(dataMigrationRecord); } } } + private DataMigrationRecord GetDataMigrationRecord(IDataMigration tempMigration) { + return _dataMigrationRepository.Table + .Where(dm => dm.DataMigrationClass == tempMigration.GetType().FullName) + .FirstOrDefault(); + } + /// - /// Returns all the available IDataMigration instances for a specific module + /// Returns all the available IDataMigration instances for a specific module, and inject necessary builders /// - public IEnumerable GetDataMigrations(string feature) { - return _dataMigrations + private IEnumerable GetDataMigrations(string feature) { + var migrations = _dataMigrations .Where(dm => String.Equals(dm.Feature, feature, StringComparison.OrdinalIgnoreCase)) .ToList(); + + foreach (var migration in migrations.OfType()) { + migration.SchemaBuilder = new SchemaBuilder(_shellSettings.DataTablePrefix); + } + + return migrations; + } + + /// + /// Whether a feature has already been installed, i.e. one of its Data Migration class has already been processed + /// + public bool IsFeatureAlreadyInstalled(string feature) { + return GetDataMigrations(feature).Any(dataMigration => GetDataMigrationRecord(dataMigration) != null); } } } diff --git a/src/Orchard/DataMigration/IDataMigrationManager.cs b/src/Orchard/DataMigration/IDataMigrationManager.cs index bf7032f67..7f887e728 100644 --- a/src/Orchard/DataMigration/IDataMigrationManager.cs +++ b/src/Orchard/DataMigration/IDataMigrationManager.cs @@ -1,5 +1,25 @@ +using System.Collections.Generic; + namespace Orchard.DataMigration { public interface IDataMigrationManager : IDependency { - void Upgrade(string feature); + /// + /// Whether a feature has already been installed, i.e. one of its Data Migration class has already been processed + /// + bool IsFeatureAlreadyInstalled(string feature); + + /// + /// Returns the features which have at least one Data Migration class with a corresponding Upgrade method to be called + /// + IEnumerable GetFeaturesThatNeedUpdate(); + + /// + /// Updates the database to the latest version for the specified feature + /// + void Update(string feature); + + /// + /// Updates the database to the latest version for the specified features + /// + void Update(IEnumerable features); } } \ No newline at end of file diff --git a/src/Orchard/DataMigration/Schema/AlterColumnCommand.cs b/src/Orchard/DataMigration/Schema/AlterColumnCommand.cs new file mode 100644 index 000000000..c3d88884a --- /dev/null +++ b/src/Orchard/DataMigration/Schema/AlterColumnCommand.cs @@ -0,0 +1,15 @@ +namespace Orchard.DataMigration.Schema { + public class AlterColumnCommand : ColumnCommand { + private string _newName; + + public AlterColumnCommand(string name) + : base(name) { + } + + + public AlterColumnCommand Rename(string name) { + _newName = name; + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/AlterTableCommand.cs b/src/Orchard/DataMigration/Schema/AlterTableCommand.cs new file mode 100644 index 000000000..2fee79722 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/AlterTableCommand.cs @@ -0,0 +1,64 @@ +using System; +using System.Data; + +namespace Orchard.DataMigration.Schema { + public class AlterTableCommand : SchemaCommand { + public AlterTableCommand(string name) + : base(name) { + } + + public AlterTableCommand AddColumn(string name, DbType dbType, Action column = null) { + var command = new CreateColumnCommand(name); + command.Type(dbType); + + if(column != null) { + column(command); + } + + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand DropColumn(string name) { + var command = new DropColumnCommand(name); + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand AlterColumn(string name, Action column = null) { + var command = new AlterColumnCommand(name); + + if ( column != null ) { + column(command); + } + + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand CreateIndex(string name, params string[] columnNames) { + var command = new CreateIndexCommand(name, columnNames); + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand DropIndex(string name) { + var command = new DropIndexCommand(name); + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand AddForeignKey(string name, Action fk) { + var command = new CreateForeignKeyCommand(name); + fk(command); + _tableCommands.Add(command); + return this; + } + + public AlterTableCommand DropForeignKey(string name) { + var command = new DropForeignKeyCommand(name); + _tableCommands.Add(command); + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/ColumnCommand.cs b/src/Orchard/DataMigration/Schema/ColumnCommand.cs new file mode 100644 index 000000000..46e9f32a2 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/ColumnCommand.cs @@ -0,0 +1,23 @@ +using System.Data; + +namespace Orchard.DataMigration.Schema { + public class ColumnCommand : TableCommand { + private DbType _dbType; + private object _default; + public ColumnCommand(string name) : base(name) { + _dbType = DbType.Object; + _default = null; + } + + public ColumnCommand Type(DbType dbType) { + _dbType = dbType; + return this; + } + + public ColumnCommand Default(object @default) { + _default = @default; + return this; + } + + } +} diff --git a/src/Orchard/DataMigration/Schema/CreateColumnCommand.cs b/src/Orchard/DataMigration/Schema/CreateColumnCommand.cs new file mode 100644 index 000000000..86bc1aef6 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/CreateColumnCommand.cs @@ -0,0 +1,60 @@ +namespace Orchard.DataMigration.Schema { + public class CreateColumnCommand : ColumnCommand { + private bool _primaryKey; + private byte? _precision; + private byte? _scale; + private int? _length; + private bool _notNull; + private bool _unique; + + + public CreateColumnCommand(string name) : base(name) { + _precision = null; + _scale = null; + _length = null; + _notNull = false; + _unique = false; + + } + + public CreateColumnCommand PrimaryKey() { + _primaryKey = true; + return this; + } + + public CreateColumnCommand Precision(byte? precision) { + _precision = precision; + return this; + } + + public CreateColumnCommand Scale(byte? scale) { + _scale = scale; + return this; + } + + public CreateColumnCommand Length(int? length) { + _length = length; + return this; + } + + public CreateColumnCommand NotNull() { + _notNull = true; + return this; + } + + public CreateColumnCommand Nullable() { + _notNull = false; + return this; + } + + public CreateColumnCommand Unique() { + _unique = true; + return this; + } + + public CreateColumnCommand NotUnique() { + _unique = false; + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/CreateForeignKeyCommand.cs b/src/Orchard/DataMigration/Schema/CreateForeignKeyCommand.cs new file mode 100644 index 000000000..0fe485ee5 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/CreateForeignKeyCommand.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace Orchard.DataMigration.Schema { + public class CreateForeignKeyCommand : TableCommand { + protected readonly List _foreignKeyClauses; + + public CreateForeignKeyCommand(string name) + : base(name) { + _foreignKeyClauses = new List(); + } + + public CreateForeignKeyCommand On(string srcColumn, string destTable, string destColumn) { + _foreignKeyClauses.Add(new ForeignKeyClause(srcColumn, destTable, destColumn)); + return this; + } + } + + public class ForeignKeyClause { + public ForeignKeyClause(string srcColumn, string destTable, string destColumn) { + SrcColumn = srcColumn; + DestTable = destTable; + DestColumn = destColumn; + } + + public string DestColumn { get; private set; } + + public string DestTable { get; private set; } + + public string SrcColumn { get; private set; } + } +} diff --git a/src/Orchard/DataMigration/Schema/CreateIndexCommand.cs b/src/Orchard/DataMigration/Schema/CreateIndexCommand.cs new file mode 100644 index 000000000..3460c8364 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/CreateIndexCommand.cs @@ -0,0 +1,10 @@ +namespace Orchard.DataMigration.Schema { + public class CreateIndexCommand : TableCommand { + public CreateIndexCommand(string name, params string[] columnNames) + : base(name) { + ColumnNames = columnNames; + } + + public string[] ColumnNames { get; private set; } + } +} diff --git a/src/Orchard/DataMigration/Schema/CreateTableCommand.cs b/src/Orchard/DataMigration/Schema/CreateTableCommand.cs new file mode 100644 index 000000000..f49342afa --- /dev/null +++ b/src/Orchard/DataMigration/Schema/CreateTableCommand.cs @@ -0,0 +1,38 @@ +using System; +using System.Data; + +namespace Orchard.DataMigration.Schema { + public class CreateTableCommand : SchemaCommand { + public CreateTableCommand(string name) + : base(name) { + } + + public CreateTableCommand Column(string name, DbType dbType, Action column = null) { + var command = new CreateColumnCommand(name); + command.Type(dbType); + + if ( column != null ) { + column(command); + } + _tableCommands.Add(command); + return this; + } + + public CreateTableCommand ContentPartRecord() { + /// TODO: Call Column() with necessary information for content part records + return this; + } + + public CreateTableCommand VersionedContentPartRecord() { + /// TODO: Call Column() with necessary information for content part records + return this; + } + + public CreateTableCommand ForeignKey(string name, Action fk) { + var command = new CreateForeignKeyCommand(name); + fk(command); + _tableCommands.Add(command); + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/DropColumnCommand.cs b/src/Orchard/DataMigration/Schema/DropColumnCommand.cs new file mode 100644 index 000000000..03e32b942 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/DropColumnCommand.cs @@ -0,0 +1,8 @@ +namespace Orchard.DataMigration.Schema { + public class DropColumnCommand : ColumnCommand { + public DropColumnCommand(string name) + : base(name) { + + } + } +} diff --git a/src/Orchard/DataMigration/Schema/DropForeignKeyCommand.cs b/src/Orchard/DataMigration/Schema/DropForeignKeyCommand.cs new file mode 100644 index 000000000..ceb1fe530 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/DropForeignKeyCommand.cs @@ -0,0 +1,8 @@ +namespace Orchard.DataMigration.Schema { + public class DropForeignKeyCommand : TableCommand { + + public DropForeignKeyCommand(string name) + : base(name) { + } + } +} diff --git a/src/Orchard/DataMigration/Schema/DropIndexCommand.cs b/src/Orchard/DataMigration/Schema/DropIndexCommand.cs new file mode 100644 index 000000000..ba48e5269 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/DropIndexCommand.cs @@ -0,0 +1,8 @@ +namespace Orchard.DataMigration.Schema { + public class DropIndexCommand : TableCommand { + + public DropIndexCommand(string name) + : base(name) { + } + } +} diff --git a/src/Orchard/DataMigration/Schema/DropTableCommand.cs b/src/Orchard/DataMigration/Schema/DropTableCommand.cs new file mode 100644 index 000000000..38d21ecbd --- /dev/null +++ b/src/Orchard/DataMigration/Schema/DropTableCommand.cs @@ -0,0 +1,7 @@ +namespace Orchard.DataMigration.Schema { + public class DropTableCommand : SchemaCommand { + public DropTableCommand(string name) + : base(name) { + } + } +} diff --git a/src/Orchard/DataMigration/Schema/SchemaBuilder.cs b/src/Orchard/DataMigration/Schema/SchemaBuilder.cs new file mode 100644 index 000000000..2cd33ba34 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/SchemaBuilder.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace Orchard.DataMigration.Schema { + public class SchemaBuilder { + + private readonly List _schemaCommands; + + public SchemaBuilder() { + _schemaCommands = new List(); + } + + public SchemaBuilder(string tablePrefix) : this() { + TablePrefix = tablePrefix; + } + + public string TablePrefix { get; private set; } + + public SchemaBuilder CreateTable(string name, Action table) { + var createTable = new CreateTableCommand(name); + table(createTable); + _schemaCommands.Add(createTable); + return this; + } + + public SchemaBuilder AlterTable(string name, Action table) { + var alterTable = new AlterTableCommand(name); + table(alterTable); + _schemaCommands.Add(alterTable); + return this; + } + + public SchemaBuilder DropTable(string name) { + var deleteTable = new DropTableCommand(name); + _schemaCommands.Add(deleteTable); + return this; + } + + public SchemaBuilder ExecuteSql(string sql, Action statement) { + var sqlStatmentCommand = new SqlStatementCommand(sql); + statement(sqlStatmentCommand); + return this; + } + + } +} diff --git a/src/Orchard/DataMigration/Schema/SchemaCommand.cs b/src/Orchard/DataMigration/Schema/SchemaCommand.cs new file mode 100644 index 000000000..3f4392ad0 --- /dev/null +++ b/src/Orchard/DataMigration/Schema/SchemaCommand.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Orchard.DataMigration.Schema { + public class SchemaCommand { + protected readonly List _tableCommands; + + public SchemaCommand(string tableName) { + _tableCommands = new List(); + Name(tableName); + } + + public string TableName { get; private set; } + + public SchemaCommand Name(string name) { + TableName = name; + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/SqlStatementCommand.cs b/src/Orchard/DataMigration/Schema/SqlStatementCommand.cs new file mode 100644 index 000000000..86721f76f --- /dev/null +++ b/src/Orchard/DataMigration/Schema/SqlStatementCommand.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Orchard.DataMigration.Schema { + public class SqlStatementCommand : SchemaCommand { + protected readonly List _dialects; + public SqlStatementCommand(string sql) + : base("") { + Sql = sql; + _dialects = new List(); + } + + public string Sql { get; private set; } + + public SqlStatementCommand ForDialect(string dialect) { + _dialects.Add(dialect); + return this; + } + } +} diff --git a/src/Orchard/DataMigration/Schema/TableCommand.cs b/src/Orchard/DataMigration/Schema/TableCommand.cs new file mode 100644 index 000000000..5e5bb458e --- /dev/null +++ b/src/Orchard/DataMigration/Schema/TableCommand.cs @@ -0,0 +1,10 @@ +namespace Orchard.DataMigration.Schema { + public class TableCommand { + private string _name; + + public TableCommand(string name) { + _name = name; + } + + } +} diff --git a/src/Orchard/Environment/State/ShellStateCoordinator.cs b/src/Orchard/Environment/State/ShellStateCoordinator.cs index 637ae8a0d..004ce0cc4 100644 --- a/src/Orchard/Environment/State/ShellStateCoordinator.cs +++ b/src/Orchard/Environment/State/ShellStateCoordinator.cs @@ -195,7 +195,7 @@ namespace Orchard.Environment.State { } } - private static IEnumerable OrderByDependencies(IEnumerable descriptors) { + public static IEnumerable OrderByDependencies(IEnumerable descriptors) { var population = descriptors.Select(d => new Linkage { Feature = d }).ToArray(); diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 61ae62328..01159b3b6 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -349,7 +349,19 @@ Code + + + + + + + + + + + + @@ -358,6 +370,10 @@ + + + +