Change ReplacePlaceholders to return NULL for unresolved

Previously, ReplacePlaceholders threw PlaceholderResolutionException when a placeholder could not be resolved. Now, unresolved placeholders are replaced with "NULL" instead. All exception references and related tests have been updated to reflect this new behavior. Documentation has also been revised accordingly.
This commit is contained in:
2026-03-30 14:33:13 +02:00
parent 77baf395ce
commit bb5eac023c
2 changed files with 14 additions and 24 deletions

View File

@@ -1,7 +1,6 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ReC.Application.Common.Exceptions;
namespace ReC.Application.Common.Dto; namespace ReC.Application.Common.Dto;
@@ -14,10 +13,8 @@ public static partial class PlaceholderExtensions
/// Replaces placeholders in the format <c>{#ANY_STRING#COLUMN_NAME}</c> with the corresponding /// 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. /// property value resolved via <see cref="GetValueByColumnName{T}"/> from the provided objects.
/// Values are converted to SQL-compatible string representations. /// Values are converted to SQL-compatible string representations.
/// If a placeholder cannot be resolved, it is replaced with <c>NULL</c>.
/// </summary> /// </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) public static string ReplacePlaceholders(this string str, params object?[] objects)
{ {
return PlaceholderRegex().Replace(str, match => return PlaceholderRegex().Replace(str, match =>
@@ -37,7 +34,7 @@ public static partial class PlaceholderExtensions
return ToSqlLiteral(value); return ToSqlLiteral(value);
} }
throw new PlaceholderResolutionException(placeholder, columnName, str); return "NULL";
}); });
} }

View File

@@ -1,6 +1,5 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using ReC.Application.Common.Dto; using ReC.Application.Common.Dto;
using ReC.Application.Common.Exceptions;
namespace ReC.Tests.Application.Behaviors; namespace ReC.Tests.Application.Behaviors;
@@ -211,46 +210,40 @@ public class InvokeActionTests
#region ReplacePlaceholders - Exception Tests #region ReplacePlaceholders - Exception Tests
[Test] [Test]
public void ReplacePlaceholders_UnresolvableColumn_ThrowsPlaceholderResolutionException() public void ReplacePlaceholders_UnresolvableColumn_ReturnsNull()
{ {
var input = "WHERE X = {#INT#NON_EXISTING}"; var input = "WHERE X = {#INT#NON_EXISTING}";
var ex = Assert.Throws<PlaceholderResolutionException>(() => var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
input.ReplacePlaceholders(_foo, _bar, _fuz)); Assert.That(result, Is.EqualTo("WHERE X = NULL"));
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] [Test]
public void ReplacePlaceholders_NoObjectsProvided_ThrowsPlaceholderResolutionException() public void ReplacePlaceholders_NoObjectsProvided_ReturnsNull()
{ {
var input = "WHERE X = {#INT#BAZ}"; var input = "WHERE X = {#INT#BAZ}";
Assert.Throws<PlaceholderResolutionException>(() => var result = input.ReplacePlaceholders();
input.ReplacePlaceholders()); Assert.That(result, Is.EqualTo("WHERE X = NULL"));
} }
[Test] [Test]
public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ThrowsPlaceholderResolutionException() public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ReturnsNull()
{ {
var model = new NoColumnModel { Id = 1, Name = "Test" }; var model = new NoColumnModel { Id = 1, Name = "Test" };
var input = "WHERE X = {#INT#Id}"; var input = "WHERE X = {#INT#Id}";
Assert.Throws<PlaceholderResolutionException>(() => var result = input.ReplacePlaceholders(model);
input.ReplacePlaceholders(model)); Assert.That(result, Is.EqualTo("WHERE X = NULL"));
} }
[Test] [Test]
public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ThrowsOnUnresolvable() public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ReturnsNullForUnresolvable()
{ {
var input = "WHERE BAZ = {#INT#BAZ} AND X = {#INT#UNKNOWN}"; var input = "WHERE BAZ = {#INT#BAZ} AND X = {#INT#UNKNOWN}";
var ex = Assert.Throws<PlaceholderResolutionException>(() => var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
input.ReplacePlaceholders(_foo, _bar, _fuz)); Assert.That(result, Is.EqualTo("WHERE BAZ = 2 AND X = NULL"));
Assert.That(ex!.ColumnName, Is.EqualTo("UNKNOWN"));
} }
#endregion #endregion