Add project files.

This commit is contained in:
2025-08-18 17:11:43 +03:30
parent 807dc263be
commit e5eb10d604
3943 changed files with 223719 additions and 0 deletions
@@ -0,0 +1,36 @@
using Elsa.Sql.Client;
namespace Elsa.Sql.Services;
public class ClientStore
{
private readonly Dictionary<string, Type> clients = new();
/// <summary>
/// Dictionary of registered clients and their type.
/// </summary>
public IReadOnlyDictionary<string, Type> Clients => clients;
/// <summary>
/// Registers the specified client type <typeparamref name="TClient"/> with the store.
/// The client type must inherit from <see cref="ISqlClient"/>.
/// </summary>
/// <typeparam name="TClient">
/// The type of the client to be registered. The client must be a class that implements the <see cref="ISqlClient"/> interface.
/// </typeparam>
/// <param name="name">
/// The name of the client to register. If not provided, the name defaults to <c>nameof(TClient)</c>.
/// This value is used as a key to identify the client in the store.
/// </param>
/// <exception cref="InvalidOperationException">
/// Thrown when a client with the same name is already registered in the store.
/// </exception>
/// <remarks>
/// This method registers a client type to the store using a unique key. The key is either the provided <paramref name="name"/> or the default name derived from <typeparamref name="TClient"/>.
/// </remarks>
public void Register<TClient>(string? name) where TClient : class, ISqlClient
{
var key = string.IsNullOrEmpty(name) ? nameof(TClient) : name;
if (clients.ContainsKey(key)) { throw new InvalidOperationException($"Client with key '{name}' is already registered."); }
clients.Add(key, typeof(TClient));
}
}
@@ -0,0 +1,94 @@
using System.Text;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Sql.Contracts;
using Elsa.Sql.Models;
using Elsa.Workflows;
namespace Elsa.Sql.Services;
/// <summary>
/// A SQL expression evaluator.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="SqlEvaluator"/> class.WS
/// </remarks>
public class SqlEvaluator() : ISqlEvaluator
{
private WorkflowExecutionContext executionContext;
private ActivityExecutionContext activityContext;
private ExpressionExecutionContext expressionContext;
/// <inheritdoc />
public async Task<EvaluatedQuery> EvaluateAsync(
string expression,
ExpressionExecutionContext context,
ExpressionEvaluatorOptions options,
CancellationToken cancellationToken = default)
{
if (!expression.Contains("{{")) return new EvaluatedQuery(expression);
expressionContext = context;
executionContext = context.GetWorkflowExecutionContext();
activityContext = context.GetActivityExecutionContext();
// Create client
var factory = context.GetRequiredService<ISqlClientFactory>();
var client = factory.CreateClient(activityContext.ActivityState["Client"].ToString(), activityContext.ActivityState["ConnectionString"].ToString());
var sb = new StringBuilder();
int start = 0;
var parameters = new Dictionary<string, object?>();
int paramIndex = 0;
while (start < expression.Length)
{
int openIndex = expression.IndexOf("{{", start);
if (openIndex == -1)
{
sb.Append(expression.AsSpan(start));
break;
}
// Append everything before {{
sb.Append(expression.AsSpan(start, openIndex - start));
// Find the closing }}
int closeIndex = expression.IndexOf("}}", openIndex + 2);
if (closeIndex == -1) throw new FormatException("Unmatched '{{' found in SQL expression.");
// Extract key
string key = expression.Substring(openIndex + 2, closeIndex - openIndex - 2).Trim();
if (string.IsNullOrEmpty(key)) throw new FormatException("Empty placeholder '{{}}' is not allowed.");
// Resolve value and replace with parameterized name
var counterValue = client.IncrementParameter ? paramIndex++.ToString() : string.Empty;
string paramName = $"{client.ParameterMarker}{client.ParameterText}{counterValue}";
parameters[paramName] = ResolveValue(key);
sb.Append(paramName);
start = closeIndex + 2;
}
return new EvaluatedQuery(sb.ToString(), parameters);
}
private object? ResolveValue(string key)
{
return key switch
{
"Workflow.Definition.Id" => executionContext.Workflow.Identity.DefinitionId,
"Workflow.Definition.Version.Id" => executionContext.Workflow.Identity.Id,
"Workflow.Definition.Version" => executionContext.Workflow.Identity.Version,
"Workflow.Instance.Id" => activityContext.WorkflowExecutionContext.Id,
"Correlation.Id" => activityContext.WorkflowExecutionContext.CorrelationId,
"LastResult" => expressionContext.GetLastResult(),
var i when i.StartsWith("Input.") => executionContext.Input.TryGetValue(i.Substring(6), out var v) ? v : null,
var o when o.StartsWith("Output.") => executionContext.Output.TryGetValue(o.Substring(7), out var v) ? v : null,
var v when v.StartsWith("Variable.") => expressionContext.GetVariableInScope(v.Substring(9)) ?? null,
// OBSOLETE: This is deprecated and will be removed in a future version. Use 'Variable.' instead.
var v when v.StartsWith("Variables.") => expressionContext.GetVariableInScope(v.Substring(10)) ?? null,
_ => throw new NullReferenceException($"No matching property found for {{{{{key}}}}}.")
};
}
}