From 5b02ca2813562c3f5146811d97b6d7afed3ca09f Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sat, 10 Oct 2020 22:14:10 +0200 Subject: [PATCH] Incremental work on migrations --- .../Extensions/ServiceCollectionExtensions.cs | 6 ++- ...rkflowInstanceByReceiveHttpRequestIndex.cs | 43 ++++++++++++++++++- .../Elsa.Activities.Http/Migrations.cs | 19 ++++++++ .../Elsa.Abstractions/Data/CollectionNames.cs | 2 +- .../Data/ServiceCollectionExtensions.cs | 11 +++-- .../PersistenceServiceCollectionExtensions.cs | 9 +++- .../Data/Services/DataMigrationManager.cs | 7 ++- src/core/Elsa.Core/Elsa.Core.csproj | 1 + .../ElsaServiceCollectionExtensions.cs | 4 +- src/core/Elsa.Core/Migrations.cs | 28 +++++++++++- .../Elsa.Samples.HelloWorldConsole/Program.cs | 4 +- .../Elsa.Samples.HelloWorldHttp/Startup.cs | 3 +- 12 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 src/activities/Elsa.Activities.Http/Migrations.cs diff --git a/src/activities/Elsa.Activities.Http/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.Http/Extensions/ServiceCollectionExtensions.cs index 937038f09..ef7de3b2b 100644 --- a/src/activities/Elsa.Activities.Http/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.Http/Extensions/ServiceCollectionExtensions.cs @@ -1,11 +1,14 @@ using System; using Elsa.Activities.Http; +using Elsa.Activities.Http.Indexes; using Elsa.Activities.Http.Models; using Elsa.Activities.Http.Options; using Elsa.Activities.Http.Parsers; using Elsa.Activities.Http.RequestHandlers.Handlers; using Elsa.Activities.Http.Services; +using Elsa.Data; using Elsa.Extensions; +using Elsa.Indexes; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -37,7 +40,8 @@ namespace Microsoft.Extensions.DependencyInjection .AddSingleton() .AddSingleton() .AddSingleton() - .AddTypeAlias() + .AddIndexProvider() + .AddDataMigration() .AddHttpContextAccessor() .AddNotificationHandlers(typeof(ServiceCollectionExtensions)) .AddDataProtection(); diff --git a/src/activities/Elsa.Activities.Http/Indexes/WorkflowInstanceByReceiveHttpRequestIndex.cs b/src/activities/Elsa.Activities.Http/Indexes/WorkflowInstanceByReceiveHttpRequestIndex.cs index 189c05169..8abfae227 100644 --- a/src/activities/Elsa.Activities.Http/Indexes/WorkflowInstanceByReceiveHttpRequestIndex.cs +++ b/src/activities/Elsa.Activities.Http/Indexes/WorkflowInstanceByReceiveHttpRequestIndex.cs @@ -1,4 +1,7 @@ -using YesSql.Indexes; +using System.Linq; +using Elsa.Indexes; +using Elsa.Models; +using YesSql.Indexes; namespace Elsa.Activities.Http.Indexes { @@ -8,4 +11,42 @@ namespace Elsa.Activities.Http.Indexes public string RequestPath { get; set; } = default!; public string? RequestMethod { get; set; } } + + public class WorkflowInstanceByReceiveHttpRequestIndexProvider : IndexProvider + { + public override void Describe(DescribeContext context) + { + context.For() + .Map( + workflowInstance => new WorkflowInstanceIndex + { + WorkflowInstanceId = workflowInstance.WorkflowInstanceId, + WorkflowDefinitionId = workflowInstance.WorkflowDefinitionId, + WorkflowStatus = workflowInstance.Status, + CorrelationId = workflowInstance.CorrelationId, + CreatedAt = workflowInstance.CreatedAt + }); + + context.For() + .Map( + workflowInstance => workflowInstance.BlockingActivities + .Where(x => x.ActivityType == nameof(ReceiveHttpRequest)) + .Select( + blockingActivity => + { + var activity = workflowInstance.Activities + .First(x => x.Id == blockingActivity.ActivityId); + + var path = activity.Data.Value(nameof(ReceiveHttpRequest.Path)); + var method = activity.Data.Value(nameof(ReceiveHttpRequest.Method)); + + return new WorkflowInstanceByReceiveHttpRequestIndex + { + ActivityId = blockingActivity.ActivityId, + RequestPath = path, + RequestMethod = method + }; + })); + } + } } \ No newline at end of file diff --git a/src/activities/Elsa.Activities.Http/Migrations.cs b/src/activities/Elsa.Activities.Http/Migrations.cs new file mode 100644 index 000000000..58e402350 --- /dev/null +++ b/src/activities/Elsa.Activities.Http/Migrations.cs @@ -0,0 +1,19 @@ +using Elsa.Activities.Http.Indexes; +using Elsa.Data; +using YesSql.Sql; + +namespace Elsa.Activities.Http +{ + public class Migrations : DataMigration + { + public int Create() + { + SchemaBuilder.CreateMapIndexTable(table => table + .Column("ActivityId") + .Column("RequestPath") + .Column("RequestMethod")); + + return 1; + } + } +} \ No newline at end of file diff --git a/src/core/Elsa.Abstractions/Data/CollectionNames.cs b/src/core/Elsa.Abstractions/Data/CollectionNames.cs index 969d31b57..19e827dde 100644 --- a/src/core/Elsa.Abstractions/Data/CollectionNames.cs +++ b/src/core/Elsa.Abstractions/Data/CollectionNames.cs @@ -3,6 +3,6 @@ public static class CollectionNames { public static string WorkflowDefinitions = "WorkflowDefinitions"; - public static string WorkflowInstances = "WorkflowDefinitions"; + public static string WorkflowInstances = "WorkflowInstances"; } } \ No newline at end of file diff --git a/src/core/Elsa.Abstractions/Data/ServiceCollectionExtensions.cs b/src/core/Elsa.Abstractions/Data/ServiceCollectionExtensions.cs index 3b96e00c9..a7d1069f9 100644 --- a/src/core/Elsa.Abstractions/Data/ServiceCollectionExtensions.cs +++ b/src/core/Elsa.Abstractions/Data/ServiceCollectionExtensions.cs @@ -1,15 +1,10 @@ -using Elsa.Services; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using YesSql.Indexes; namespace Elsa.Data { public static class ServiceCollectionExtensions { - public static IServiceCollection AddWorkflowProvider(this IServiceCollection services) - where T : class, IWorkflowProvider => - services.AddTransient(); - public static IServiceCollection AddIndexProvider(this IServiceCollection services) where T : class, IIndexProvider => services.AddSingleton(); @@ -17,5 +12,9 @@ namespace Elsa.Data public static IServiceCollection AddScopedIndexProvider(this IServiceCollection services) where T : class, IIndexProvider => services.AddScoped(); + + public static IServiceCollection AddDataMigration(this IServiceCollection services) + where T : class, IDataMigration => + services.AddScoped(); } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Data/Extensions/PersistenceServiceCollectionExtensions.cs b/src/core/Elsa.Core/Data/Extensions/PersistenceServiceCollectionExtensions.cs index 3700f880c..a118276d0 100644 --- a/src/core/Elsa.Core/Data/Extensions/PersistenceServiceCollectionExtensions.cs +++ b/src/core/Elsa.Core/Data/Extensions/PersistenceServiceCollectionExtensions.cs @@ -1,10 +1,14 @@ using System; +using System.Data; using System.Linq; +using Dapper; using Elsa.Data.Services; using Elsa.Runtime; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using YesSql; using YesSql.Indexes; +using ISession = YesSql.ISession; namespace Elsa.Data.Extensions { @@ -20,7 +24,8 @@ namespace Elsa.Data.Extensions .AddScoped(CreateSession) .AddSingleton() .AddStartupTask() - .AddStartupTask(); + .AddStartupTask() + .AddDataMigration(); return services; } @@ -36,6 +41,8 @@ namespace Elsa.Data.Extensions var store = StoreFactory.CreateAndInitializeAsync(configuration).GetAwaiter().GetResult(); //var store = StoreFactory.Create(configuration); + SqlMapper.AddTypeMap(typeof(PathString), DbType.String); + var indexes = serviceProvider.GetServices(); store.RegisterIndexes(indexes); diff --git a/src/core/Elsa.Core/Data/Services/DataMigrationManager.cs b/src/core/Elsa.Core/Data/Services/DataMigrationManager.cs index fe2f9a5f3..5780d6250 100644 --- a/src/core/Elsa.Core/Data/Services/DataMigrationManager.cs +++ b/src/core/Elsa.Core/Data/Services/DataMigrationManager.cs @@ -40,7 +40,7 @@ namespace Elsa.Data.Services public async Task RunAllAsync() { var migrationsToUpdate = await GetMigrationsThatNeedUpdateAsync(); - + foreach (var migration in migrationsToUpdate) { try @@ -52,6 +52,8 @@ namespace Elsa.Data.Services _logger.LogError(ex, "Could not run migrations automatically on '{FeatureName}'", migration); } } + + await _session.CommitAsync(); } public async Task> GetMigrationsThatNeedUpdateAsync() @@ -241,7 +243,8 @@ namespace Elsa.Data.Services { var flags = BindingFlags.Public | BindingFlags.Instance; var methodInfo = dataMigration.GetType().GetMethod(name, flags); - return methodInfo != null && methodInfo.ReturnType == typeof(Task) ? methodInfo : null; + var returnType = methodInfo?.ReturnType; + return returnType != null && (returnType == typeof(Task) || returnType == typeof(int)) ? methodInfo : null; } } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Elsa.Core.csproj b/src/core/Elsa.Core/Elsa.Core.csproj index 85d5617e3..3e94bfe8e 100644 --- a/src/core/Elsa.Core/Elsa.Core.csproj +++ b/src/core/Elsa.Core/Elsa.Core.csproj @@ -32,6 +32,7 @@ + diff --git a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs index 8d8233f15..35397cfc9 100644 --- a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs +++ b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs @@ -6,6 +6,7 @@ using Elsa.Activities.Primitives; using Elsa.Activities.Signaling; using Elsa.Builders; using Elsa.Converters; +using Elsa.Data; using Elsa.Data.Extensions; using Elsa.Expressions; using Elsa.Extensions; @@ -107,7 +108,8 @@ namespace Microsoft.Extensions.DependencyInjection .AddSingleton() .AddScoped() .AddSingleton() - .AddSingleton() + .AddIndexProvider() + .AddIndexProvider() .AddStartupRunner() .AddTransient() .AddWorkflowProvider() diff --git a/src/core/Elsa.Core/Migrations.cs b/src/core/Elsa.Core/Migrations.cs index bc51e43f7..048f052de 100644 --- a/src/core/Elsa.Core/Migrations.cs +++ b/src/core/Elsa.Core/Migrations.cs @@ -1,4 +1,7 @@ -using Elsa.Data; +using System.Data; +using Elsa.Data; +using Elsa.Indexes; +using YesSql.Sql; namespace Elsa { @@ -6,7 +9,28 @@ namespace Elsa { public int Create() { - //SchemaBuilder.CreateMapIndexTable<>() + SchemaBuilder.CreateMapIndexTable(table => table + .Column("WorkflowDefinitionId") + .Column("WorkflowDefinitionVersionId") + .Column("Version") + .Column("IsLatest") + .Column("IsPublished") + .Column("IsEnabled")); + + SchemaBuilder.CreateMapIndexTable(table => table + .Column("WorkflowInstanceId") + .Column("WorkflowDefinitionId") + .Column("CorrelationId") + .Column("WorkflowStatus", DbType.String) + .Column("CreatedAt", DbType.DateTimeOffset)); + + SchemaBuilder.CreateMapIndexTable(table => table + .Column("ActivityId") + .Column("ActivityType") + .Column("CorrelationId") + .Column("WorkflowStatus", DbType.String) + .Column("CreatedAt", DbType.DateTimeOffset)); + return 1; } } diff --git a/src/samples/Elsa.Samples.HelloWorldConsole/Program.cs b/src/samples/Elsa.Samples.HelloWorldConsole/Program.cs index 947a068d5..758858b64 100644 --- a/src/samples/Elsa.Samples.HelloWorldConsole/Program.cs +++ b/src/samples/Elsa.Samples.HelloWorldConsole/Program.cs @@ -5,7 +5,6 @@ using Elsa.Builders; using Elsa.Runtime; using Elsa.Services; using Microsoft.Extensions.DependencyInjection; -using YesSql.Provider.Sqlite; namespace Elsa.Samples.HelloWorldConsole { @@ -14,8 +13,7 @@ namespace Elsa.Samples.HelloWorldConsole static async Task Main(string[] args) { // Create a service container with Elsa services. - var services = new ServiceCollection() - //.AddElsa(options => options.UsePersistence(config => config.UseSqLite("Data Source=elsa.db;Cache=Shared"))) + var services = new ServiceCollection() .AddElsa() .AddConsoleActivities() .AddSingleton(Console.In) diff --git a/src/samples/Elsa.Samples.HelloWorldHttp/Startup.cs b/src/samples/Elsa.Samples.HelloWorldHttp/Startup.cs index 4f4c77a39..b9bc0de03 100644 --- a/src/samples/Elsa.Samples.HelloWorldHttp/Startup.cs +++ b/src/samples/Elsa.Samples.HelloWorldHttp/Startup.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; +using YesSql.Provider.Sqlite; namespace Elsa.Samples.HelloWorldHttp { @@ -8,7 +9,7 @@ namespace Elsa.Samples.HelloWorldHttp public void ConfigureServices(IServiceCollection services) { services - .AddElsa() + .AddElsa(option => option.UsePersistence(db => db.UseSqLite("Data Source=elsa.db;Cache=Shared"))) .AddHttpActivities() .AddWorkflow(); }