Compare commits
16 Commits
e96773f3c4
...
b3dfdd1e5c
| Author | SHA1 | Date | |
|---|---|---|---|
| b3dfdd1e5c | |||
| bd78ada686 | |||
| 2b4773a4c0 | |||
| ff7d6c99ae | |||
| fa438e70cb | |||
| 4931d3b8aa | |||
| 6aae26bfb6 | |||
| 38d8ef6e93 | |||
| 7bc5428bd4 | |||
| c405f369ac | |||
| c2e073dade | |||
| 7a11ac3635 | |||
| a91e3264b4 | |||
| 2ae5251550 | |||
| 56730c0d4e | |||
| d8aa032a57 |
@@ -3,7 +3,7 @@ using ReC.Application.Common.Dto;
|
|||||||
using ReC.Application.Common.Interfaces;
|
using ReC.Application.Common.Interfaces;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Behaviors;
|
namespace ReC.Application.Common.Behaviors.Action;
|
||||||
|
|
||||||
public class BodyQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext) : IPipelineBehavior<TRequest, TResponse>
|
public class BodyQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext) : IPipelineBehavior<TRequest, TResponse>
|
||||||
where TRequest : RecActionViewDto
|
where TRequest : RecActionViewDto
|
||||||
@@ -5,7 +5,7 @@ using ReC.Application.Common.Dto;
|
|||||||
using ReC.Application.Common.Interfaces;
|
using ReC.Application.Common.Interfaces;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Behaviors;
|
namespace ReC.Application.Common.Behaviors.Action;
|
||||||
|
|
||||||
public class HeaderQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext, ILogger<HeaderQueryBehavior<TRequest, TResponse>>? logger = null) : IPipelineBehavior<TRequest, TResponse>
|
public class HeaderQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext, ILogger<HeaderQueryBehavior<TRequest, TResponse>>? logger = null) : IPipelineBehavior<TRequest, TResponse>
|
||||||
where TRequest : RecActionViewDto
|
where TRequest : RecActionViewDto
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record ConnectionDto
|
|
||||||
{
|
|
||||||
public short? Id { get; set; }
|
|
||||||
|
|
||||||
public string? Bezeichnung { get; set; }
|
|
||||||
|
|
||||||
public string? SqlProvider { get; set; }
|
|
||||||
|
|
||||||
public string? Server { get; set; }
|
|
||||||
|
|
||||||
public string? Datenbank { get; set; }
|
|
||||||
|
|
||||||
public string? Username { get; set; }
|
|
||||||
|
|
||||||
public string? Password { get; set; }
|
|
||||||
|
|
||||||
public string? Bemerkung { get; set; }
|
|
||||||
|
|
||||||
public bool? Aktiv { get; set; }
|
|
||||||
|
|
||||||
public string? ErstelltWer { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ErstelltWann { get; set; }
|
|
||||||
|
|
||||||
public string? GeandertWer { get; set; }
|
|
||||||
|
|
||||||
public DateTime? GeaendertWann { get; set; }
|
|
||||||
|
|
||||||
public bool? SysConnection { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using ReC.Domain.Views;
|
using ReC.Domain.Views;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
namespace ReC.Application.Common.Dto;
|
||||||
|
|
||||||
@@ -6,7 +6,12 @@ public class DtoMappingProfile : AutoMapper.Profile
|
|||||||
{
|
{
|
||||||
public DtoMappingProfile()
|
public DtoMappingProfile()
|
||||||
{
|
{
|
||||||
CreateMap<RecActionView, RecActionViewDto>();
|
CreateMap<RecActionView, RecActionViewDto>()
|
||||||
|
.ForMember(dest => dest.PreprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||||
|
src.PreprocessingQuery?.ReplacePlaceholders(src, src.Profile)))
|
||||||
|
.ForMember(dest => dest.PostprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||||
|
src.PostprocessingQuery?.ReplacePlaceholders(src, src.Profile)));
|
||||||
|
|
||||||
CreateMap<ResultView, ResultViewDto>();
|
CreateMap<ResultView, ResultViewDto>();
|
||||||
CreateMap<ProfileView, ProfileViewDto>();
|
CreateMap<ProfileView, ProfileViewDto>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record EndpointAuthDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public EndpointAuthType? Type { get; set; }
|
|
||||||
|
|
||||||
public string? ApiKey { get; set; }
|
|
||||||
|
|
||||||
public string? ApiValue { get; set; }
|
|
||||||
|
|
||||||
public ApiKeyLocation? ApiKeyAddTo { get; set; }
|
|
||||||
|
|
||||||
public string? Token { get; set; }
|
|
||||||
|
|
||||||
public string? Username { get; set; }
|
|
||||||
|
|
||||||
public string? Password { get; set; }
|
|
||||||
|
|
||||||
public string? Domain { get; set; }
|
|
||||||
|
|
||||||
public string? Workstation { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record EndpointDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public string? Uri { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the TBREC_CFG_ENDPOINT_PARAMS table.
|
|
||||||
/// All properties are nullable to provide flexibility on the database side,
|
|
||||||
/// preventing breaking changes if columns are altered to be nullable in production.
|
|
||||||
/// </summary>
|
|
||||||
public record EndpointParamDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public short? GroupId { get; set; }
|
|
||||||
|
|
||||||
public byte? Sequence { get; set; }
|
|
||||||
|
|
||||||
public string? Key { get; set; }
|
|
||||||
|
|
||||||
public string? Value { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record OutResDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public long? ActionId { get; set; }
|
|
||||||
|
|
||||||
public RecActionDto? Action { get; set; }
|
|
||||||
|
|
||||||
public long? ProfileId { get; set; }
|
|
||||||
|
|
||||||
public ProfileDto? Profile { get; set; }
|
|
||||||
|
|
||||||
public string? ProfileName { get; set; }
|
|
||||||
|
|
||||||
public short? StatusCode { get; set; }
|
|
||||||
|
|
||||||
public string? StatusName { get; set; }
|
|
||||||
|
|
||||||
public ResultType? Type { get; set; }
|
|
||||||
|
|
||||||
public string? Header { get; set; }
|
|
||||||
|
|
||||||
public string? Body { get; set; }
|
|
||||||
|
|
||||||
public string? Info { get; set; }
|
|
||||||
|
|
||||||
public string? Error { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
63
src/ReC.Application/Common/Dto/PlaceholderExtensions.cs
Normal file
63
src/ReC.Application/Common/Dto/PlaceholderExtensions.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using ReC.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Dto;
|
||||||
|
|
||||||
|
public static partial class PlaceholderExtensions
|
||||||
|
{
|
||||||
|
[GeneratedRegex(@"\{#[^#]+#[^}]+\}")]
|
||||||
|
private static partial Regex PlaceholderRegex();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces placeholders in the format <c>{#ANY_STRING#COLUMN_NAME}</c> with the corresponding
|
||||||
|
/// property value resolved via <see cref="GetValueByColumnName{T}"/> from the provided objects.
|
||||||
|
/// Values are converted to SQL-compatible string representations.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="PlaceholderResolutionException">
|
||||||
|
/// Thrown when a placeholder's column name cannot be resolved from any of the provided objects.
|
||||||
|
/// </exception>
|
||||||
|
public static string ReplacePlaceholders(this string str, params object?[] objects)
|
||||||
|
{
|
||||||
|
return PlaceholderRegex().Replace(str, match =>
|
||||||
|
{
|
||||||
|
var placeholder = match.Value;
|
||||||
|
var inner = placeholder[2..^1]; // remove {# and }
|
||||||
|
var lastHash = inner.LastIndexOf('#');
|
||||||
|
var columnName = inner[(lastHash + 1)..];
|
||||||
|
|
||||||
|
foreach (var obj in objects)
|
||||||
|
{
|
||||||
|
if (obj is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var value = obj.GetValueByColumnName(columnName);
|
||||||
|
if (value is not null)
|
||||||
|
return ToSqlLiteral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PlaceholderResolutionException(placeholder, columnName, str);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToSqlLiteral(object value) => value switch
|
||||||
|
{
|
||||||
|
bool b => b ? "TRUE" : "FALSE",
|
||||||
|
DateTime dt => dt.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||||
|
DateTimeOffset dto => dto.ToString("yyyy-MM-dd HH:mm:ss zzz"),
|
||||||
|
_ => value.ToString() ?? string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a property by its column name defined in <see cref="ColumnAttribute"/>.
|
||||||
|
/// Returns <c>null</c> if no property with the given column name exists.
|
||||||
|
/// </summary>
|
||||||
|
public static object? GetValueByColumnName<T>(this T obj, string columnName) where T : class
|
||||||
|
{
|
||||||
|
var property = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.FirstOrDefault(p => p.GetCustomAttribute<ColumnAttribute>()?.Name == columnName);
|
||||||
|
|
||||||
|
return property?.GetValue(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record ProfileDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; }
|
|
||||||
|
|
||||||
public string? Mandantor { get; set; }
|
|
||||||
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public string? LogLevel { get; set; }
|
|
||||||
|
|
||||||
public string? Language { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record RecActionDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public long? ProfileId { get; set; }
|
|
||||||
|
|
||||||
public ProfileDto? Profile { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public byte? Sequence { get; set; }
|
|
||||||
|
|
||||||
public long? EndpointId { get; set; }
|
|
||||||
|
|
||||||
public EndpointDto? Endpoint { get; set; }
|
|
||||||
|
|
||||||
public long? EndpointAuthId { get; set; }
|
|
||||||
|
|
||||||
public EndpointAuthDto? EndpointAuth { get; set; }
|
|
||||||
|
|
||||||
public short? EndpointParamsId { get; set; }
|
|
||||||
|
|
||||||
public short? SqlConnectionId { get; set; }
|
|
||||||
|
|
||||||
public ConnectionDto? SqlConnection { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; }
|
|
||||||
|
|
||||||
public string? PreprocessingQuery { get; set; }
|
|
||||||
|
|
||||||
public string? HeaderQuery { get; set; }
|
|
||||||
|
|
||||||
public string? BodyQuery { get; set; }
|
|
||||||
|
|
||||||
public string? PostprocessingQuery { get; set; }
|
|
||||||
|
|
||||||
public ErrorAction? ErrorAction { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
|
|
||||||
public OutResDto? OutRes { get; set; }
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,8 @@ public record RecActionViewDto
|
|||||||
|
|
||||||
public long? ProfileId { get; init; }
|
public long? ProfileId { get; init; }
|
||||||
|
|
||||||
|
public ProfileViewDto? Profile { get; init; }
|
||||||
|
|
||||||
public string? ProfileName { get; init; }
|
public string? ProfileName { get; init; }
|
||||||
|
|
||||||
public ProfileType? ProfileType { get; init; }
|
public ProfileType? ProfileType { get; init; }
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ public record ResultViewDto
|
|||||||
{
|
{
|
||||||
public long Id { get; init; }
|
public long Id { get; init; }
|
||||||
|
|
||||||
public OutResDto? Root { get; init; }
|
|
||||||
|
|
||||||
public long? ActionId { get; init; }
|
public long? ActionId { get; init; }
|
||||||
|
|
||||||
public RecActionViewDto? Action { get; init; }
|
public RecActionViewDto? Action { get; init; }
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ReC.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
public class PlaceholderResolutionException(string placeholder, string columnName, string input)
|
||||||
|
: Exception($"Failed to resolve placeholder '{placeholder}'. No object contains a property with column name '{columnName}'. Input: '{input}'")
|
||||||
|
{
|
||||||
|
public string Placeholder { get; } = placeholder;
|
||||||
|
|
||||||
|
public string ColumnName { get; } = columnName;
|
||||||
|
|
||||||
|
public string Input { get; } = input;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using MediatR;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ReC.Application.Common.Behaviors;
|
using ReC.Application.Common.Behaviors;
|
||||||
|
using ReC.Application.Common.Behaviors.Action;
|
||||||
using ReC.Application.Common.Behaviors.InvokeAction;
|
using ReC.Application.Common.Behaviors.InvokeAction;
|
||||||
using ReC.Application.Common.Constants;
|
using ReC.Application.Common.Constants;
|
||||||
using ReC.Application.Common.Options;
|
using ReC.Application.Common.Options;
|
||||||
|
|||||||
@@ -23,9 +23,4 @@
|
|||||||
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
|
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Common\Behaviors\Action\" />
|
|
||||||
<Folder Include="Common\Options\DbModel\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
257
tests/ReC.Tests/Application/Behaviors/InvokeActionTests.cs
Normal file
257
tests/ReC.Tests/Application/Behaviors/InvokeActionTests.cs
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using ReC.Application.Common.Dto;
|
||||||
|
using ReC.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace ReC.Tests.Application.Behaviors;
|
||||||
|
|
||||||
|
#region Test Models
|
||||||
|
|
||||||
|
public class Foo
|
||||||
|
{
|
||||||
|
[Column("BAZ")]
|
||||||
|
public int Baz { get; set; }
|
||||||
|
|
||||||
|
[Column("FOO_NAME")]
|
||||||
|
public string FooName { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Bar
|
||||||
|
{
|
||||||
|
[Column("QUX")]
|
||||||
|
public bool Qux { get; set; }
|
||||||
|
|
||||||
|
[Column("BAR_DATE")]
|
||||||
|
public DateTime BarDate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Fuz
|
||||||
|
{
|
||||||
|
[Column("QUZ")]
|
||||||
|
public string Quz { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Column("FUZ_OFFSET")]
|
||||||
|
public DateTimeOffset FuzOffset { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoColumnModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class InvokeActionTests
|
||||||
|
{
|
||||||
|
private Foo _foo = null!;
|
||||||
|
private Bar _bar = null!;
|
||||||
|
private Fuz _fuz = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_foo = new Foo { Baz = 2, FooName = "TestFoo" };
|
||||||
|
_bar = new Bar { Qux = true, BarDate = new DateTime(2025, 6, 15, 14, 30, 0) };
|
||||||
|
_fuz = new Fuz { Quz = "QuZ", FuzOffset = new DateTimeOffset(2025, 6, 15, 14, 30, 0, TimeSpan.FromHours(3)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#region GetValueByColumnName Tests
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_ExistingColumn_ReturnsValue()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("BAZ");
|
||||||
|
Assert.That(result, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_NonExistingColumn_ReturnsNull()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("NON_EXISTING");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_PropertyNameInsteadOfColumnName_ReturnsNull()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("Baz");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_ModelWithoutColumnAttribute_ReturnsNull()
|
||||||
|
{
|
||||||
|
var model = new NoColumnModel { Id = 1, Name = "Test" };
|
||||||
|
var result = model.GetValueByColumnName("Id");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Basic Type Tests
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE BAZ = {#INT#BAZ}", "SELECT * FROM T WHERE BAZ = 2")]
|
||||||
|
[TestCase("... WHERE BAZ = {#INT#BAZ}", "... WHERE BAZ = 2")]
|
||||||
|
public void ReplacePlaceholders_IntValue_ReplacesCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE QUX = {#BOOL#QUX}", "SELECT * FROM T WHERE QUX = TRUE")]
|
||||||
|
[TestCase("... WHERE QUX = {#INT#QUX}", "... WHERE QUX = TRUE")]
|
||||||
|
public void ReplacePlaceholders_BoolTrueValue_ReplacesWithTRUE(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_BoolFalseValue_ReplacesWithFALSE()
|
||||||
|
{
|
||||||
|
var bar = new Bar { Qux = false };
|
||||||
|
var result = "WHERE QUX = {#BOOL#QUX}".ReplacePlaceholders(bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUX = FALSE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("... WHERE QUZ <> '{#STR#QUZ}'", "... WHERE QUZ <> 'QuZ'")]
|
||||||
|
[TestCase("SELECT * FROM T WHERE QUZ = '{#TEXT#QUZ}'", "SELECT * FROM T WHERE QUZ = 'QuZ'")]
|
||||||
|
public void ReplacePlaceholders_StringValue_ReplacesCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_DateTimeValue_FormatsAsSqlDateTime()
|
||||||
|
{
|
||||||
|
var result = "WHERE D = '{#DATE#BAR_DATE}'".ReplacePlaceholders(_bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE D = '2025-06-15 14:30:00'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_DateTimeOffsetValue_FormatsWithOffset()
|
||||||
|
{
|
||||||
|
var result = "WHERE D = '{#DTO#FUZ_OFFSET}'".ReplacePlaceholders(_fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE D = '2025-06-15 14:30:00 +03:00'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Multiple Placeholders
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_MultiplePlaceholdersInSameString_ReplacesAll()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} AND QUX = {#BOOL#QUX} AND QUZ = '{#STR#QUZ}'";
|
||||||
|
var expected = "WHERE BAZ = 2 AND QUX = TRUE AND QUZ = 'QuZ'";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_SamePlaceholderTwice_ReplacesBoth()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} OR BAZ = {#INT#BAZ}";
|
||||||
|
var expected = "WHERE BAZ = 2 OR BAZ = 2";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Object Resolution Order
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ValueFoundInSecondObject_ReturnsValueFromSecondObject()
|
||||||
|
{
|
||||||
|
var result = "WHERE QUX = {#BOOL#QUX}".ReplacePlaceholders(_foo, _bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUX = TRUE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ValueFoundInThirdObject_ReturnsValueFromThirdObject()
|
||||||
|
{
|
||||||
|
var result = "WHERE QUZ = '{#STR#QUZ}'".ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUZ = 'QuZ'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - No Placeholder
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE X = 1")]
|
||||||
|
[TestCase("")]
|
||||||
|
[TestCase("some random text")]
|
||||||
|
public void ReplacePlaceholders_NoPlaceholders_ReturnsOriginalString(string input)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Different Prefix Strings
|
||||||
|
|
||||||
|
[TestCase("WHERE BAZ = {#VAR#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#PARAM#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#X#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#SOME_LONG_PREFIX#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
public void ReplacePlaceholders_DifferentPrefixes_AllResolveCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Exception Tests
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_UnresolvableColumn_ThrowsPlaceholderResolutionException()
|
||||||
|
{
|
||||||
|
var input = "WHERE X = {#INT#NON_EXISTING}";
|
||||||
|
|
||||||
|
var ex = Assert.Throws<PlaceholderResolutionException>(() =>
|
||||||
|
input.ReplacePlaceholders(_foo, _bar, _fuz));
|
||||||
|
|
||||||
|
Assert.That(ex!.ColumnName, Is.EqualTo("NON_EXISTING"));
|
||||||
|
Assert.That(ex.Placeholder, Is.EqualTo("{#INT#NON_EXISTING}"));
|
||||||
|
Assert.That(ex.Input, Is.EqualTo(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_NoObjectsProvided_ThrowsPlaceholderResolutionException()
|
||||||
|
{
|
||||||
|
var input = "WHERE X = {#INT#BAZ}";
|
||||||
|
|
||||||
|
Assert.Throws<PlaceholderResolutionException>(() =>
|
||||||
|
input.ReplacePlaceholders());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ThrowsPlaceholderResolutionException()
|
||||||
|
{
|
||||||
|
var model = new NoColumnModel { Id = 1, Name = "Test" };
|
||||||
|
var input = "WHERE X = {#INT#Id}";
|
||||||
|
|
||||||
|
Assert.Throws<PlaceholderResolutionException>(() =>
|
||||||
|
input.ReplacePlaceholders(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ThrowsOnUnresolvable()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} AND X = {#INT#UNKNOWN}";
|
||||||
|
|
||||||
|
var ex = Assert.Throws<PlaceholderResolutionException>(() =>
|
||||||
|
input.ReplacePlaceholders(_foo, _bar, _fuz));
|
||||||
|
|
||||||
|
Assert.That(ex!.ColumnName, Is.EqualTo("UNKNOWN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user