From 158adb156a8191341c88961a78f822494bdba57a Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 19 Jul 2010 17:46:35 -0700 Subject: [PATCH] Enhanced data migration scaffolding tool not to required the feature to be enabled --HG-- branch : dev --- .../DataMigration/SchemaBuilderTests.cs | 11 +- .../SchemaCommandGeneratorTests.cs | 150 ++++++++++++++---- .../Commands/ScaffoldingCommands.cs | 1 + .../Orchard.Setup/Services/SetupService.cs | 4 +- .../Generator/SchemaCommandGenerator.cs | 49 +++++- .../Extensions/ExtensionManager.cs | 2 +- 6 files changed, 174 insertions(+), 43 deletions(-) diff --git a/src/Orchard.Tests/DataMigration/SchemaBuilderTests.cs b/src/Orchard.Tests/DataMigration/SchemaBuilderTests.cs index c45551600..a14d63f3b 100644 --- a/src/Orchard.Tests/DataMigration/SchemaBuilderTests.cs +++ b/src/Orchard.Tests/DataMigration/SchemaBuilderTests.cs @@ -102,8 +102,17 @@ namespace Orchard.Tests.DataMigration { ); } - [Test, Ignore("Fix pending")] + [Test] public void DropTableCommandShouldBeHandled() { + _schemaBuilder + .CreateTable("User", table => table + .Column("Id", DbType.Int32, column => column.PrimaryKey().Identity()) + .Column("Firstname", DbType.String, column => column.WithLength(255)) + .Column("Lastname", DbType.String, column => column.WithLength(100).NotNull()) + .Column("SN", DbType.AnsiString, column => column.WithLength(40).Unique()) + .Column("Salary", DbType.Decimal, column => column.WithPrecision(9).WithScale(2)) + .Column("Gender", DbType.Decimal, column => column.WithDefault("''")) + ); _schemaBuilder .DropTable("User"); diff --git a/src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs b/src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs index 2f833590c..effe65baf 100644 --- a/src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs +++ b/src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs @@ -4,10 +4,13 @@ using System.ComponentModel.DataAnnotations; using System.Data; using System.IO; using System.Linq; +using System.Reflection; +using System.Web; using Autofac; using Autofac.Features.Metadata; using NHibernate; using NUnit.Framework; +using Orchard.Caching; using Orchard.ContentManagement.Records; using Orchard.Data; using Orchard.Data.Conventions; @@ -20,16 +23,20 @@ using Orchard.DevTools.Services; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Folders; +using Orchard.Environment.Extensions.Loaders; using Orchard.Environment.Extensions.Models; +using Orchard.Environment.ShellBuilders; using Orchard.Environment.ShellBuilders.Models; using Orchard.FileSystems.AppData; +using Orchard.FileSystems.Dependencies; using Orchard.Tests.ContentManagement; using Orchard.Data.Providers; +using Orchard.Tests.DataMigration.Orchard.Tests.DataMigration.Records; using Orchard.Tests.FileSystems.AppData; namespace Orchard.Tests.DataMigration { [TestFixture] - public class SchemaCommandGeneratorTests { + public class SchemaCommandGeneratorTests { private IContainer _container; private StubFolders _folders; private ISchemaCommandGenerator _generator; @@ -49,7 +56,7 @@ namespace Orchard.Tests.DataMigration { var databaseFileName = System.IO.Path.GetTempFileName(); _sessionFactory = DataUtility.CreateSessionFactory( - databaseFileName, types ); + databaseFileName, types); var builder = new ContainerBuilder(); _folders = new StubFolders(); @@ -60,25 +67,28 @@ namespace Orchard.Tests.DataMigration { new Dictionary {{"ProviderName", "SqlCe"}}) }); - builder.RegisterInstance(new ShellSettings { Name = "Default", DataTablePrefix = "TEST_", DataProvider = "SqlCe"}); + builder.RegisterInstance(new ShellSettings { Name = "Default", DataTablePrefix = "TEST", DataProvider = "SqlCe" }); builder.RegisterInstance(AppDataFolderTests.CreateAppDataFolder(Path.GetDirectoryName(databaseFileName))).As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterInstance(manager).As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterInstance(_folders).As(); + builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)); _session = _sessionFactory.OpenSession(); builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As(); - builder.RegisterInstance(new ShellBlueprint() { Records = types.Select(t => new RecordBlueprint { Feature = new Feature() { Descriptor = new FeatureDescriptor() { Name = "Feature1" } }, TableName = "TEST_" + t.Name, Type = t })}); + builder.RegisterInstance(new ShellBlueprint()); _container = builder.Build(); _generator = _container.Resolve(); - _folders.Manifests.Add("Module1", @" + _folders.Manifests.Add("Feature1", @" name: Module1 version: 0.1 orchardversion: 1 @@ -96,7 +106,7 @@ features: public IDictionary Manifests { get; set; } public IEnumerable AvailableExtensions() { - foreach (var e in Manifests) { + foreach ( var e in Manifests ) { string name = e.Key; var parseResult = ExtensionFolders.ParseManifest(Manifests[name]); yield return ExtensionFolders.GetDescriptorForExtension("~/", name, "Module", parseResult); @@ -104,27 +114,96 @@ features: } } + public class StubLoaders : IExtensionLoader { + #region Implementation of IExtensionLoader + + public int Order { + get { return 1; } + } + + public string Name { + get { return this.GetType().Name; } + } + + public Assembly LoadReference(DependencyReferenceDescriptor reference) { + throw new NotImplementedException(); + } + + public void ReferenceActivated(ExtensionLoadingContext context, ExtensionReferenceProbeEntry referenceEntry) { + throw new NotImplementedException(); + } + + public void ReferenceDeactivated(ExtensionLoadingContext context, ExtensionReferenceProbeEntry referenceEntry) { + throw new NotImplementedException(); + } + + public bool IsCompatibleWithModuleReferences(ExtensionDescriptor extension, IEnumerable references) { + throw new NotImplementedException(); + } + + public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { + return new ExtensionProbeEntry { Descriptor = descriptor, Loader = this }; + } + + public IEnumerable ProbeReferences(ExtensionDescriptor extensionDescriptor) { + throw new NotImplementedException(); + } + + public ExtensionEntry Load(ExtensionDescriptor descriptor) { + return new ExtensionEntry { Descriptor = descriptor, ExportedTypes = new[] { typeof(BlogRecord), typeof(BodyRecord), typeof(BlogArchiveRecord) } }; + } + + public void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { + throw new NotImplementedException(); + } + + public void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { + throw new NotImplementedException(); + } + + public void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) { + throw new NotImplementedException(); + } + + public void Monitor(ExtensionDescriptor extension, Action monitor) { + throw new NotImplementedException(); + } + + public string GetWebFormAssemblyDirective(DependencyDescriptor dependency) { + throw new NotImplementedException(); + } + + public IEnumerable GetWebFormVirtualDependencies(DependencyDescriptor dependency) { + throw new NotImplementedException(); + } + + public IEnumerable GetFileDependencies(DependencyDescriptor dependency, string virtualPath) { + throw new NotImplementedException(); + } + + #endregion + } [Test] public void ShouldCreateCreateTableCommands() { var commands = _generator.GetCreateFeatureCommands("Feature1", false).ToList(); Assert.That(commands, Is.Not.Null); - Assert.That(commands.Count(), Is.EqualTo(6)); + Assert.That(commands.Count(), Is.EqualTo(3)); - var blogRecord = commands.Where(c => c.Name == "TEST_BlogRecord").First(); + var blogRecord = commands.Where(c => c.Name == "TEST_Feature1_BlogRecord").First(); Assert.That(blogRecord.TableCommands.OfType().Any(c => c.ColumnName == "Id" && !c.IsIdentity && c.IsPrimaryKey && c.DbType == DbType.Int32)); Assert.That(blogRecord.TableCommands.OfType().Any(c => c.ColumnName == "Description" && c.DbType == DbType.String)); Assert.That(blogRecord.TableCommands.OfType().Any(c => c.ColumnName == "PostCount" && c.DbType == DbType.Int32)); - var blogArchiveRecord = commands.Where(c => c.Name == "TEST_BlogArchiveRecord").First(); + var blogArchiveRecord = commands.Where(c => c.Name == "TEST_Feature1_BlogArchiveRecord").First(); Assert.That(blogArchiveRecord.TableCommands.OfType().Any(c => c.ColumnName == "Id" && c.IsPrimaryKey && c.DbType == DbType.Int32)); Assert.That(blogArchiveRecord.TableCommands.OfType().Any(c => c.ColumnName == "Year" && c.DbType == DbType.Int32)); Assert.That(blogArchiveRecord.TableCommands.OfType().Any(c => c.ColumnName == "Month" && c.DbType == DbType.Int32)); Assert.That(blogArchiveRecord.TableCommands.OfType().Any(c => c.ColumnName == "PostCount" && c.DbType == DbType.Int32)); Assert.That(blogArchiveRecord.TableCommands.OfType().Any(c => c.ColumnName == "Blog_id" && c.DbType == DbType.Int32)); - var bodyRecord = commands.Where(c => c.Name == "TEST_BodyRecord").First(); + var bodyRecord = commands.Where(c => c.Name == "TEST_Feature1_BodyRecord").First(); Assert.That(bodyRecord.TableCommands.OfType().Any(c => c.ColumnName == "Id" && c.IsPrimaryKey && c.DbType == DbType.Int32)); Assert.That(bodyRecord.TableCommands.OfType().Any(c => c.ColumnName == "Text" && c.DbType == DbType.String && c.Length == 10000)); Assert.That(bodyRecord.TableCommands.OfType().Any(c => c.ColumnName == "Format" && c.DbType == DbType.String && c.Length == 42)); @@ -136,25 +215,25 @@ features: var commands = _generator.GetCreateFeatureCommands("Feature1", false).ToList(); Assert.That(commands, Is.Not.Null); - Assert.That(commands.Count(), Is.EqualTo(6)); + Assert.That(commands.Count(), Is.EqualTo(3)); var sw = new StringWriter(); var interpreter = new ScaffoldingCommandInterpreter(sw); - var blogRecord = commands.Where(c => c.Name == "TEST_BlogRecord").First(); - var blogArchiveRecord = commands.Where(c => c.Name == "TEST_BlogArchiveRecord").First(); - var bodyRecord = commands.Where(c => c.Name == "TEST_BodyRecord").First(); + var blogRecord = commands.Where(c => c.Name == "TEST_Feature1_BlogRecord").First(); + var blogArchiveRecord = commands.Where(c => c.Name == "TEST_Feature1_BlogArchiveRecord").First(); + var bodyRecord = commands.Where(c => c.Name == "TEST_Feature1_BodyRecord").First(); sw.GetStringBuilder().Clear(); interpreter.Visit(blogRecord); - Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BlogRecord")); + Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_Feature1_BlogRecord")); Assert.That(sw.ToString().Contains(".ContentPartRecord()")); Assert.That(sw.ToString().Contains(".Column(\"Description\", DbType.String)")); Assert.That(sw.ToString().Contains(".Column(\"PostCount\", DbType.Int32)")); sw.GetStringBuilder().Clear(); interpreter.Visit(blogArchiveRecord); - Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BlogArchiveRecord")); + Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_Feature1_BlogArchiveRecord")); Assert.That(sw.ToString().Contains(".Column(\"Id\", DbType.Int32, column => column.PrimaryKey().Identity())")); Assert.That(sw.ToString().Contains(".Column(\"Year\", DbType.Int32)")); Assert.That(sw.ToString().Contains(".Column(\"Month\", DbType.Int32)")); @@ -163,7 +242,7 @@ features: sw.GetStringBuilder().Clear(); interpreter.Visit(bodyRecord); - Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BodyRecord")); + Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_Feature1_BodyRecord")); Assert.That(sw.ToString().Contains(".ContentPartVersionRecord()")); Assert.That(sw.ToString().Contains(".Column(\"Text\", DbType.String, column => column.Unlimited())")); Assert.That(sw.ToString().Contains(".Column(\"Format\", DbType.String, column => column.WithLength(42))")); @@ -172,23 +251,26 @@ features: } - public class BlogRecord : ContentPartRecord { - public virtual string Description { get; set; } - public virtual int PostCount { get; set; } - } + // namespace is needed as the shell composition strategy will filter records using it also + namespace Orchard.Tests.DataMigration.Records { + public class BlogRecord : ContentPartRecord { + public virtual string Description { get; set; } + public virtual int PostCount { get; set; } + } - public class BodyRecord : ContentPartVersionRecord { - [StringLengthMax] - public virtual string Text { get; set; } - [StringLength(42)] - public virtual string Format { get; set; } - } + public class BodyRecord : ContentPartVersionRecord { + [StringLengthMax] + public virtual string Text { get; set; } + [StringLength(42)] + public virtual string Format { get; set; } + } - public class BlogArchiveRecord { - public virtual int Id { get; set; } - public virtual BlogRecord Blog { get; set; } - public virtual int Year { get; set; } - public virtual int Month { get; set; } - public virtual int PostCount { get; set; } + public class BlogArchiveRecord { + public virtual int Id { get; set; } + public virtual BlogRecord Blog { get; set; } + public virtual int Year { get; set; } + public virtual int Month { get; set; } + public virtual int PostCount { get; set; } + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Commands/ScaffoldingCommands.cs b/src/Orchard.Web/Modules/Orchard.DevTools/Commands/ScaffoldingCommands.cs index ede0ec79b..dcaa4665a 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Commands/ScaffoldingCommands.cs +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Commands/ScaffoldingCommands.cs @@ -6,6 +6,7 @@ using Orchard.Commands; using Orchard.Data.Migration.Generator; using Orchard.DevTools.Services; using Orchard.Environment.Extensions; +using Orchard.Environment.State; namespace Orchard.DevTools.Commands { [OrchardFeature("Scaffolding")] diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index 7e70e6e8c..3f8956bd2 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -105,10 +105,10 @@ namespace Orchard.Setup.Services { Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }) }; - var shellToplogy = _compositionStrategy.Compose(shellSettings, shellDescriptor); + var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); // initialize database explicitly, and store shell descriptor - var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellToplogy); + var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint); using ( var environment = new StandaloneEnvironment(bootstrapLifetimeScope) ) { // check if the database is already created (in case an exception occured in the second phase) diff --git a/src/Orchard/Data/Migration/Generator/SchemaCommandGenerator.cs b/src/Orchard/Data/Migration/Generator/SchemaCommandGenerator.cs index b99a5e8cf..c93393daf 100644 --- a/src/Orchard/Data/Migration/Generator/SchemaCommandGenerator.cs +++ b/src/Orchard/Data/Migration/Generator/SchemaCommandGenerator.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Data; using System.Linq; using System.Reflection; @@ -9,27 +10,65 @@ using Orchard.ContentManagement.Records; using Orchard.Data.Migration.Schema; using Orchard.Data.Providers; using NHibernate.Dialect; +using Orchard.Environment.Configuration; +using Orchard.Environment.Descriptor.Models; +using Orchard.Environment.Extensions; +using Orchard.Environment.Extensions.Models; +using Orchard.Environment.ShellBuilders; +using Orchard.Environment.ShellBuilders.Models; +using Orchard.Environment.State; namespace Orchard.Data.Migration.Generator { public class SchemaCommandGenerator : ISchemaCommandGenerator { private readonly ISessionFactoryHolder _sessionFactoryHolder; + private readonly IExtensionManager _extensionManager; + private readonly ICompositionStrategy _compositionStrategy; + private readonly ShellSettings _shellSettings; + private readonly IDataServicesProviderFactory _dataServicesProviderFactory; public SchemaCommandGenerator( - ISessionFactoryHolder sessionFactoryHolder) { + ISessionFactoryHolder sessionFactoryHolder, + IExtensionManager extensionManager, + ICompositionStrategy compositionStrategy, + ShellSettings shellSettings, + IDataServicesProviderFactory dataServicesProviderFactory) { _sessionFactoryHolder = sessionFactoryHolder; + _extensionManager = extensionManager; + _compositionStrategy = compositionStrategy; + _shellSettings = shellSettings; + _dataServicesProviderFactory = dataServicesProviderFactory; } /// /// Generates SchemaCommand instances in order to create the schema for a specific feature /// public IEnumerable GetCreateFeatureCommands(string feature, bool drop) { - var parameters = _sessionFactoryHolder.GetSessionFactoryParameters(); + 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(); - if (!parameters.RecordDescriptors.Any()) { + var shellDescriptor = new ShellDescriptor { + Features = dependencies.Select(name => new ShellFeature { Name = name }).Union(new[] { new ShellFeature { Name = feature }, new ShellFeature { Name = "Orchard.Framework" } }) + }; + + var shellBlueprint = _compositionStrategy.Compose(_shellSettings, shellDescriptor); + + if ( !shellBlueprint.Records.Any() ) { yield break; } - var configuration = _sessionFactoryHolder.GetConfiguration(); + //var features = dependencies.Select(name => new ShellFeature {Name = name}).Union(new[] {new ShellFeature {Name = feature}, new ShellFeature {Name = "Orchard.Framework"}}); + + var parameters = _sessionFactoryHolder.GetSessionFactoryParameters(); + parameters.RecordDescriptors = shellBlueprint.Records; + + var configuration = _dataServicesProviderFactory + .CreateProvider(parameters) + .BuildConfiguration(parameters); + Dialect.GetDialect(configuration.Properties); var mapping = configuration.BuildMapping(); diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index ac8ad567c..99ec652a7 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -45,7 +45,7 @@ namespace Orchard.Environment.Extensions { public IEnumerable LoadFeatures(IEnumerable featureDescriptors) { return featureDescriptors - .Select(featureDescriptor => LoadFeature(featureDescriptor)) + .Select(LoadFeature) .ToArray(); }