diff --git a/src/modules/Elsa.Dapper.Migrations/Runtime/AddKeyValueStore.cs b/src/modules/Elsa.Dapper.Migrations/Runtime/AddKeyValueStore.cs
new file mode 100644
index 000000000..4baae4147
--- /dev/null
+++ b/src/modules/Elsa.Dapper.Migrations/Runtime/AddKeyValueStore.cs
@@ -0,0 +1,25 @@
+using FluentMigrator;
+using JetBrains.Annotations;
+
+namespace Elsa.Dapper.Migrations.Runtime;
+
+///
+[Migration(20002, "Elsa:Runtime:AddKeyValueStore")]
+[PublicAPI]
+public class AddKeyValueStore : Migration
+{
+ ///
+ public override void Up()
+ {
+ Create
+ .Table("KeyValuePairs")
+ .WithColumn("Key").AsString().PrimaryKey()
+ .WithColumn("Value").AsString().NotNullable();
+ }
+
+ ///
+ public override void Down()
+ {
+ Delete.Table("KeyValuePairs");
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Dapper/Modules/Runtime/Features/DapperWorkflowRuntimePersistenceFeature.cs b/src/modules/Elsa.Dapper/Modules/Runtime/Features/DapperWorkflowRuntimePersistenceFeature.cs
index bfa802419..43888dd14 100644
--- a/src/modules/Elsa.Dapper/Modules/Runtime/Features/DapperWorkflowRuntimePersistenceFeature.cs
+++ b/src/modules/Elsa.Dapper/Modules/Runtime/Features/DapperWorkflowRuntimePersistenceFeature.cs
@@ -31,6 +31,7 @@ public class DapperWorkflowRuntimePersistenceFeature : FeatureBase
feature.WorkflowInboxStore = sp => sp.GetRequiredService();
feature.WorkflowExecutionLogStore = sp => sp.GetRequiredService();
feature.ActivityExecutionLogStore = sp => sp.GetRequiredService();
+ feature.KeyValueStore = sp => sp.GetRequiredService();
});
}
@@ -44,5 +45,6 @@ public class DapperWorkflowRuntimePersistenceFeature : FeatureBase
Services.AddScoped();
Services.AddScoped();
Services.AddScoped();
+ Services.AddScoped();
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Dapper/Modules/Runtime/Records/KeyValuePairRecord.cs b/src/modules/Elsa.Dapper/Modules/Runtime/Records/KeyValuePairRecord.cs
new file mode 100644
index 000000000..64730f781
--- /dev/null
+++ b/src/modules/Elsa.Dapper/Modules/Runtime/Records/KeyValuePairRecord.cs
@@ -0,0 +1,7 @@
+namespace Elsa.Dapper.Modules.Runtime.Records;
+
+public class KeyValuePairRecord
+{
+ public string Key { get; set; } = default!;
+ public string Value { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Dapper/Modules/Runtime/Stores/KeyValueStore.cs b/src/modules/Elsa.Dapper/Modules/Runtime/Stores/KeyValueStore.cs
new file mode 100644
index 000000000..1c0c2e392
--- /dev/null
+++ b/src/modules/Elsa.Dapper/Modules/Runtime/Stores/KeyValueStore.cs
@@ -0,0 +1,64 @@
+using Elsa.Dapper.Contracts;
+using Elsa.Dapper.Extensions;
+using Elsa.Dapper.Modules.Runtime.Records;
+using Elsa.Dapper.Services;
+using Elsa.Workflows.Runtime.Contracts;
+using Elsa.Workflows.Runtime.Entities;
+
+namespace Elsa.Dapper.Modules.Runtime.Stores;
+
+///
+/// A Dapper implementation of .
+///
+public class DapperKeyValueStore : IKeyValueStore
+{
+ private const string TableName = "Users";
+ private const string PrimaryKeyName = "Key";
+ private readonly Store _store;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ public DapperKeyValueStore(IDbConnectionProvider dbConnectionProvider)
+ {
+ _store = new Store(dbConnectionProvider, TableName, PrimaryKeyName);
+ }
+
+ ///
+ public Task SaveAsync(SerializedKeyValuePair keyValuePair, CancellationToken cancellationToken)
+ {
+ var record = Map(keyValuePair);
+ return _store.SaveAsync(record, PrimaryKeyName, cancellationToken);
+ }
+
+ ///
+ public async Task GetValue(string key, CancellationToken cancellationToken)
+ {
+ var record = await _store.FindAsync(query => query.Is(nameof(KeyValuePairRecord.Key), key), cancellationToken);
+ return record == null ? null : Map(record);
+ }
+
+ ///
+ public Task DeleteAsync(string key, CancellationToken cancellationToken)
+ {
+ return _store.DeleteAsync(query => query.Is(nameof(KeyValuePairRecord.Key), key), cancellationToken);
+ }
+
+ private KeyValuePairRecord Map(SerializedKeyValuePair kvp)
+ {
+ return new()
+ {
+ Key = kvp.Key,
+ Value = kvp.SerializedValue
+ };
+ }
+
+ private SerializedKeyValuePair Map(KeyValuePairRecord kvp)
+ {
+ return new()
+ {
+ Key = kvp.Key,
+ SerializedValue = kvp.Value
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.Designer.cs b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.Designer.cs
new file mode 100644
index 000000000..c15199c95
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.Designer.cs
@@ -0,0 +1,405 @@
+//
+using System;
+using Elsa.EntityFrameworkCore.Modules.Runtime;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.MySql.Migrations.Runtime
+{
+ [DbContext(typeof(RuntimeElsaDbContext))]
+ [Migration("20240202095704_AddKeyValueStore")]
+ partial class AddKeyValueStore
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("Elsa")
+ .HasAnnotation("ProductVersion", "7.0.2")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityName")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityNodeId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityType")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityTypeVersion")
+ .HasColumnType("int");
+
+ b.Property("CompletedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("HasBookmarks")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("SerializedActivityState")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedException")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedOutputs")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("longtext");
+
+ b.Property("StartedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ActivityId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityId");
+
+ b.HasIndex("ActivityName")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityName");
+
+ b.HasIndex("ActivityNodeId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityNodeId");
+
+ b.HasIndex("ActivityType")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityType");
+
+ b.HasIndex("ActivityTypeVersion")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityTypeVersion");
+
+ b.HasIndex("CompletedAt")
+ .HasDatabaseName("IX_ActivityExecutionRecord_CompletedAt");
+
+ b.HasIndex("HasBookmarks")
+ .HasDatabaseName("IX_ActivityExecutionRecord_HasBookmarks");
+
+ b.HasIndex("StartedAt")
+ .HasDatabaseName("IX_ActivityExecutionRecord_StartedAt");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("IX_ActivityExecutionRecord_Status");
+
+ b.HasIndex("WorkflowInstanceId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_WorkflowInstanceId");
+
+ b.HasIndex("ActivityType", "ActivityTypeVersion")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityType_ActivityTypeVersion");
+
+ b.ToTable("ActivityExecutionRecords", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.SerializedKeyValuePair", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("varchar(255)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SerializedValue")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Key");
+
+ b.ToTable("KeyValuePairs", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredBookmark", b =>
+ {
+ b.Property("BookmarkId")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityInstanceId")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityTypeName")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("CorrelationId")
+ .HasColumnType("longtext");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Hash")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("SerializedMetadata")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("longtext");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.HasKey("BookmarkId");
+
+ b.HasIndex(new[] { "ActivityInstanceId" }, "IX_StoredBookmark_ActivityInstanceId");
+
+ b.HasIndex(new[] { "ActivityTypeName" }, "IX_StoredBookmark_ActivityTypeName");
+
+ b.HasIndex(new[] { "ActivityTypeName", "Hash" }, "IX_StoredBookmark_ActivityTypeName_Hash");
+
+ b.HasIndex(new[] { "ActivityTypeName", "Hash", "WorkflowInstanceId" }, "IX_StoredBookmark_ActivityTypeName_Hash_WorkflowInstanceId");
+
+ b.HasIndex(new[] { "CreatedAt" }, "IX_StoredBookmark_CreatedAt");
+
+ b.HasIndex(new[] { "Hash" }, "IX_StoredBookmark_Hash");
+
+ b.HasIndex(new[] { "WorkflowInstanceId" }, "IX_StoredBookmark_WorkflowInstanceId");
+
+ b.ToTable("Bookmarks", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredTrigger", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("Hash")
+ .HasColumnType("varchar(255)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("longtext");
+
+ b.Property("WorkflowDefinitionId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("WorkflowDefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Hash")
+ .HasDatabaseName("IX_StoredTrigger_Hash");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_StoredTrigger_Name");
+
+ b.HasIndex("WorkflowDefinitionId")
+ .HasDatabaseName("IX_StoredTrigger_WorkflowDefinitionId");
+
+ b.HasIndex("WorkflowDefinitionVersionId")
+ .HasDatabaseName("IX_StoredTrigger_WorkflowDefinitionVersionId");
+
+ b.ToTable("Triggers", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.WorkflowExecutionLogRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityInstanceId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityName")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityNodeId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityType")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityTypeVersion")
+ .HasColumnType("int");
+
+ b.Property("EventName")
+ .HasColumnType("varchar(255)");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("ParentActivityInstanceId")
+ .HasColumnType("varchar(255)");
+
+ b.Property("Sequence")
+ .HasColumnType("bigint");
+
+ b.Property("SerializedActivityState")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("longtext");
+
+ b.Property("Source")
+ .HasColumnType("longtext");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime(6)");
+
+ b.Property("WorkflowDefinitionId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("WorkflowDefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("WorkflowVersion")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ActivityId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityId");
+
+ b.HasIndex("ActivityInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityInstanceId");
+
+ b.HasIndex("ActivityName")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityName");
+
+ b.HasIndex("ActivityNodeId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityNodeId");
+
+ b.HasIndex("ActivityType")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityType");
+
+ b.HasIndex("ActivityTypeVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityTypeVersion");
+
+ b.HasIndex("EventName")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_EventName");
+
+ b.HasIndex("ParentActivityInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ParentActivityInstanceId");
+
+ b.HasIndex("Sequence")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Sequence");
+
+ b.HasIndex("Timestamp")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Timestamp");
+
+ b.HasIndex("WorkflowDefinitionId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowDefinitionId");
+
+ b.HasIndex("WorkflowDefinitionVersionId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowDefinitionVersionId");
+
+ b.HasIndex("WorkflowInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowInstanceId");
+
+ b.HasIndex("WorkflowVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowVersion");
+
+ b.HasIndex("ActivityType", "ActivityTypeVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityType_ActivityTypeVersion");
+
+ b.HasIndex("Timestamp", "Sequence")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Timestamp_Sequence");
+
+ b.ToTable("WorkflowExecutionLogRecords", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.WorkflowInboxMessage", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityInstanceId")
+ .HasColumnType("varchar(255)");
+
+ b.Property("ActivityTypeName")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("CorrelationId")
+ .HasColumnType("varchar(255)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Hash")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("SerializedBookmarkPayload")
+ .HasColumnType("longtext");
+
+ b.Property("SerializedInput")
+ .HasColumnType("longtext");
+
+ b.Property("WorkflowInstanceId")
+ .HasColumnType("varchar(255)");
+
+ b.HasKey("Id");
+
+ b.HasIndex(new[] { "ActivityInstanceId" }, "IX_WorkflowInboxMessage_ActivityInstanceId");
+
+ b.HasIndex(new[] { "ActivityTypeName" }, "IX_WorkflowInboxMessage_ActivityTypeName");
+
+ b.HasIndex(new[] { "CorrelationId" }, "IX_WorkflowInboxMessage_CorrelationId");
+
+ b.HasIndex(new[] { "CreatedAt" }, "IX_WorkflowInboxMessage_CreatedAt");
+
+ b.HasIndex(new[] { "ExpiresAt" }, "IX_WorkflowInboxMessage_ExpiresAt");
+
+ b.HasIndex(new[] { "Hash" }, "IX_WorkflowInboxMessage_Hash");
+
+ b.HasIndex(new[] { "WorkflowInstanceId" }, "IX_WorkflowInboxMessage_WorkflowInstanceId");
+
+ b.ToTable("WorkflowInboxMessages", "Elsa");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.cs b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.cs
new file mode 100644
index 000000000..075cb919c
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/20240202095704_AddKeyValueStore.cs
@@ -0,0 +1,41 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.MySql.Migrations.Runtime
+{
+ ///
+ public partial class AddKeyValueStore : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "KeyValuePairs",
+ schema: "Elsa",
+ columns: table => new
+ {
+ Key = table.Column(type: "varchar(255)", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ SerializedValue = table.Column(type: "longtext", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ CreatedAt = table.Column(type: "datetime(6)", nullable: false),
+ UpdatedAt = table.Column(type: "datetime(6)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_KeyValuePairs", x => x.Key);
+ })
+ .Annotation("MySql:CharSet", "utf8mb4");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "KeyValuePairs",
+ schema: "Elsa");
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
index 86665b528..dd910f205 100644
--- a/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.MySql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
@@ -17,7 +17,7 @@ namespace Elsa.EntityFrameworkCore.MySql.Migrations.Runtime
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Elsa")
- .HasAnnotation("ProductVersion", "7.0.11")
+ .HasAnnotation("ProductVersion", "7.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord", b =>
@@ -110,6 +110,26 @@ namespace Elsa.EntityFrameworkCore.MySql.Migrations.Runtime
b.ToTable("ActivityExecutionRecords", "Elsa");
});
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.SerializedKeyValuePair", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("varchar(255)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SerializedValue")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Key");
+
+ b.ToTable("KeyValuePairs", "Elsa");
+ });
+
modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredBookmark", b =>
{
b.Property("BookmarkId")
diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.Designer.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.Designer.cs
new file mode 100644
index 000000000..7aae79840
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.Designer.cs
@@ -0,0 +1,408 @@
+//
+using System;
+using Elsa.EntityFrameworkCore.Modules.Runtime;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.PostgreSql.Migrations.Runtime
+{
+ [DbContext(typeof(RuntimeElsaDbContext))]
+ [Migration("20240202095953_AddKeyValueStore")]
+ partial class AddKeyValueStore
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("Elsa")
+ .HasAnnotation("ProductVersion", "7.0.14")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityName")
+ .HasColumnType("text");
+
+ b.Property("ActivityNodeId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityTypeVersion")
+ .HasColumnType("integer");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("HasBookmarks")
+ .HasColumnType("boolean");
+
+ b.Property("SerializedActivityState")
+ .HasColumnType("text");
+
+ b.Property("SerializedException")
+ .HasColumnType("text");
+
+ b.Property("SerializedOutputs")
+ .HasColumnType("text");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("text");
+
+ b.Property("StartedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ActivityId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityId");
+
+ b.HasIndex("ActivityName")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityName");
+
+ b.HasIndex("ActivityNodeId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityNodeId");
+
+ b.HasIndex("ActivityType")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityType");
+
+ b.HasIndex("ActivityTypeVersion")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityTypeVersion");
+
+ b.HasIndex("CompletedAt")
+ .HasDatabaseName("IX_ActivityExecutionRecord_CompletedAt");
+
+ b.HasIndex("HasBookmarks")
+ .HasDatabaseName("IX_ActivityExecutionRecord_HasBookmarks");
+
+ b.HasIndex("StartedAt")
+ .HasDatabaseName("IX_ActivityExecutionRecord_StartedAt");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("IX_ActivityExecutionRecord_Status");
+
+ b.HasIndex("WorkflowInstanceId")
+ .HasDatabaseName("IX_ActivityExecutionRecord_WorkflowInstanceId");
+
+ b.HasIndex("ActivityType", "ActivityTypeVersion")
+ .HasDatabaseName("IX_ActivityExecutionRecord_ActivityType_ActivityTypeVersion");
+
+ b.ToTable("ActivityExecutionRecords", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.SerializedKeyValuePair", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SerializedValue")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Key");
+
+ b.ToTable("KeyValuePairs", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredBookmark", b =>
+ {
+ b.Property("BookmarkId")
+ .HasColumnType("text");
+
+ b.Property("ActivityInstanceId")
+ .HasColumnType("text");
+
+ b.Property("ActivityTypeName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CorrelationId")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Hash")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SerializedMetadata")
+ .HasColumnType("text");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("text");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("BookmarkId");
+
+ b.HasIndex(new[] { "ActivityInstanceId" }, "IX_StoredBookmark_ActivityInstanceId");
+
+ b.HasIndex(new[] { "ActivityTypeName" }, "IX_StoredBookmark_ActivityTypeName");
+
+ b.HasIndex(new[] { "ActivityTypeName", "Hash" }, "IX_StoredBookmark_ActivityTypeName_Hash");
+
+ b.HasIndex(new[] { "ActivityTypeName", "Hash", "WorkflowInstanceId" }, "IX_StoredBookmark_ActivityTypeName_Hash_WorkflowInstanceId");
+
+ b.HasIndex(new[] { "CreatedAt" }, "IX_StoredBookmark_CreatedAt");
+
+ b.HasIndex(new[] { "Hash" }, "IX_StoredBookmark_Hash");
+
+ b.HasIndex(new[] { "WorkflowInstanceId" }, "IX_StoredBookmark_WorkflowInstanceId");
+
+ b.ToTable("Bookmarks", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredTrigger", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Hash")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("text");
+
+ b.Property("WorkflowDefinitionId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WorkflowDefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Hash")
+ .HasDatabaseName("IX_StoredTrigger_Hash");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_StoredTrigger_Name");
+
+ b.HasIndex("WorkflowDefinitionId")
+ .HasDatabaseName("IX_StoredTrigger_WorkflowDefinitionId");
+
+ b.HasIndex("WorkflowDefinitionVersionId")
+ .HasDatabaseName("IX_StoredTrigger_WorkflowDefinitionVersionId");
+
+ b.ToTable("Triggers", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.WorkflowExecutionLogRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ActivityId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityInstanceId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityName")
+ .HasColumnType("text");
+
+ b.Property("ActivityNodeId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ActivityTypeVersion")
+ .HasColumnType("integer");
+
+ b.Property("EventName")
+ .HasColumnType("text");
+
+ b.Property("Message")
+ .HasColumnType("text");
+
+ b.Property("ParentActivityInstanceId")
+ .HasColumnType("text");
+
+ b.Property("Sequence")
+ .HasColumnType("bigint");
+
+ b.Property("SerializedActivityState")
+ .HasColumnType("text");
+
+ b.Property("SerializedPayload")
+ .HasColumnType("text");
+
+ b.Property("Source")
+ .HasColumnType("text");
+
+ b.Property("Timestamp")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("WorkflowDefinitionId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WorkflowDefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WorkflowInstanceId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WorkflowVersion")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ActivityId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityId");
+
+ b.HasIndex("ActivityInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityInstanceId");
+
+ b.HasIndex("ActivityName")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityName");
+
+ b.HasIndex("ActivityNodeId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityNodeId");
+
+ b.HasIndex("ActivityType")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityType");
+
+ b.HasIndex("ActivityTypeVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityTypeVersion");
+
+ b.HasIndex("EventName")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_EventName");
+
+ b.HasIndex("ParentActivityInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ParentActivityInstanceId");
+
+ b.HasIndex("Sequence")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Sequence");
+
+ b.HasIndex("Timestamp")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Timestamp");
+
+ b.HasIndex("WorkflowDefinitionId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowDefinitionId");
+
+ b.HasIndex("WorkflowDefinitionVersionId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowDefinitionVersionId");
+
+ b.HasIndex("WorkflowInstanceId")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowInstanceId");
+
+ b.HasIndex("WorkflowVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_WorkflowVersion");
+
+ b.HasIndex("ActivityType", "ActivityTypeVersion")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_ActivityType_ActivityTypeVersion");
+
+ b.HasIndex("Timestamp", "Sequence")
+ .HasDatabaseName("IX_WorkflowExecutionLogRecord_Timestamp_Sequence");
+
+ b.ToTable("WorkflowExecutionLogRecords", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.WorkflowInboxMessage", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ActivityInstanceId")
+ .HasColumnType("text");
+
+ b.Property("ActivityTypeName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CorrelationId")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Hash")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SerializedBookmarkPayload")
+ .HasColumnType("text");
+
+ b.Property("SerializedInput")
+ .HasColumnType("text");
+
+ b.Property("WorkflowInstanceId")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex(new[] { "ActivityInstanceId" }, "IX_WorkflowInboxMessage_ActivityInstanceId");
+
+ b.HasIndex(new[] { "ActivityTypeName" }, "IX_WorkflowInboxMessage_ActivityTypeName");
+
+ b.HasIndex(new[] { "CorrelationId" }, "IX_WorkflowInboxMessage_CorrelationId");
+
+ b.HasIndex(new[] { "CreatedAt" }, "IX_WorkflowInboxMessage_CreatedAt");
+
+ b.HasIndex(new[] { "ExpiresAt" }, "IX_WorkflowInboxMessage_ExpiresAt");
+
+ b.HasIndex(new[] { "Hash" }, "IX_WorkflowInboxMessage_Hash");
+
+ b.HasIndex(new[] { "WorkflowInstanceId" }, "IX_WorkflowInboxMessage_WorkflowInstanceId");
+
+ b.ToTable("WorkflowInboxMessages", "Elsa");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.cs
new file mode 100644
index 000000000..4e6f1ff59
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/20240202095953_AddKeyValueStore.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.PostgreSql.Migrations.Runtime
+{
+ ///
+ public partial class AddKeyValueStore : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "KeyValuePairs",
+ schema: "Elsa",
+ columns: table => new
+ {
+ Key = table.Column(type: "text", nullable: false),
+ SerializedValue = table.Column(type: "text", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_KeyValuePairs", x => x.Key);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "KeyValuePairs",
+ schema: "Elsa");
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
index fed171fef..61f543a75 100644
--- a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Migrations/Runtime/RuntimeElsaDbContextModelSnapshot.cs
@@ -18,7 +18,7 @@ namespace Elsa.EntityFrameworkCore.PostgreSql.Migrations.Runtime
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Elsa")
- .HasAnnotation("ProductVersion", "7.0.11")
+ .HasAnnotation("ProductVersion", "7.0.14")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -113,6 +113,26 @@ namespace Elsa.EntityFrameworkCore.PostgreSql.Migrations.Runtime
b.ToTable("ActivityExecutionRecords", "Elsa");
});
+ modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.SerializedKeyValuePair", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SerializedValue")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Key");
+
+ b.ToTable("KeyValuePairs", "Elsa");
+ });
+
modelBuilder.Entity("Elsa.Workflows.Runtime.Entities.StoredBookmark", b =>
{
b.Property("BookmarkId")
diff --git a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
index 29d7599be..defa876d8 100644
--- a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
@@ -18,7 +18,7 @@ namespace Elsa.EntityFrameworkCore.SqlServer.Migrations.Management
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Elsa")
- .HasAnnotation("ProductVersion", "7.0.11")
+ .HasAnnotation("ProductVersion", "7.0.14")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
diff --git a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.Designer.cs b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.Designer.cs
new file mode 100644
index 000000000..5d7d27d93
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.Designer.cs
@@ -0,0 +1,196 @@
+//
+using System;
+using Elsa.EntityFrameworkCore.Modules.Management;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.SqlServer.Migrations.Runtime
+{
+ [DbContext(typeof(ManagementElsaDbContext))]
+ [Migration("20240202100123_AddKeyValueStore")]
+ partial class AddKeyValueStore
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("Elsa")
+ .HasAnnotation("ProductVersion", "7.0.14")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Elsa.Workflows.Management.Entities.WorkflowDefinition", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("BinaryData")
+ .HasColumnType("varbinary(max)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("Data")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DefinitionId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Description")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("IsLatest")
+ .HasColumnType("bit");
+
+ b.Property("IsPublished")
+ .HasColumnType("bit");
+
+ b.Property("IsReadonly")
+ .HasColumnType("bit");
+
+ b.Property("MaterializerContext")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("MaterializerName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("ProviderName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("StringData")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ToolVersion")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UsableAsActivity")
+ .HasColumnType("bit");
+
+ b.Property("Version")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IsLatest")
+ .HasDatabaseName("IX_WorkflowDefinition_IsLatest");
+
+ b.HasIndex("IsPublished")
+ .HasDatabaseName("IX_WorkflowDefinition_IsPublished");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_WorkflowDefinition_Name");
+
+ b.HasIndex("UsableAsActivity")
+ .HasDatabaseName("IX_WorkflowDefinition_UsableAsActivity");
+
+ b.HasIndex("Version")
+ .HasDatabaseName("IX_WorkflowDefinition_Version");
+
+ b.HasIndex("DefinitionId", "Version")
+ .IsUnique()
+ .HasDatabaseName("IX_WorkflowDefinition_DefinitionId_Version");
+
+ b.ToTable("WorkflowDefinitions", "Elsa");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Management.Entities.WorkflowInstance", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("CorrelationId")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("Data")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DefinitionId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("DefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("FinishedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("IncidentCount")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("SubStatus")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("Version")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CorrelationId")
+ .HasDatabaseName("IX_WorkflowInstance_CorrelationId");
+
+ b.HasIndex("CreatedAt")
+ .HasDatabaseName("IX_WorkflowInstance_CreatedAt");
+
+ b.HasIndex("DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_DefinitionId");
+
+ b.HasIndex("FinishedAt")
+ .HasDatabaseName("IX_WorkflowInstance_FinishedAt");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_WorkflowInstance_Name");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("IX_WorkflowInstance_Status");
+
+ b.HasIndex("SubStatus")
+ .HasDatabaseName("IX_WorkflowInstance_SubStatus");
+
+ b.HasIndex("UpdatedAt")
+ .HasDatabaseName("IX_WorkflowInstance_UpdatedAt");
+
+ b.HasIndex("Status", "DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_Status_DefinitionId");
+
+ b.HasIndex("Status", "SubStatus")
+ .HasDatabaseName("IX_WorkflowInstance_Status_SubStatus");
+
+ b.HasIndex("SubStatus", "DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_SubStatus_DefinitionId");
+
+ b.HasIndex("Status", "SubStatus", "DefinitionId", "Version")
+ .HasDatabaseName("IX_WorkflowInstance_Status_SubStatus_DefinitionId_Version");
+
+ b.ToTable("WorkflowInstances", "Elsa");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.cs b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.cs
new file mode 100644
index 000000000..d76ed03a7
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Migrations/Runtime/20240202100123_AddKeyValueStore.cs
@@ -0,0 +1,22 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.SqlServer.Migrations.Runtime
+{
+ ///
+ public partial class AddKeyValueStore : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
index 5fcd8c784..22d9a56aa 100644
--- a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Management/ManagementElsaDbContextModelSnapshot.cs
@@ -15,7 +15,7 @@ namespace Elsa.EntityFrameworkCore.Sqlite.Migrations.Management
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "7.0.11");
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.14");
modelBuilder.Entity("Elsa.Workflows.Management.Entities.WorkflowDefinition", b =>
{
diff --git a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.Designer.cs b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.Designer.cs
new file mode 100644
index 000000000..2370a6707
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.Designer.cs
@@ -0,0 +1,193 @@
+//
+using System;
+using Elsa.EntityFrameworkCore.Modules.Management;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.Sqlite.Migrations.Runtime
+{
+ [DbContext(typeof(ManagementElsaDbContext))]
+ [Migration("20240202100045_AddKeyValueStore")]
+ partial class AddKeyValueStore
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.14");
+
+ modelBuilder.Entity("Elsa.Workflows.Management.Entities.WorkflowDefinition", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("TEXT");
+
+ b.Property("BinaryData")
+ .HasColumnType("BLOB");
+
+ b.Property("CreatedAt")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Data")
+ .HasColumnType("TEXT");
+
+ b.Property("DefinitionId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("IsLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsPublished")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsReadonly")
+ .HasColumnType("INTEGER");
+
+ b.Property("MaterializerContext")
+ .HasColumnType("TEXT");
+
+ b.Property("MaterializerName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("ProviderName")
+ .HasColumnType("TEXT");
+
+ b.Property("StringData")
+ .HasColumnType("TEXT");
+
+ b.Property("ToolVersion")
+ .HasColumnType("TEXT");
+
+ b.Property("UsableAsActivity")
+ .HasColumnType("INTEGER");
+
+ b.Property("Version")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IsLatest")
+ .HasDatabaseName("IX_WorkflowDefinition_IsLatest");
+
+ b.HasIndex("IsPublished")
+ .HasDatabaseName("IX_WorkflowDefinition_IsPublished");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_WorkflowDefinition_Name");
+
+ b.HasIndex("UsableAsActivity")
+ .HasDatabaseName("IX_WorkflowDefinition_UsableAsActivity");
+
+ b.HasIndex("Version")
+ .HasDatabaseName("IX_WorkflowDefinition_Version");
+
+ b.HasIndex("DefinitionId", "Version")
+ .IsUnique()
+ .HasDatabaseName("IX_WorkflowDefinition_DefinitionId_Version");
+
+ b.ToTable("WorkflowDefinitions");
+ });
+
+ modelBuilder.Entity("Elsa.Workflows.Management.Entities.WorkflowInstance", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("TEXT");
+
+ b.Property("CorrelationId")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedAt")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Data")
+ .HasColumnType("TEXT");
+
+ b.Property("DefinitionId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("DefinitionVersionId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FinishedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("IncidentCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("SubStatus")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UpdatedAt")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Version")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CorrelationId")
+ .HasDatabaseName("IX_WorkflowInstance_CorrelationId");
+
+ b.HasIndex("CreatedAt")
+ .HasDatabaseName("IX_WorkflowInstance_CreatedAt");
+
+ b.HasIndex("DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_DefinitionId");
+
+ b.HasIndex("FinishedAt")
+ .HasDatabaseName("IX_WorkflowInstance_FinishedAt");
+
+ b.HasIndex("Name")
+ .HasDatabaseName("IX_WorkflowInstance_Name");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("IX_WorkflowInstance_Status");
+
+ b.HasIndex("SubStatus")
+ .HasDatabaseName("IX_WorkflowInstance_SubStatus");
+
+ b.HasIndex("UpdatedAt")
+ .HasDatabaseName("IX_WorkflowInstance_UpdatedAt");
+
+ b.HasIndex("Status", "DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_Status_DefinitionId");
+
+ b.HasIndex("Status", "SubStatus")
+ .HasDatabaseName("IX_WorkflowInstance_Status_SubStatus");
+
+ b.HasIndex("SubStatus", "DefinitionId")
+ .HasDatabaseName("IX_WorkflowInstance_SubStatus_DefinitionId");
+
+ b.HasIndex("Status", "SubStatus", "DefinitionId", "Version")
+ .HasDatabaseName("IX_WorkflowInstance_Status_SubStatus_DefinitionId_Version");
+
+ b.ToTable("WorkflowInstances");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.cs b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.cs
new file mode 100644
index 000000000..1c17505c2
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Migrations/Runtime/20240202100045_AddKeyValueStore.cs
@@ -0,0 +1,22 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Elsa.EntityFrameworkCore.Sqlite.Migrations.Runtime
+{
+ ///
+ public partial class AddKeyValueStore : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/Configurations.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/Configurations.cs
index 0691c0678..edc79a0e9 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/Configurations.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/Configurations.cs
@@ -12,7 +12,8 @@ public class Configurations :
IEntityTypeConfiguration,
IEntityTypeConfiguration,
IEntityTypeConfiguration,
- IEntityTypeConfiguration
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration
{
///
public void Configure(EntityTypeBuilder builder)
@@ -109,4 +110,10 @@ public class Configurations :
builder.HasIndex(x => x.CreatedAt, $"IX_{nameof(WorkflowInboxMessage)}_{nameof(WorkflowInboxMessage.CreatedAt)}");
builder.HasIndex(x => x.ExpiresAt, $"IX_{nameof(WorkflowInboxMessage)}_{nameof(WorkflowInboxMessage.ExpiresAt)}");
}
+
+ ///
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(x => x.Key);
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/DbContext.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/DbContext.cs
index 650137b36..3e229cae7 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/DbContext.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/DbContext.cs
@@ -38,6 +38,11 @@ public class RuntimeElsaDbContext : ElsaDbContextBase
/// The workflow inbox messages.
///
public DbSet WorkflowInboxMessages { get; set; } = default!;
+
+ ///
+ /// The generic key value pairs.
+ ///
+ public DbSet KeyValuePairs { get; set; } = default!;
///
protected override void ApplyEntityConfigurations(ModelBuilder modelBuilder)
@@ -48,6 +53,7 @@ public class RuntimeElsaDbContext : ElsaDbContextBase
modelBuilder.ApplyConfiguration(config);
modelBuilder.ApplyConfiguration(config);
modelBuilder.ApplyConfiguration(config);
+ modelBuilder.ApplyConfiguration(config);
}
///
@@ -71,5 +77,7 @@ public class RuntimeElsaDbContext : ElsaDbContextBase
modelBuilder.Entity().Property("SerializedInput").HasColumnType("NCLOB");
modelBuilder.Entity().Property("SerializedBookmarkPayload").HasColumnType("NCLOB");
+
+ modelBuilder.Entity().Property("Value").HasColumnType("NCLOB");
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/KeyValueStore.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/KeyValueStore.cs
new file mode 100644
index 000000000..ee692344b
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/KeyValueStore.cs
@@ -0,0 +1,36 @@
+using Elsa.EntityFrameworkCore.Common;
+using Elsa.Workflows.Runtime.Contracts;
+using Elsa.Workflows.Runtime.Entities;
+
+namespace Elsa.EntityFrameworkCore.Modules.Runtime;
+
+///
+/// Entity Framework implementation of the
+///
+public class EFCoreKeyValueStore : IKeyValueStore
+{
+ private readonly Store _store;
+
+ public EFCoreKeyValueStore(Store store)
+ {
+ _store = store;
+ }
+
+ ///
+ public Task SaveAsync(SerializedKeyValuePair keyValuePair, CancellationToken cancellationToken)
+ {
+ return _store.SaveAsync(keyValuePair, x => x.Key, cancellationToken);
+ }
+
+ ///
+ public Task GetValue(string key, CancellationToken cancellationToken)
+ {
+ return _store.FindAsync(x => x.Key == key, cancellationToken);
+ }
+
+ ///
+ public Task DeleteAsync(string key, CancellationToken cancellationToken)
+ {
+ return _store.DeleteWhereAsync(x => x.Key == key, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
index 5c019e4f2..0543af3c4 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
@@ -28,6 +28,7 @@ public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase sp.GetRequiredService();
feature.WorkflowExecutionLogStore = sp => sp.GetRequiredService();
feature.ActivityExecutionLogStore = sp => sp.GetRequiredService();
+ feature.KeyValueStore = sp => sp.GetRequiredService();
});
}
@@ -41,5 +42,6 @@ public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase();
AddEntityStore();
AddEntityStore();
+ AddStore();
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.MongoDb/Modules/Runtime/CreateIndices.cs b/src/modules/Elsa.MongoDb/Modules/Runtime/CreateIndices.cs
index e3752ee16..2c79b087e 100644
--- a/src/modules/Elsa.MongoDb/Modules/Runtime/CreateIndices.cs
+++ b/src/modules/Elsa.MongoDb/Modules/Runtime/CreateIndices.cs
@@ -1,3 +1,4 @@
+using Elsa.Common.Entities;
using Elsa.MongoDb.Helpers;
using Elsa.Workflows.Runtime.Entities;
using Elsa.Workflows.State;
@@ -23,7 +24,8 @@ internal class CreateIndices : IHostedService
CreateActivityExecutionLogIndices(cancellationToken),
CreateWorkflowBookmarkIndices(cancellationToken),
CreateWorkflowTriggerIndices(cancellationToken),
- CreateWorkflowInboxIndices(cancellationToken)
+ CreateWorkflowInboxIndices(cancellationToken),
+ CreateKeyValueIndices(cancellationToken)
);
}
@@ -181,4 +183,20 @@ internal class CreateIndices : IHostedService
},
cancellationToken));
}
+
+ private Task CreateKeyValueIndices(CancellationToken cancellationToken)
+ {
+ var keyValuePairCollection = _serviceProvider.GetService>();
+ if (keyValuePairCollection == null) return Task.CompletedTask;
+
+ return IndexHelpers.CreateAsync(
+ keyValuePairCollection,
+ async (collection, indexBuilder) =>
+ await collection.Indexes.CreateManyAsync(
+ new List>
+ {
+ new(indexBuilder.Ascending(x => x.Key))
+ },
+ cancellationToken));
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.MongoDb/Modules/Runtime/KeyValueStore.cs b/src/modules/Elsa.MongoDb/Modules/Runtime/KeyValueStore.cs
new file mode 100644
index 000000000..14b409606
--- /dev/null
+++ b/src/modules/Elsa.MongoDb/Modules/Runtime/KeyValueStore.cs
@@ -0,0 +1,39 @@
+using Elsa.MongoDb.Common;
+using Elsa.Workflows.Runtime.Contracts;
+using Elsa.Workflows.Runtime.Entities;
+
+namespace Elsa.MongoDb.Modules.Runtime;
+
+///
+/// A MongoDB based store for s.
+///
+public class MongoKeyValueStore : IKeyValueStore
+{
+ private readonly MongoDbStore _keyValueMongoDbStore;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MongoKeyValueStore(MongoDbStore keyValueMongoDbStore)
+ {
+ _keyValueMongoDbStore = keyValueMongoDbStore;
+ }
+
+ ///
+ public Task SaveAsync(SerializedKeyValuePair keyValuePair, CancellationToken cancellationToken)
+ {
+ return _keyValueMongoDbStore.SaveAsync(keyValuePair, cancellationToken);
+ }
+
+ ///
+ public Task GetValue(string key, CancellationToken cancellationToken)
+ {
+ return _keyValueMongoDbStore.FindAsync(x => x.Key == key, cancellationToken);
+ }
+
+ ///
+ public Task DeleteAsync(string key, CancellationToken cancellationToken)
+ {
+ return _keyValueMongoDbStore.DeleteWhereAsync(x => x.Key == key, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.MongoDb/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs b/src/modules/Elsa.MongoDb/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
index a7af08291..671b94393 100644
--- a/src/modules/Elsa.MongoDb/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
+++ b/src/modules/Elsa.MongoDb/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
@@ -1,3 +1,4 @@
+using Elsa.Common.Entities;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.MongoDb.Common;
@@ -28,6 +29,7 @@ public class MongoWorkflowRuntimePersistenceFeature : PersistenceFeatureBase
feature.WorkflowExecutionLogStore = sp => sp.GetRequiredService();
feature.ActivityExecutionLogStore = sp => sp.GetRequiredService();
feature.WorkflowInboxStore = sp => sp.GetRequiredService();
+ feature.KeyValueStore = sp => sp.GetRequiredService