Skip to content

Commit

Permalink
Implement Dynamic Expression Evaluation for Log Persistence Mode (#6159)
Browse files Browse the repository at this point in the history
* Add log persistence configuration and strategy evaluation

Introduced `LogPersistenceConfiguration` to support dynamic strategy and expression-based log persistence evaluations. Updated `Default default values.

* Add LogPersistenceConfiguration and enum support

Introduced LogPersistenceConfiguration class and LogPersistenceEvaluationMode enum in both Elsa.Api.Client and Elsa.Workflows.Runtime. Updated JavaScript services to handle enums correctly and register LogPersistenceMode.

* Rename log persistence key for consistency

Updated the log persistence key from `LogPersistenceStrategyKey` to `LogPersistenceConfigKey` to maintain consistency across the codebase. This change ensures that property access aligns with the updated naming conventions used in the application's configuration.

* Reuse JSON serializer options

* Update log persistence config structure in comments

This commit revises the JSON example in code comments to reflect the updated structure of the log persistence configuration. The changes include updated evaluation modes and strategy types for default, inputs, and outputs sections. These modifications aim to enhance clarity and provide accurate documentation of the expected configuration format.
  • Loading branch information
sfmskywalker authored Nov 28, 2024
1 parent f8fb715 commit 0863247
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Elsa.Api.Client.Shared.Enums;

public enum LogPersistenceEvaluationMode
{
Strategy,
Expression
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Elsa.Api.Client.Resources.Scripting.Models;
using Elsa.Api.Client.Shared.Enums;

namespace Elsa.Api.Client.Shared.Models;

public class LogPersistenceConfiguration
{
public LogPersistenceEvaluationMode EvaluationMode { get; set; }
public string? StrategyType { get; set; }
public Expression? Expression { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Elsa.Extensions;
using Elsa.JavaScript.Notifications;
using Elsa.Mediator.Contracts;
using Elsa.Workflows.LogPersistence;
using JetBrains.Annotations;

namespace Elsa.JavaScript.Handlers;
Expand All @@ -22,6 +23,7 @@ public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken can
engine.RegisterType<TimeSpan>();
engine.RegisterType<Guid>();
engine.RegisterType<Random>();
engine.RegisterType<LogPersistenceMode>();

return Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected override IEnumerable<TypeDefinition> GetTypeDefinitions(TypeDefinition
var variableTypeQuery =
from variable in variables
let variableType = variable.GetVariableType()
where (variableType.IsClass || variableType.IsInterface) && !variableType.IsPrimitive && !excludedTypes.Any(x => x(variableType))
where (variableType.IsClass || variableType.IsInterface || variableType.IsEnum) && !variableType.IsPrimitive && !excludedTypes.Any(x => x(variableType))
select variableType;

var variableTypes = variableTypeQuery.Distinct();
Expand Down
2 changes: 2 additions & 0 deletions src/modules/Elsa.JavaScript/Services/TypeAliasRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Dynamic;
using Elsa.JavaScript.Contracts;
using Elsa.JavaScript.Extensions;
using Elsa.Workflows.LogPersistence;

namespace Elsa.JavaScript.Services;

Expand Down Expand Up @@ -32,6 +33,7 @@ public TypeAliasRegistry()
this.RegisterType<DateOnly>("Date");
this.RegisterType<TimeOnly>("Date");
this.RegisterType<IDictionary<string, object>>("ObjectDictionary");
this.RegisterType<LogPersistenceMode>("LogPersistenceMode");
}

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,25 @@ private void Render(TypeDefinition typeDefinition, StringBuilder output)
{
output.AppendLine($"declare {typeDefinition.DeclarationKeyword} {typeDefinition.Name} {{");

foreach (var property in typeDefinition.Properties)
Render(property, output);

if (typeDefinition.DeclarationKeyword == "enum")
{
foreach (var property in typeDefinition.Properties)
RenderEnumMember(property, output);
}
else
{
foreach (var property in typeDefinition.Properties)
Render(property, output);
}

foreach (var method in typeDefinition.Methods)
RenderMethod(method, output);

output.AppendLine("}");
}

private void Render(PropertyDefinition property, StringBuilder output) => output.AppendLine($"{property.Name}{(property.IsOptional ? "?" : "")}: {property.Type};");
private void RenderEnumMember(PropertyDefinition property, StringBuilder output) => output.AppendLine($"{property.Name} = \"{property.Name}\";");
private void Render(VariableDefinition variable, StringBuilder output) => output.AppendLine($"declare var {variable.Name}: {variable.Type};");
string RenderParameter(ParameterDefinition parameter) => $"{parameter.Name}{(parameter.IsOptional ? "?" : "")}: {parameter.Type}";
string RenderParameters(IEnumerable<ParameterDefinition> parameters) => string.Join(", ", parameters.Select(RenderParameter));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public TypeDefinition DescribeType(Type type)

private IEnumerable<FunctionDefinition> GetMethodDefinitions(Type type)
{
if(type.IsEnum)
yield break;

#pragma warning disable IL2070
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).Where(x => !x.IsSpecialName).ToList();
#pragma warning restore IL2070
Expand Down Expand Up @@ -68,6 +71,22 @@ private IEnumerable<ParameterDefinition> GetMethodParameters(MethodInfo method)

private IEnumerable<PropertyDefinition> GetPropertyDefinitions([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type)
{
// If the type is an enum, enumerate its members.
if (type.IsEnum)
{
foreach (var name in Enum.GetNames(type))
{
yield return new PropertyDefinition
{
Name = name,
Type = "string",
IsOptional = false,
};
}

yield break;
}

var properties = type.GetProperties();

foreach (var property in properties)
Expand All @@ -86,8 +105,8 @@ private static string GetDeclarationKeyword(Type type) =>
{
{ IsInterface: true } => "interface",
{ IsClass: true } => "class",
{ IsValueType: true } => "class",
{ IsEnum: true } => "enum",
{ IsValueType: true, IsEnum: false } => "class",
_ => "interface"
};
}
13 changes: 13 additions & 0 deletions src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ public static class DictionaryExtensions
public static bool TryGetValue<T>(this IDictionary<string, object> dictionary, IEnumerable<string> keys, out T value) => dictionary.TryGetValue<string, T>(keys, out value);
public static bool TryGetValue<T>(this IDictionary<object, object> dictionary, string key, out T value) => dictionary.TryGetValue<object, T>(key, out value);

public static bool TryGetValue<TKey, T>(this IDictionary<TKey, T> dictionary, TKey key, out T value)
{
if (!dictionary.TryGetValue(key, out var item))
{
value = default!;
return false;
}

value = item;
return true;
}

public static bool TryGetValue<TKey, T>(this IDictionary<TKey, object> dictionary, TKey key, out T value)
{
if (!dictionary.TryGetValue(key, out var item))
Expand Down Expand Up @@ -38,6 +50,7 @@ public static bool TryGetValue<TKey, T>(this IDictionary<TKey, object> dictionar

public static T? GetValue<TKey, T>(this IDictionary<TKey, T> dictionary, TKey key) => ConvertValue<T>(dictionary[key]);
public static T? GetValue<T>(this IDictionary<string, object> dictionary, string key) => ConvertValue<T>(dictionary[key]);
public static T? GetValueOrDefault<TKey, T>(this IDictionary<TKey, T> dictionary, TKey key, Func<T?> defaultValueFactory) => TryGetValue(dictionary, key, out var value) ? value : defaultValueFactory();

public static T? GetValueOrDefault<TKey, T>(this IDictionary<TKey, object> dictionary, TKey key, Func<T?> defaultValueFactory) => TryGetValue<TKey, T>(dictionary, key, out var value) ? value : defaultValueFactory();
public static T? GetValueOrDefault<TKey, T>(this IDictionary<TKey, object> dictionary, TKey key) => GetValueOrDefault<TKey, T>(dictionary, key, () => default);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class WorkflowManagementFeature : FeatureBase
private const string LookupsCategory = "Lookups";
private const string DynamicCategory = "Dynamic";
private const string DataCategory = "Data";
private const string SystemCategory = "System";

private string CompressionAlgorithm { get; set; } = nameof(None);
private LogPersistenceMode LogPersistenceMode { get; set; } = LogPersistenceMode.Include;
Expand Down Expand Up @@ -86,7 +87,8 @@ public WorkflowManagementFeature(IModule module) : base(module)
new(typeof(JsonNode), DynamicCategory, "A JSON node for reading and writing a JSON structure."),
new(typeof(JsonObject), DynamicCategory, "A JSON object for reading and writing a JSON structure."),
new(typeof(byte[]), DataCategory, "A byte array."),
new(typeof(Stream), DataCategory, "A stream.")
new(typeof(Stream), DataCategory, "A stream."),
new(typeof(LogPersistenceMode), SystemCategory, "A LogPersistenceMode enum value.")
];

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=contexts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=contracts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=enums/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=requests/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Elsa.Workflows.Runtime;

public enum LogPersistenceEvaluationMode
{
Strategy,
Expression
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Elsa.Expressions.Models;

namespace Elsa.Workflows.Runtime;

public class LogPersistenceConfiguration
{
public LogPersistenceEvaluationMode EvaluationMode { get; set; }
public string? StrategyType { get; set; }
public Expression? Expression { get; set; }
}
Loading

0 comments on commit 0863247

Please sign in to comment.