using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore.Metadata.Internal; using System.Data; using System.Text; namespace ReC.Application.Common.Procedures; internal sealed class StoredProcedureBuilder(string procedureName, string? returnVariable = null) { private readonly StringBuilder _execSql = returnVariable is not null ? new StringBuilder($"EXEC @{returnVariable} = {procedureName}") : new StringBuilder($"EXEC {procedureName}"); private readonly List _parameters = []; private char _separator = ' '; public StoredProcedureBuilder Add(string name, object? value, SqlDbType? dbType = null) { if (value is null) return this; _execSql.AppendLine($"{_separator}@{name} = @{name}"); _separator = ','; if (!dbType.HasValue && value is DateTime) dbType = SqlDbType.DateTime; if (dbType.HasValue) _parameters.Add(new SqlParameter($"@{name}", dbType.Value) { Value = value }); else _parameters.Add(new SqlParameter($"@{name}", value)); return this; } public StoredProcedureBuilder Add(string name, EntityType entityType) { var entityTypeStr = entityType switch { EntityType.Action => "ACTION", EntityType.Endpoint => "ENDPOINT", EntityType.EndpointAuth => "ENDPOINT_AUTH", EntityType.EndpointParams => "ENDPOINT_PARAMS", EntityType.Profile => "PROFILE", EntityType.Result => "RESULT", _ => throw new ArgumentOutOfRangeException(nameof(entityType), $"Not expected entity type value: {entityType}") }; return Add(name, entityTypeStr); } public StoredProcedureBuilder AddOutput(string name, SqlDbType dbType) { _execSql.AppendLine($"{_separator}@{name} = @{name} OUTPUT"); _separator = ','; _parameters.Add(new SqlParameter { ParameterName = $"@{name}", SqlDbType = dbType, Direction = ParameterDirection.Output }); return this; } public string BuildSql() { if (returnVariable is null) return _execSql.ToString(); return new StringBuilder() .AppendLine($"DECLARE @{returnVariable} SMALLINT = 0;") .Append(_execSql).AppendLine(";") .AppendLine($"SELECT @{returnVariable};") .ToString(); } public SqlParameter[] BuildParameters() => [.. _parameters]; public SqlParameter? GetParameter(string name) => _parameters.Find(p => p.ParameterName == $"@{name}"); }