Merge branch 'develop' into feature/elsa-2.0

# Conflicts:
#	src/persistence/Elsa.Persistence.YesSql/StartupTasks/InitializeStoreTask.cs
This commit is contained in:
Sipke Schoorstra 2019-12-21 12:32:04 +01:00
commit 452516bdfa
33 changed files with 500 additions and 187 deletions

View file

@ -1,70 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Elsa.Serialization.Handlers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using NodaTime.Text;
namespace Elsa.Converters
{
public class TypeNameHandlingConverter : JsonConverter
{
private const string TypeFieldName = "TypeName";
private static readonly IDictionary<Type, IValueHandler> ValueHandlers = new Dictionary<Type, IValueHandler>();
public static void RegisterTypeHandler<T>() where T : IValueHandler
{
var handler = Activator.CreateInstance<T>();
RegisterTypeHandler(handler);
}
public static void RegisterTypeHandler(IValueHandler handler)
{
ValueHandlers[handler.GetType()] = handler;
}
static TypeNameHandlingConverter()
{
RegisterTypeHandler<DateTimeHandler>();
RegisterTypeHandler<InstantHandler>();
RegisterTypeHandler<AnnualDateHandler>();
RegisterTypeHandler<DurationHandler>();
RegisterTypeHandler<LocalDateHandler>();
RegisterTypeHandler<LocalDateTimeHandler>();
RegisterTypeHandler<LocalTimeHandler>();
RegisterTypeHandler<OffsetDateHandler>();
RegisterTypeHandler<OffsetHandler>();
RegisterTypeHandler<OffsetTimeHandler>();
RegisterTypeHandler<YearMonthHandler>();
RegisterTypeHandler<ZonedDateTimeHandler>();
}
public override bool CanRead => true;
public override bool CanWrite => true;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var valueType = value.GetType();
var token = JToken.FromObject(value);
var handler = GetHandler(x => x.CanSerialize(token, valueType));
switch (token.Type)
{
case JTokenType.Object:
token[TypeFieldName] = GetAssemblyQualifiedTypeName(value.GetType());
token.WriteTo(writer, serializer.Converters.ToArray());
break;
case JTokenType.Date: // Taking over DateTime serialization because NodaTime disabled date handling.
var dateToken = new JObject();
dateToken[TypeFieldName] = "DateTime";
dateToken["Value"] = token;
dateToken.WriteTo(writer, serializer.Converters.ToArray());
break;
default:
token.WriteTo(writer);
break;
}
handler.Serialize(writer, serializer, token);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.ReadFrom(reader);
var handler = GetHandler(x => x.CanDeserialize(token, objectType));
switch (token.Type)
{
case JTokenType.Object:
var typeName = token[TypeFieldName].Value<string>();
if (typeName == "DateTime")
{
var dateTime = token["Value"].ToObject<DateTime>();
return dateTime;
}
else
{
var type = Type.GetType(typeName);
return token.ToObject(type, serializer);
}
default:
return token.ToObject(objectType);
}
return handler.Deserialize(reader, serializer, objectType, token);
}
public override bool CanConvert(Type objectType) => true;
private string GetAssemblyQualifiedTypeName(Type type)
{
var typeName = type.FullName;
var assemblyName = type.Assembly.GetName().Name;
return $"{typeName}, {assemblyName}";
}
private IValueHandler GetHandler(Func<IValueHandler, bool> predicate) =>
ValueHandlers.Values.OrderByDescending(x => x.Priority).FirstOrDefault(predicate) ?? new DefaultValueHandler();
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class AnnualDateHandler : PrimitiveValueHandler<AnnualDate>
{
protected override object ParseValue(JToken value) => AnnualDatePattern.Iso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,10 @@
using System;
using Newtonsoft.Json.Linq;
namespace Elsa.Serialization.Handlers
{
public sealed class DateTimeHandler : PrimitiveValueHandler<DateTime>
{
protected override object ParseValue(JToken value) => value.Value<DateTime>();
}
}

View file

@ -0,0 +1,15 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Elsa.Serialization.Handlers
{
public class DefaultValueHandler : IValueHandler
{
public int Priority => -9000;
public bool CanSerialize(JToken value, Type type) => true;
public bool CanDeserialize(JToken value, Type type) => true;
public object Deserialize(JsonReader reader, JsonSerializer serializer, Type type, JToken value) => serializer.Deserialize(value.CreateReader(), type);
public void Serialize(JsonWriter writer, JsonSerializer serializer, JToken value) => serializer.Serialize(writer, value);
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class DurationHandler : PrimitiveValueHandler<Duration>
{
protected override object ParseValue(JToken value) => DurationPattern.Roundtrip.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,15 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Elsa.Serialization.Handlers
{
public interface IValueHandler
{
int Priority { get; }
bool CanSerialize(JToken value, Type type);
bool CanDeserialize(JToken value, Type type);
object Deserialize(JsonReader reader, JsonSerializer serializer, Type type, JToken value);
void Serialize(JsonWriter writer, JsonSerializer serializer, JToken value);
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class InstantHandler : PrimitiveValueHandler<Instant>
{
protected override object ParseValue(JToken value) => InstantPattern.ExtendedIso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class LocalDateHandler : PrimitiveValueHandler<LocalDate>
{
protected override object ParseValue(JToken value) => LocalDatePattern.Iso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class LocalDateTimeHandler : PrimitiveValueHandler<LocalDateTime>
{
protected override object ParseValue(JToken value) => LocalDateTimePattern.ExtendedIso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class LocalTimeHandler : PrimitiveValueHandler<LocalTime>
{
protected override object ParseValue(JToken value) => LocalTimePattern.LongExtendedIso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,36 @@
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Elsa.Serialization.Handlers
{
public class ObjectHandler : IValueHandler
{
private const string TypeFieldName = "TypeName";
public int Priority => -8999;
public bool CanSerialize(JToken value, Type type) => value.Type == JTokenType.Object;
public bool CanDeserialize(JToken value, Type type) => value.Type == JTokenType.Object;
public object Deserialize(JsonReader reader, JsonSerializer serializer, Type type, JToken value)
{
var typeName = value[TypeFieldName].Value<string>();
var objectType = Type.GetType(typeName);
return value.ToObject(objectType, serializer);
}
public void Serialize(JsonWriter writer, JsonSerializer serializer, JToken value)
{
value[TypeFieldName] = GetAssemblyQualifiedTypeName(value.GetType());
value.WriteTo(writer, serializer.Converters.ToArray());
}
private string GetAssemblyQualifiedTypeName(Type type)
{
var typeName = type.FullName;
var assemblyName = type.Assembly.GetName().Name;
return $"{typeName}, {assemblyName}";
}
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class OffsetDateHandler : PrimitiveValueHandler<OffsetDate>
{
protected override object ParseValue(JToken value) => OffsetDatePattern.GeneralIso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class OffsetHandler : PrimitiveValueHandler<Offset>
{
protected override object ParseValue(JToken value) => OffsetPattern.GeneralInvariant.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class OffsetTimeHandler : PrimitiveValueHandler<OffsetTime>
{
protected override object ParseValue(JToken value) => OffsetTimePattern.GeneralIso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,33 @@
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Elsa.Serialization.Handlers
{
public abstract class PrimitiveValueHandler<T> : IValueHandler
{
public virtual int Priority => 0;
public bool CanSerialize(JToken value, Type type) => type == typeof(T);
public bool CanDeserialize(JToken value, Type type) => value.Type == JTokenType.Object && value["Type"]?.Value<string>() == TypeName;
protected virtual string TypeName => typeof(T).Name;
public virtual object Deserialize(JsonReader reader, JsonSerializer serializer, Type type, JToken value)
{
var valueToken = value["Value"];
return ParseValue(valueToken);
}
public virtual void Serialize(JsonWriter writer, JsonSerializer serializer, JToken value)
{
var token = new JObject
{
["Type"] = TypeName,
["Value"] = value
};
token.WriteTo(writer, serializer.Converters.ToArray());
}
protected abstract object ParseValue(JToken value);
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class YearMonthHandler : PrimitiveValueHandler<YearMonth>
{
protected override object ParseValue(JToken value) => YearMonthPattern.Iso.Parse(value.ToString()).Value;
}
}

View file

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
namespace Elsa.Serialization.Handlers
{
public sealed class ZonedDateTimeHandler : PrimitiveValueHandler<ZonedDateTime>
{
protected override object ParseValue(JToken value) => ZonedDateTimePattern.ExtendedFormatOnlyIso.Parse(value.ToString()).Value;
}
}

View file

@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
namespace Elsa.Persistence.EntityFrameworkCore.Extensions
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public static class CustomSchemaDbContextBuilderExtensions
{

View file

@ -1,12 +1,15 @@
using Elsa.Persistence.EntityFrameworkCore.DbContexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public class CustomSchemaModelCacheKeyFactory : IModelCacheKeyFactory
{
public CustomSchemaModelCacheKeyFactory() { }
public CustomSchemaModelCacheKeyFactory()
{
}
public object Create(DbContext context)
{
string schema = null;
@ -18,6 +21,7 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
schema = dbContextCustomSchema.Schema;
}
}
return new
{
Type = context.GetType(),

View file

@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public class CustomSchemaOptionsExtension : IDbContextOptionsExtension
{
public DbContextOptionsExtensionInfo Info => new CustomSchemaOptionsExtensionInfo(this);
public IDbContextCustomSchema ContextCustomSchema { get; protected set; }
public CustomSchemaOptionsExtension(IDbContextCustomSchema customSchema) : base()
{
ContextCustomSchema = customSchema;
}
protected CustomSchemaOptionsExtension(CustomSchemaOptionsExtension copyFrom)
{
copyFrom.ContextCustomSchema = ContextCustomSchema;
}
public void ApplyServices(IServiceCollection services)
{
}
public void Validate(IDbContextOptions options)
{
}
}
}

View file

@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public sealed class CustomSchemaOptionsExtensionInfo : DbContextOptionsExtensionInfo
{
private string logFragment;
public CustomSchemaOptionsExtensionInfo(IDbContextOptionsExtension dbContextOptionsExtension) : base(dbContextOptionsExtension)
{
}
/// <summary>
/// The extension for which this instance contains metadata.
/// </summary>
private new CustomSchemaOptionsExtension Extension => (CustomSchemaOptionsExtension)base.Extension;
public override bool IsDatabaseProvider => false;
public override string LogFragment
{
get
{
if (!string.IsNullOrWhiteSpace(LogFragment))
return logFragment;
if (Extension.ContextCustomSchema != null && Extension.ContextCustomSchema.UseCustomSchema)
{
var builder = new StringBuilder();
builder.Append($"Use Custom Schema: {Extension.ContextCustomSchema.UseCustomSchema}");
builder.Append($"Custom Schema: {Extension.ContextCustomSchema.Schema}");
builder.Append($"Migrations History Table Name: {Extension.ContextCustomSchema.MigrationsHistoryTableName}");
logFragment = builder.ToString();
}
return logFragment;
}
}
public override long GetServiceProviderHashCode() => 0;
public override void PopulateDebugInfo([NotNull] IDictionary<string, string> debugInfo)
{
debugInfo["CustomSchemaExtensionInfo"] = true.ToString();
}
}
}

View file

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public class DbContextCustomSchema : IDbContextCustomSchema
{

View file

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public interface IDbContextCustomSchema
{

View file

@ -1,8 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
namespace Elsa.Persistence.EntityFrameworkCore.CustomSchema
{
public class SchemaEntityTypeConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
where TEntity : class

View file

@ -1,86 +0,0 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
{
public class CustomSchemaOptionsExtension : IDbContextOptionsExtension
{
public DbContextOptionsExtensionInfo Info => new CustomSchemaExtensionInfo(this);
public IDbContextCustomSchema ContextCustomSchema { get; protected set; }
public CustomSchemaOptionsExtension(IDbContextCustomSchema customSchema) : base()
{
ContextCustomSchema = customSchema;
}
protected CustomSchemaOptionsExtension(CustomSchemaOptionsExtension copyFrom)
{
copyFrom.ContextCustomSchema = ContextCustomSchema;
}
public void ApplyServices(IServiceCollection services)
{
}
public void Validate(IDbContextOptions options)
{
}
protected CustomSchemaOptionsExtension Clone()
{
return new CustomSchemaOptionsExtension(this);
}
}
public class CustomSchemaExtensionInfo : DbContextOptionsExtensionInfo
{
string logFragment = null;
public CustomSchemaExtensionInfo(IDbContextOptionsExtension dbContextOptionsExtension) : base(dbContextOptionsExtension)
{
}
/// <summary>
/// The extension for which this instance contains metadata.
/// </summary>
public new virtual CustomSchemaOptionsExtension Extension
=> (CustomSchemaOptionsExtension)base.Extension;
public override bool IsDatabaseProvider => false;
public override string LogFragment
{
get
{
if (!string.IsNullOrWhiteSpace(LogFragment)) return logFragment;
if(Extension.ContextCustomSchema != null && Extension.ContextCustomSchema.UseCustomSchema)
{
var builder = new StringBuilder();
builder.Append($"Use Custom Schema: {Extension.ContextCustomSchema.UseCustomSchema}");
builder.Append($"Custom Schema: {Extension.ContextCustomSchema.Schema}");
builder.Append($"Migrations History Table Name: {Extension.ContextCustomSchema.MigrationsHistoryTableName}");
logFragment = builder.ToString();
}
return logFragment;
}
}
public override long GetServiceProviderHashCode()
{
return 0;
}
public override void PopulateDebugInfo([NotNullAttribute] IDictionary<string, string> debugInfo)
{
debugInfo["CustomSchemaExtensionInfo"] = true.ToString();
}
}
}

View file

@ -1,10 +1,9 @@
using System.Collections.Generic;
using Elsa.Models;
using Elsa.Persistence.EntityFrameworkCore.CustomSchema;
using Elsa.Persistence.EntityFrameworkCore.Entities;
using Elsa.Persistence.EntityFrameworkCore.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime;
@ -15,17 +14,18 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts
public class ElsaContext : DbContext
{
private readonly JsonSerializerSettings serializerSettings;
/// <summary>
/// The CustomSchemaModelCacheKeyFactory will not resolve services from the DI container for constructor injection
/// so this is necessary in order to set the custom schema for the Model Cache.
/// </summary>
internal IDbContextCustomSchema DbContextCustomSchema { get; set; }
public ElsaContext(DbContextOptions<ElsaContext> options) : base(options)
{
serializerSettings = new JsonSerializerSettings().ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
DbContextCustomSchema = options.GetDbContextCustomSchema();
}
/// <summary>
/// The CustomSchemaModelCacheKeyFactory will not resolve services from the DI container for constructor injection
/// so this is necessary in order to set the custom schema for the Model Cache.
/// </summary>
internal IDbContextCustomSchema DbContextCustomSchema { get; }
public DbSet<WorkflowDefinitionVersionEntity> WorkflowDefinitionVersions { get; set; }
public DbSet<WorkflowInstanceEntity> WorkflowInstances { get; set; }

View file

@ -3,6 +3,7 @@ using Elsa.AutoMapper.Extensions;
using Elsa.AutoMapper.Extensions.NodaTime;
using Elsa.Persistence.YesSql.Indexes;
using Elsa.Persistence.YesSql.Mapping;
using Elsa.Persistence.YesSql.Schema;
using Elsa.Persistence.YesSql.Services;
using Elsa.Persistence.YesSql.StartupTasks;
using Elsa.Runtime;
@ -22,6 +23,7 @@ namespace Elsa.Persistence.YesSql.Extensions
.AddSingleton(sp => StoreFactory.CreateStore(sp, configure))
.AddSingleton<IIndexProvider, WorkflowDefinitionIndexProvider>()
.AddSingleton<IIndexProvider, WorkflowInstanceIndexProvider>()
.AddTransient<ISchemaVersionStore, SchemaVersionStore>()
.AddScoped(CreateSession)
.AddAutoMapperProfile<NodaTimeProfile>(ServiceLifetime.Singleton)
.AddAutoMapperProfile<DocumentProfile>(ServiceLifetime.Singleton)

View file

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Elsa.Persistence.YesSql.Schema
{
public interface ISchemaVersionStore
{
Task<int> GetVersionAsync();
Task SaveVersionAsync(int version);
}
}

View file

@ -0,0 +1,7 @@
namespace Elsa.Persistence.YesSql.Schema
{
public class SchemaVersionDocument
{
public int Version { get; set; }
}
}

View file

@ -0,0 +1,37 @@
using System.Threading.Tasks;
using YesSql;
namespace Elsa.Persistence.YesSql.Schema
{
public class SchemaVersionStore : ISchemaVersionStore
{
private readonly ISession session;
public SchemaVersionStore(ISession session)
{
this.session = session;
}
public async Task<int> GetVersionAsync()
{
var schemaVersion = await session.Query<SchemaVersionDocument>().FirstOrDefaultAsync();
if (schemaVersion == null)
{
schemaVersion = new SchemaVersionDocument {Version = 0};
session.Save(schemaVersion);
await session.CommitAsync();
}
return schemaVersion.Version;
}
public async Task SaveVersionAsync(int version)
{
var schemaVersion = await session.Query<SchemaVersionDocument>().FirstOrDefaultAsync();
schemaVersion.Version = version;
session.Save(schemaVersion);
await session.CommitAsync();
}
}
}

View file

@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Persistence.YesSql.Indexes;
using Elsa.Persistence.YesSql.Schema;
using Elsa.Runtime;
using YesSql;
using YesSql.Sql;
@ -11,19 +14,68 @@ namespace Elsa.Persistence.YesSql.StartupTasks
public class InitializeStoreTask : IStartupTask
{
private readonly IStore store;
private readonly ISchemaVersionStore schemaVersionStore;
private readonly SchemaUpdate[] schemaVersionUpdates;
public InitializeStoreTask(IStore store)
public InitializeStoreTask(IStore store,
ISchemaVersionStore schemaVersionStore)
{
this.store = store;
}
public Task ExecuteAsync(CancellationToken cancellationToken = default)
{
CreateTables();
return Task.CompletedTask;
this.schemaVersionStore = schemaVersionStore;
schemaVersionUpdates = new[]
{
new SchemaUpdate {Version = 1, Update = UpdateToVersion1}
};
}
private void CreateTables()
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
int currentVersion = await schemaVersionStore.GetVersionAsync();
foreach (var schemaUpdate in schemaVersionUpdates.Where(x => x.Version > currentVersion))
{
schemaUpdate.Update();
await schemaVersionStore.SaveVersionAsync(schemaUpdate.Version);
}
}
private void UpdateToVersion1()
{
PerformUpdates(builder =>
{
builder
.CreateMapIndexTable(nameof(WorkflowDefinitionIndex), table => table
.Column<string>("VersionId")
.Column<string>("WorkflowDefinitionId")
.Column<int>("Version")
.Column<bool>("IsPublished")
.Column<bool>("IsLatest")
.Column<bool>("IsDisabled")
)
.CreateMapIndexTable(nameof(WorkflowDefinitionStartActivitiesIndex), table => table
.Column<string>("StartActivityId")
.Column<string>("StartActivityType")
.Column<bool>("IsDisabled")
)
.CreateMapIndexTable(nameof(WorkflowInstanceIndex), table => table
.Column<string>("WorkflowInstanceId")
.Column<string>("WorkflowDefinitionId")
.Column<string>("CorrelationId")
.Column<string>("WorkflowStatus")
.Column<DateTime>("CreatedAt")
)
.CreateMapIndexTable(nameof(WorkflowInstanceBlockingActivitiesIndex), table => table
.Column<string>("ActivityId")
.Column<string>("ActivityType")
.Column<string>("CorrelationId")
.Column<string>("WorkflowStatus")
.Column<DateTime>("CreatedAt")
);
});
}
private void PerformUpdates(Action<ISchemaBuilder> builder)
{
using (var connection = store.Configuration.ConnectionFactory.CreateConnection())
{
@ -31,38 +83,19 @@ namespace Elsa.Persistence.YesSql.StartupTasks
using (var transaction = connection.BeginTransaction(store.Configuration.IsolationLevel))
{
new SchemaBuilder(store.Configuration, transaction, false)
.CreateMapIndexTable(nameof(WorkflowDefinitionIndex), table => table
.Column<string>("VersionId")
.Column<string>("WorkflowDefinitionId")
.Column<int>("Version")
.Column<bool>("IsPublished")
.Column<bool>("IsLatest")
.Column<bool>("IsDisabled")
)
.CreateMapIndexTable(nameof(WorkflowDefinitionStartActivitiesIndex), table => table
.Column<string>("StartActivityId")
.Column<string>("StartActivityType")
.Column<bool>("IsDisabled")
)
.CreateMapIndexTable(nameof(WorkflowInstanceIndex), table => table
.Column<string>("WorkflowInstanceId")
.Column<string>("WorkflowDefinitionId")
.Column<string>("CorrelationId")
.Column<string>("WorkflowStatus")
.Column<DateTime>("CreatedAt")
)
.CreateMapIndexTable(nameof(WorkflowInstanceBlockingActivitiesIndex), table => table
.Column<string>("ActivityId")
.Column<string>("ActivityType")
.Column<string>("CorrelationId")
.Column<string>("WorkflowStatus")
.Column<DateTime>("CreatedAt")
);
var schemaBuilder = new SchemaBuilder(store.Configuration, transaction, false);
builder(schemaBuilder);
transaction.Commit();
}
}
}
private class SchemaUpdate
{
internal int Version { get; set; }
internal Action Update { get; set; }
}
}
}

View file

@ -1,4 +1,5 @@
using Elsa;
using Elsa.Persistence.EntityFrameworkCore.CustomSchema;
using Elsa.Persistence.EntityFrameworkCore.DbContexts;
using Elsa.Persistence.EntityFrameworkCore.Extensions;
using Microsoft.EntityFrameworkCore;

View file

@ -5,6 +5,7 @@ using Elsa.Extensions;
using Elsa.Models;
using Elsa.Persistence;
using Elsa.Persistence.EntityFrameworkCore;
using Elsa.Persistence.EntityFrameworkCore.CustomSchema;
using Elsa.Persistence.EntityFrameworkCore.DbContexts;
using Elsa.Persistence.EntityFrameworkCore.Extensions;
using Elsa.Runtime;