Merge remote-tracking branch 'origin/patch/3.2.x'

This commit is contained in:
Sipke Schoorstra 2024-08-30 12:23:38 +02:00
commit 9e421a166d
12 changed files with 32 additions and 99 deletions

View file

@ -74,11 +74,12 @@ public class AlterationContext
/// <summary>
/// Logs a message.
/// </summary>
/// <param name="eventName">The event name to log.</param>
/// <param name="message">The message to log.</param>
/// <param name="logLevel">The log level.</param>
public void Log(string message, LogLevel logLevel = LogLevel.Information)
public void Log(string eventName, string message, LogLevel logLevel = LogLevel.Information)
{
AlterationLog.Add(message, logLevel);
AlterationLog.Add(message, logLevel, eventName);
}
/// <summary>
@ -104,7 +105,7 @@ public class AlterationContext
public void Succeed(string message)
{
HasSucceeded = true;
Log(message, LogLevel.Information);
Log($"Alteration {Alteration.GetType().Name} succeeded", message, LogLevel.Information);
}
/// <summary>
@ -123,6 +124,6 @@ public class AlterationContext
public void Fail(string? message = default)
{
HasFailed = true;
Log(message ?? $"{Alteration.GetType().Name} failed", LogLevel.Error);
Log($"Alteration {Alteration.GetType().Name} failed", message ?? $"{Alteration.GetType().Name} failed", LogLevel.Error);
}
}

View file

@ -24,15 +24,16 @@ public class AlterationLog
/// Gets the log entries.
/// </summary>
public IReadOnlyCollection<AlterationLogEntry> LogEntries => _logEntries.ToList().AsReadOnly();
/// <summary>
/// Adds a log entry.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="logLevel">The log level.</param>
public void Add(string message, LogLevel logLevel = LogLevel.Information)
/// <param name="eventName">The event that generated the log entry.</param>
public void Add(string message, LogLevel logLevel = LogLevel.Information, string? eventName = null)
{
var entry = new AlterationLogEntry(message, logLevel, _systemClock.UtcNow);
var entry = new AlterationLogEntry(message, logLevel, _systemClock.UtcNow, eventName);
_logEntries.Add(entry);
}

View file

@ -8,4 +8,5 @@ namespace Elsa.Alterations.Core.Models;
/// <param name="Message">The log message.</param>
/// <param name="LogLevel">The log level.</param>
/// <param name="Timestamp">The timestamp when the log entry was created.</param>
public record AlterationLogEntry(string Message, LogLevel LogLevel, DateTimeOffset Timestamp);
/// <param name="EventName">The event that generated the log entry.</param>
public record AlterationLogEntry(string Message, LogLevel LogLevel, DateTimeOffset Timestamp, string? EventName = null);

View file

@ -50,5 +50,9 @@ internal class RunAlterationsMiddleware(WorkflowMiddlewareDelegate next, IEnumer
// Execute commit handlers.
foreach (var commitAction in commitActions)
await commitAction();
// Add alteration logs to the workflow execution log.
foreach (var alterationLogEntry in log.LogEntries)
workflowExecutionContext.AddExecutionLogEntry(alterationLogEntry.EventName ?? alterationLogEntry.Message, alterationLogEntry.Message);
}
}

View file

@ -20,8 +20,9 @@ public class DbExceptionTransformer : IDbExceptionHandler<AlterationsElsaDbConte
/// Transforms database exceptions encountered when using a postgreSQL database into more generic exceptions.
public void Handle(DbUpdateException exception)
{
var ex = exception.InnerException as PostgresException;
if (exception.InnerException is PostgresException { SqlState: "23505" })
throw new UniqueKeyConstraintViolationException("Unable to save data", exception);
throw new DataProcessingException(ex?.SqlState == "23505", "Unable to save data", exception);
throw new DataProcessingException("Unable to save data", exception);
}
}

View file

@ -1,59 +0,0 @@
using System.Collections;
using Elsa.Extensions;
using Jint;
using Jint.Native;
using Jint.Native.Object;
using Jint.Runtime.Descriptors;
namespace Elsa.JavaScript.Helpers;
internal static class ConverterHelper
{
public static ObjectInstance ConvertToJsObject(Engine engine, IDictionary<string, object?> expando)
{
var jsObject = engine.Intrinsics.Object.Construct([]);
foreach (var kvp in expando)
{
var value = kvp.Value;
var jsValue = ConvertToJsValue(engine, value);
var propertyDescriptor = new PropertyDescriptor(jsValue, true, true, true);
jsObject.DefineOwnProperty(kvp.Key, propertyDescriptor);
}
return jsObject;
}
private static JsValue ConvertToJsValue(Engine engine, object? value)
{
if (value == null)
return JsValue.Null;
if (value is IDictionary<string, object?> dict)
return ConvertToJsObject(engine, dict);
var valueType = value.GetType();
if (valueType.IsCollectionType())
{
var list = (ICollection)value;
var jsArray = engine.Intrinsics.Array.Construct(list.Count);
var index = 0;
foreach (var item in list)
jsArray.Set(index++, ConvertToJsValue(engine, item), true);
return jsArray;
}
if (value is string str)
return JsValue.FromObject(engine, str);
if (value is int or double or float or decimal)
return JsValue.FromObject(engine, Convert.ToDouble(value));
if (value is bool b)
return JsValue.FromObject(engine, b);
return JsValue.FromObject(engine, value);
}
}

View file

@ -1,22 +0,0 @@
using System.Dynamic;
using Elsa.JavaScript.Helpers;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;
namespace Elsa.JavaScript.ObjectConverters;
internal class ExpandoObjectConverter : IObjectConverter
{
public bool TryConvert(Engine engine, object value, out JsValue result)
{
if (value is ExpandoObject expandoObject)
{
result = ConverterHelper.ConvertToJsObject(engine, expandoObject);
return true;
}
result = JsValue.Null;
return false;
}
}

View file

@ -90,7 +90,7 @@ public class JintJavaScriptEvaluator(IConfiguration configuration, INotification
private void ConfigureObjectConverters(Jint.Options options)
{
options.Interop.ObjectConverters.AddRange([new ByteArrayConverter(), new ExpandoObjectConverter()]);
options.Interop.ObjectConverters.AddRange([new ByteArrayConverter()]);
}
private void ConfigureArgumentGetters(Engine engine, ExpressionEvaluatorOptions options)

View file

@ -43,6 +43,10 @@ public class MongoDbStore<TDocument>(IMongoCollection<TDocument> collection, ITe
public async Task AddManyAsync(IEnumerable<TDocument> documents, CancellationToken cancellationToken = default)
{
var documentsList = documents.ToList();
if (!documentsList.Any())
return;
await ApplyTenantIdAsync(documentsList, cancellationToken);
await collection.InsertManyAsync(documentsList, new InsertManyOptions(), cancellationToken);
}

View file

@ -1,8 +1,4 @@
namespace Elsa.Workflows.Exceptions;
/// An exception that occurs during data processing.
public class DataProcessingException(bool isUkViolation, string message, Exception exception) : Exception(message, exception)
{
/// Gets a value indicating whether the exception is a Unique Key violation.
public bool IsUkViolation { get; } = isUkViolation;
}
public class DataProcessingException(string message, Exception exception) : Exception(message, exception);

View file

@ -0,0 +1,4 @@
namespace Elsa.Workflows.Exceptions;
/// An exception that when a unique key constraint has been violated.
public class UniqueKeyConstraintViolationException(string message, Exception exception) : Exception(message, exception);

View file

@ -79,9 +79,11 @@ public class Tests
Assert.Equal(43, magicNumber);
}
[Theory(DisplayName = "Can sort array and list properties as mutable arrays")]
[Theory(DisplayName = "Can sort array and list properties as mutable arrays", Skip = "Not supported yet. See https://github.com/elsa-workflows/elsa-core/issues/5912")]
[MemberData(nameof(ArraySortEnumerableData))]
// See also: https://github.com/sebastienros/jint/issues/1942
// See also:
// - https://github.com/sebastienros/jint/issues/1942
// - https://github.com/elsa-workflows/elsa-core/issues/5912
public async Task Test5(IEnumerable<double> collection)
{
dynamic dynamicObject = new ExpandoObject();