Compare commits
23 Commits
b66a49f74d
...
d6af24cd91
| Author | SHA1 | Date | |
|---|---|---|---|
| d6af24cd91 | |||
| bb5eac023c | |||
| 77baf395ce | |||
| 6c9eab6df6 | |||
| c64794755d | |||
| de2185bf0a | |||
| fde9735b27 | |||
| 0342b9e0c6 | |||
| 47698b9046 | |||
| a03d21ebc6 | |||
| acff0aca89 | |||
| ce0e53baf6 | |||
| 620c0eff22 | |||
| 68f4486fa1 | |||
| 2b5e63cb45 | |||
| e9e697fa0d | |||
| 606eccb855 | |||
| 3146acfa45 | |||
| f363872e7a | |||
| ed4683323d | |||
| 4aeef10ef7 | |||
| e04e90d8c6 | |||
| 93b5f976d3 |
@@ -23,6 +23,7 @@ public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPi
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.QuerySuccess,
|
||||
ActionId = request.Action.Id,
|
||||
Info = info,
|
||||
Type = ResultType.Post
|
||||
@@ -35,6 +36,7 @@ public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPi
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Failed,
|
||||
ActionId = request.Action.Id,
|
||||
Error = error,
|
||||
Type = ResultType.Post
|
||||
|
||||
@@ -20,6 +20,7 @@ public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPip
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.QuerySuccess,
|
||||
ActionId = request.Action.Id,
|
||||
Info = JsonSerializer.Serialize(result),
|
||||
Type = ResultType.Pre
|
||||
@@ -30,6 +31,7 @@ public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPip
|
||||
{
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Failed,
|
||||
ActionId = request.Action.Id,
|
||||
Error = ex.ToString(),
|
||||
Type = ResultType.Pre
|
||||
|
||||
@@ -8,9 +8,9 @@ public class DtoMappingProfile : AutoMapper.Profile
|
||||
{
|
||||
CreateMap<RecActionView, RecActionViewDto>()
|
||||
.ForMember(dest => dest.PreprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||
src.PreprocessingQuery?.ReplacePlaceholders(src, src.Profile)))
|
||||
src.PreprocessingQuery?.ReplacePlaceholders(src)))
|
||||
.ForMember(dest => dest.PostprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||
src.PostprocessingQuery?.ReplacePlaceholders(src, src.Profile)));
|
||||
src.PostprocessingQuery?.ReplacePlaceholders(src)));
|
||||
|
||||
CreateMap<ResultView, ResultViewDto>();
|
||||
CreateMap<ProfileView, ProfileViewDto>();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
|
||||
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
|
||||
/// property value resolved via <see cref="GetValueByColumnName{T}"/> from the provided objects.
|
||||
/// Values are converted to SQL-compatible string representations.
|
||||
/// If a placeholder cannot be resolved, it is replaced with <c>NULL</c>.
|
||||
/// </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 =>
|
||||
@@ -37,7 +34,7 @@ public static partial class PlaceholderExtensions
|
||||
return ToSqlLiteral(value);
|
||||
}
|
||||
|
||||
throw new PlaceholderResolutionException(placeholder, columnName, str);
|
||||
return "NULL";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace ReC.Application.Common.Dto;
|
||||
using ReC.Domain.Constants;
|
||||
|
||||
namespace ReC.Application.Common.Dto;
|
||||
|
||||
public record ResultViewDto
|
||||
{
|
||||
@@ -14,7 +16,7 @@ public record ResultViewDto
|
||||
|
||||
public string? ProfileName { get; init; }
|
||||
|
||||
public short? StatusCode { get; init; }
|
||||
public RecStatus Status { get; set; }
|
||||
|
||||
public string? StatusName { get; init; }
|
||||
|
||||
@@ -22,6 +24,10 @@ public record ResultViewDto
|
||||
|
||||
public string? Body { get; init; }
|
||||
|
||||
public string? Info { get; set; }
|
||||
|
||||
public string? Error { get; set; }
|
||||
|
||||
public string? AddedWho { get; init; }
|
||||
|
||||
public DateTime? AddedWhen { get; init; }
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Options;
|
||||
using System.Text;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
@@ -36,21 +35,15 @@ public class DeleteObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
||||
{
|
||||
public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var sp = new StoredProcedureBuilder("EXEC @RC = [dbo].[PRREC_DELETE_OBJECT]")
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_DELETE_OBJECT]", "RC")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pSTART", request.Start.ToString())
|
||||
.Add("pEND", request.End.ToString())
|
||||
.Add("pFORCE", request.Force);
|
||||
|
||||
var sql = new StringBuilder()
|
||||
.AppendLine("DECLARE @RC SMALLINT = 0;")
|
||||
.Append(sp.BuildSql()).AppendLine(";")
|
||||
.AppendLine("SELECT @RC;")
|
||||
.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await repo.ExecuteQueryRawAsync(sql, sp.BuildParameters(), cancel);
|
||||
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
||||
{
|
||||
public async Task<long> Handle(InsertObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var sp = new StoredProcedureBuilder("EXEC [dbo].[PRREC_INSERT_OBJECT]")
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_INSERT_OBJECT]")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pADDED_WHO", request.AddedWho)
|
||||
.Add("pADDED_WHEN", DateTime.UtcNow)
|
||||
@@ -76,7 +76,7 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
||||
.Add("pPROFILE_LOG_LEVEL_ID", request.Profile?.LogLevelId, SqlDbType.TinyInt)
|
||||
.Add("pPROFILE_LANGUAGE_ID", request.Profile?.LanguageId, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_ACTION_ID", request.Result?.ActionId)
|
||||
.Add("pRESULT_STATUS_ID", request.Result?.StatusId, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_STATUS_ID", request.Result?.Status, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_TYPE_ID", request.Result?.Type is not null ? (byte)request.Result.Type : null, SqlDbType.TinyInt)
|
||||
.Add("pRESULT_HEADER", request.Result?.Header)
|
||||
.Add("pRESULT_BODY", request.Result?.Body)
|
||||
|
||||
@@ -4,22 +4,19 @@ using System.Text;
|
||||
|
||||
namespace ReC.Application.Common.Procedures;
|
||||
|
||||
internal sealed class StoredProcedureBuilder
|
||||
internal sealed class StoredProcedureBuilder(string procedureName, string? returnVariable = null)
|
||||
{
|
||||
private readonly StringBuilder _sql;
|
||||
private readonly StringBuilder _execSql = returnVariable is not null
|
||||
? new StringBuilder($"EXEC @{returnVariable} = {procedureName}")
|
||||
: new StringBuilder($"EXEC {procedureName}");
|
||||
private readonly List<SqlParameter> _parameters = [];
|
||||
private char _separator = ' ';
|
||||
|
||||
public StoredProcedureBuilder(string execPrefix)
|
||||
{
|
||||
_sql = new StringBuilder(execPrefix);
|
||||
}
|
||||
|
||||
public StoredProcedureBuilder Add(string name, object? value, SqlDbType? dbType = null)
|
||||
{
|
||||
if (value is null) return this;
|
||||
|
||||
_sql.AppendLine($"{_separator}@{name} = @{name}");
|
||||
_execSql.AppendLine($"{_separator}@{name} = @{name}");
|
||||
_separator = ',';
|
||||
|
||||
if (dbType.HasValue)
|
||||
@@ -32,7 +29,7 @@ internal sealed class StoredProcedureBuilder
|
||||
|
||||
public StoredProcedureBuilder AddOutput(string name, SqlDbType dbType)
|
||||
{
|
||||
_sql.AppendLine($"{_separator}@{name} = @{name} OUTPUT");
|
||||
_execSql.AppendLine($"{_separator}@{name} = @{name} OUTPUT");
|
||||
_separator = ',';
|
||||
|
||||
_parameters.Add(new SqlParameter
|
||||
@@ -45,7 +42,17 @@ internal sealed class StoredProcedureBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
public string BuildSql() => _sql.ToString();
|
||||
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];
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
@@ -38,7 +37,7 @@ public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
||||
{
|
||||
public async Task<int> Handle(UpdateObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var sp = new StoredProcedureBuilder("EXEC @RC = [dbo].[PRREC_UPDATE_OBJECT]")
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_UPDATE_OBJECT]", "RC")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pGUID", request.Id)
|
||||
.Add("pCHANGED_WHO", request.ChangedWho)
|
||||
@@ -91,15 +90,9 @@ public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
||||
.Add("pRESULT_HEADER", request.Result.Header)
|
||||
.Add("pRESULT_BODY", request.Result.Body);
|
||||
|
||||
var sql = new StringBuilder()
|
||||
.AppendLine("DECLARE @RC SMALLINT = 0;")
|
||||
.Append(sp.BuildSql()).AppendLine(";")
|
||||
.AppendLine("SELECT @RC;")
|
||||
.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await repo.ExecuteQueryRawAsync(sql, sp.BuildParameters(), cancel);
|
||||
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
|
||||
@@ -57,10 +57,6 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
|
||||
RuleFor(x => x.Result!.ActionId)
|
||||
.NotNull()
|
||||
.WithMessage("RESULT requires ResultActionId (maps to @pRESULT_ACTION_ID).");
|
||||
|
||||
RuleFor(x => x.Result!)
|
||||
.Must(r => r.StatusId != null || r.Info != null || r.Error != null)
|
||||
.WithMessage("RESULT requires at least one of: StatusId, Info, or Error.");
|
||||
});
|
||||
|
||||
// ENDPOINT_PARAMS validation
|
||||
|
||||
@@ -146,7 +146,7 @@ public class InvokeRecActionViewCommandHandler(
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
StatusId = statusCode,
|
||||
Status = response.StatusCode.ToRecStatus(),
|
||||
ActionId = action.Id,
|
||||
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
||||
Body = resBody,
|
||||
@@ -157,6 +157,7 @@ public class InvokeRecActionViewCommandHandler(
|
||||
{
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Failed,
|
||||
ActionId = action.Id,
|
||||
Error = ex.ToString(),
|
||||
Type = ResultType.Main
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace ReC.Application.Results.Commands;
|
||||
public record InsertResultCommand : IInsertProcedure
|
||||
{
|
||||
public long? ActionId { get; set; }
|
||||
public short? StatusId { get; set; }
|
||||
public required RecStatus Status { get; set; }
|
||||
public string? Header { get; set; }
|
||||
public string? Body { get; set; }
|
||||
public string? Info { get; set; }
|
||||
|
||||
431
src/ReC.Domain/Constants/RecStatus.cs
Normal file
431
src/ReC.Domain/Constants/RecStatus.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
using ReC.Domain.Views;
|
||||
|
||||
namespace ReC.Domain.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// Represents status codes used to indicate the outcome of an operation.
|
||||
/// <para>
|
||||
/// Includes all standard HTTP status codes as defined in <see cref="System.Net.HttpStatusCode"/>,
|
||||
/// as well as custom non-HTTP status codes for internal operation results.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <seealso cref="RecStatusExtensions"/>
|
||||
public enum RecStatus : short
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a SQL query executed successfully (value 0).
|
||||
/// Used as the result status when <see cref="RecActionView.PreprocessingQuery"/>
|
||||
/// or <see cref="RecActionView.PostprocessingQuery"/> completes without error.
|
||||
/// </summary>
|
||||
QuerySuccess = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an operation failed at any stage (value 999).
|
||||
/// This includes SQL query failures during preprocessing/postprocessing,
|
||||
/// HTTP request errors, or any other unhandled exception within the action pipeline.
|
||||
/// </summary>
|
||||
Failed = 999,
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 100. System.Net.HttpStatusCode.Continue indicates that
|
||||
// the client can continue with its request.
|
||||
Continue = 100,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 101. System.Net.HttpStatusCode.SwitchingProtocols indicates
|
||||
// that the protocol version or protocol is being changed.
|
||||
SwitchingProtocols = 101,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 102. System.Net.HttpStatusCode.Processing indicates
|
||||
// that the server has accepted the complete request but hasn't completed it yet.
|
||||
Processing = 102,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 103. System.Net.HttpStatusCode.EarlyHints indicates
|
||||
// to the client that the server is likely to send a final response with the header
|
||||
// fields included in the informational response.
|
||||
EarlyHints = 103,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 200. System.Net.HttpStatusCode.OK indicates that the
|
||||
// request succeeded and that the requested information is in the response. This
|
||||
// is the most common status code to receive.
|
||||
OK = 200,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 201. System.Net.HttpStatusCode.Created indicates that
|
||||
// the request resulted in a new resource created before the response was sent.
|
||||
Created = 201,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 202. System.Net.HttpStatusCode.Accepted indicates that
|
||||
// the request has been accepted for further processing.
|
||||
Accepted = 202,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 203. System.Net.HttpStatusCode.NonAuthoritativeInformation
|
||||
// indicates that the returned meta information is from a cached copy instead of
|
||||
// the origin server and therefore may be incorrect.
|
||||
NonAuthoritativeInformation = 203,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 204. System.Net.HttpStatusCode.NoContent indicates
|
||||
// that the request has been successfully processed and that the response is intentionally
|
||||
// blank.
|
||||
NoContent = 204,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 205. System.Net.HttpStatusCode.ResetContent indicates
|
||||
// that the client should reset (not reload) the current resource.
|
||||
ResetContent = 205,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 206. System.Net.HttpStatusCode.PartialContent indicates
|
||||
// that the response is a partial response as requested by a GET request that includes
|
||||
// a byte range.
|
||||
PartialContent = 206,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 207. System.Net.HttpStatusCode.MultiStatus indicates
|
||||
// multiple status codes for a single response during a Web Distributed Authoring
|
||||
// and Versioning (WebDAV) operation. The response body contains XML that describes
|
||||
// the status codes.
|
||||
MultiStatus = 207,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 208. System.Net.HttpStatusCode.AlreadyReported indicates
|
||||
// that the members of a WebDAV binding have already been enumerated in a preceding
|
||||
// part of the multistatus response, and are not being included again.
|
||||
AlreadyReported = 208,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 226. System.Net.HttpStatusCode.IMUsed indicates that
|
||||
// the server has fulfilled a request for the resource, and the response is a representation
|
||||
// of the result of one or more instance-manipulations applied to the current instance.
|
||||
IMUsed = 226,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 300. System.Net.HttpStatusCode.Ambiguous indicates
|
||||
// that the requested information has multiple representations. The default action
|
||||
// is to treat this status as a redirect and follow the contents of the Location
|
||||
// header associated with this response. Ambiguous is a synonym for MultipleChoices.
|
||||
Ambiguous = 300,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 300. System.Net.HttpStatusCode.MultipleChoices indicates
|
||||
// that the requested information has multiple representations. The default action
|
||||
// is to treat this status as a redirect and follow the contents of the Location
|
||||
// header associated with this response. MultipleChoices is a synonym for Ambiguous.
|
||||
MultipleChoices = 300,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 301. System.Net.HttpStatusCode.Moved indicates that
|
||||
// the requested information has been moved to the URI specified in the Location
|
||||
// header. The default action when this status is received is to follow the Location
|
||||
// header associated with the response. When the original request method was POST,
|
||||
// the redirected request will use the GET method. Moved is a synonym for MovedPermanently.
|
||||
Moved = 301,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 301. System.Net.HttpStatusCode.MovedPermanently indicates
|
||||
// that the requested information has been moved to the URI specified in the Location
|
||||
// header. The default action when this status is received is to follow the Location
|
||||
// header associated with the response. MovedPermanently is a synonym for Moved.
|
||||
MovedPermanently = 301,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 302. System.Net.HttpStatusCode.Found indicates that
|
||||
// the requested information is located at the URI specified in the Location header.
|
||||
// The default action when this status is received is to follow the Location header
|
||||
// associated with the response. When the original request method was POST, the
|
||||
// redirected request will use the GET method. Found is a synonym for Redirect.
|
||||
Found = 302,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 302. System.Net.HttpStatusCode.Redirect indicates that
|
||||
// the requested information is located at the URI specified in the Location header.
|
||||
// The default action when this status is received is to follow the Location header
|
||||
// associated with the response. When the original request method was POST, the
|
||||
// redirected request will use the GET method. Redirect is a synonym for Found.
|
||||
Redirect = 302,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 303. System.Net.HttpStatusCode.RedirectMethod automatically
|
||||
// redirects the client to the URI specified in the Location header as the result
|
||||
// of a POST. The request to the resource specified by the Location header will
|
||||
// be made with a GET. RedirectMethod is a synonym for SeeOther.
|
||||
RedirectMethod = 303,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 303. System.Net.HttpStatusCode.SeeOther automatically
|
||||
// redirects the client to the URI specified in the Location header as the result
|
||||
// of a POST. The request to the resource specified by the Location header will
|
||||
// be made with a GET. SeeOther is a synonym for RedirectMethod.
|
||||
SeeOther = 303,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 304. System.Net.HttpStatusCode.NotModified indicates
|
||||
// that the client's cached copy is up to date. The contents of the resource are
|
||||
// not transferred.
|
||||
NotModified = 304,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 305. System.Net.HttpStatusCode.UseProxy indicates that
|
||||
// the request should use the proxy server at the URI specified in the Location
|
||||
// header.
|
||||
UseProxy = 305,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 306. System.Net.HttpStatusCode.Unused is a proposed
|
||||
// extension to the HTTP/1.1 specification that is not fully specified.
|
||||
Unused = 306,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 307. System.Net.HttpStatusCode.RedirectKeepVerb indicates
|
||||
// that the request information is located at the URI specified in the Location
|
||||
// header. The default action when this status is received is to follow the Location
|
||||
// header associated with the response. When the original request method was POST,
|
||||
// the redirected request will also use the POST method. RedirectKeepVerb is a synonym
|
||||
// for TemporaryRedirect.
|
||||
RedirectKeepVerb = 307,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 307. System.Net.HttpStatusCode.TemporaryRedirect indicates
|
||||
// that the request information is located at the URI specified in the Location
|
||||
// header. The default action when this status is received is to follow the Location
|
||||
// header associated with the response. When the original request method was POST,
|
||||
// the redirected request will also use the POST method. TemporaryRedirect is a
|
||||
// synonym for RedirectKeepVerb.
|
||||
TemporaryRedirect = 307,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 308. System.Net.HttpStatusCode.PermanentRedirect indicates
|
||||
// that the request information is located at the URI specified in the Location
|
||||
// header. The default action when this status is received is to follow the Location
|
||||
// header associated with the response. When the original request method was POST,
|
||||
// the redirected request will also use the POST method.
|
||||
PermanentRedirect = 308,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 400. System.Net.HttpStatusCode.BadRequest indicates
|
||||
// that the request could not be understood by the server. System.Net.HttpStatusCode.BadRequest
|
||||
// is sent when no other error is applicable, or if the exact error is unknown or
|
||||
// does not have its own error code.
|
||||
BadRequest = 400,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 401. System.Net.HttpStatusCode.Unauthorized indicates
|
||||
// that the requested resource requires authentication. The WWW-Authenticate header
|
||||
// contains the details of how to perform the authentication.
|
||||
Unauthorized = 401,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 402. System.Net.HttpStatusCode.PaymentRequired is reserved
|
||||
// for future use.
|
||||
PaymentRequired = 402,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 403. System.Net.HttpStatusCode.Forbidden indicates
|
||||
// that the server refuses to fulfill the request.
|
||||
Forbidden = 403,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 404. System.Net.HttpStatusCode.NotFound indicates that
|
||||
// the requested resource does not exist on the server.
|
||||
NotFound = 404,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 405. System.Net.HttpStatusCode.MethodNotAllowed indicates
|
||||
// that the request method (POST or GET) is not allowed on the requested resource.
|
||||
MethodNotAllowed = 405,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 406. System.Net.HttpStatusCode.NotAcceptable indicates
|
||||
// that the client has indicated with Accept headers that it will not accept any
|
||||
// of the available representations of the resource.
|
||||
NotAcceptable = 406,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 407. System.Net.HttpStatusCode.ProxyAuthenticationRequired
|
||||
// indicates that the requested proxy requires authentication. The Proxy-authenticate
|
||||
// header contains the details of how to perform the authentication.
|
||||
ProxyAuthenticationRequired = 407,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 408. System.Net.HttpStatusCode.RequestTimeout indicates
|
||||
// that the client did not send a request within the time the server was expecting
|
||||
// the request.
|
||||
RequestTimeout = 408,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 409. System.Net.HttpStatusCode.Conflict indicates that
|
||||
// the request could not be carried out because of a conflict on the server.
|
||||
Conflict = 409,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 410. System.Net.HttpStatusCode.Gone indicates that
|
||||
// the requested resource is no longer available.
|
||||
Gone = 410,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 411. System.Net.HttpStatusCode.LengthRequired indicates
|
||||
// that the required Content-length header is missing.
|
||||
LengthRequired = 411,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 412. System.Net.HttpStatusCode.PreconditionFailed indicates
|
||||
// that a condition set for this request failed, and the request cannot be carried
|
||||
// out. Conditions are set with conditional request headers like If-Match, If-None-Match,
|
||||
// or If-Unmodified-Since.
|
||||
PreconditionFailed = 412,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 413. System.Net.HttpStatusCode.RequestEntityTooLarge
|
||||
// indicates that the request is too large for the server to process.
|
||||
RequestEntityTooLarge = 413,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 414. System.Net.HttpStatusCode.RequestUriTooLong indicates
|
||||
// that the URI is too long.
|
||||
RequestUriTooLong = 414,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 415. System.Net.HttpStatusCode.UnsupportedMediaType
|
||||
// indicates that the request is an unsupported type.
|
||||
UnsupportedMediaType = 415,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 416. System.Net.HttpStatusCode.RequestedRangeNotSatisfiable
|
||||
// indicates that the range of data requested from the resource cannot be returned,
|
||||
// either because the beginning of the range is before the beginning of the resource,
|
||||
// or the end of the range is after the end of the resource.
|
||||
RequestedRangeNotSatisfiable = 416,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 417. System.Net.HttpStatusCode.ExpectationFailed indicates
|
||||
// that an expectation given in an Expect header could not be met by the server.
|
||||
ExpectationFailed = 417,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 421. System.Net.HttpStatusCode.MisdirectedRequest indicates
|
||||
// that the request was directed at a server that is not able to produce a response.
|
||||
MisdirectedRequest = 421,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 422. System.Net.HttpStatusCode.UnprocessableEntity
|
||||
// indicates that the request was well-formed but was unable to be followed due
|
||||
// to semantic errors. UnprocessableEntity is a synonym for UnprocessableContent.
|
||||
UnprocessableEntity = 422,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 422. System.Net.HttpStatusCode.UnprocessableContent
|
||||
// indicates that the request was well-formed but was unable to be followed due
|
||||
// to semantic errors. UnprocessableContent is a synonym for UnprocessableEntity.
|
||||
UnprocessableContent = 422,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 423. System.Net.HttpStatusCode.Locked indicates that
|
||||
// the source or destination resource is locked.
|
||||
Locked = 423,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 424. System.Net.HttpStatusCode.FailedDependency indicates
|
||||
// that the method couldn't be performed on the resource because the requested action
|
||||
// depended on another action and that action failed.
|
||||
FailedDependency = 424,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 426. System.Net.HttpStatusCode.UpgradeRequired indicates
|
||||
// that the client should switch to a different protocol such as TLS/1.0.
|
||||
UpgradeRequired = 426,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 428. System.Net.HttpStatusCode.PreconditionRequired
|
||||
// indicates that the server requires the request to be conditional.
|
||||
PreconditionRequired = 428,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 429. System.Net.HttpStatusCode.TooManyRequests indicates
|
||||
// that the user has sent too many requests in a given amount of time.
|
||||
TooManyRequests = 429,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 431. System.Net.HttpStatusCode.RequestHeaderFieldsTooLarge
|
||||
// indicates that the server is unwilling to process the request because its header
|
||||
// fields (either an individual header field or all the header fields collectively)
|
||||
// are too large.
|
||||
RequestHeaderFieldsTooLarge = 431,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 451. System.Net.HttpStatusCode.UnavailableForLegalReasons
|
||||
// indicates that the server is denying access to the resource as a consequence
|
||||
// of a legal demand.
|
||||
UnavailableForLegalReasons = 451,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 500. System.Net.HttpStatusCode.InternalServerError
|
||||
// indicates that a generic error has occurred on the server.
|
||||
InternalServerError = 500,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 501. System.Net.HttpStatusCode.NotImplemented indicates
|
||||
// that the server does not support the requested function.
|
||||
NotImplemented = 501,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 502. System.Net.HttpStatusCode.BadGateway indicates
|
||||
// that an intermediate proxy server received a bad response from another proxy
|
||||
// or the origin server.
|
||||
BadGateway = 502,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 503. System.Net.HttpStatusCode.ServiceUnavailable indicates
|
||||
// that the server is temporarily unavailable, usually due to high load or maintenance.
|
||||
ServiceUnavailable = 503,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 504. System.Net.HttpStatusCode.GatewayTimeout indicates
|
||||
// that an intermediate proxy server timed out while waiting for a response from
|
||||
// another proxy or the origin server.
|
||||
GatewayTimeout = 504,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 505. System.Net.HttpStatusCode.HttpVersionNotSupported
|
||||
// indicates that the requested HTTP version is not supported by the server.
|
||||
HttpVersionNotSupported = 505,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 506. System.Net.HttpStatusCode.VariantAlsoNegotiates
|
||||
// indicates that the chosen variant resource is configured to engage in transparent
|
||||
// content negotiation itself and, therefore, isn't a proper endpoint in the negotiation
|
||||
// process.
|
||||
VariantAlsoNegotiates = 506,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 507. System.Net.HttpStatusCode.InsufficientStorage
|
||||
// indicates that the server is unable to store the representation needed to complete
|
||||
// the request.
|
||||
InsufficientStorage = 507,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 508. System.Net.HttpStatusCode.LoopDetected indicates
|
||||
// that the server terminated an operation because it encountered an infinite loop
|
||||
// while processing a WebDAV request with "Depth: infinity". This status code is
|
||||
// meant for backward compatibility with clients not aware of the 208 status code
|
||||
// System.Net.HttpStatusCode.AlreadyReported appearing in multistatus response bodies.
|
||||
LoopDetected = 508,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 510. System.Net.HttpStatusCode.NotExtended indicates
|
||||
// that further extensions to the request are required for the server to fulfill
|
||||
// it.
|
||||
NotExtended = 510,
|
||||
//
|
||||
// Summary:
|
||||
// Equivalent to HTTP status 511. System.Net.HttpStatusCode.NetworkAuthenticationRequired
|
||||
// indicates that the client needs to authenticate to gain network access; it's
|
||||
// intended for use by intercepting proxies used to control access to the network.
|
||||
NetworkAuthenticationRequired = 511
|
||||
}
|
||||
34
src/ReC.Domain/Constants/RecStatusExtensions.cs
Normal file
34
src/ReC.Domain/Constants/RecStatusExtensions.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Net;
|
||||
|
||||
namespace ReC.Domain.Constants;
|
||||
|
||||
public static class RecStatusExtensions
|
||||
{
|
||||
public static HttpStatusCode? ToHttpStatusCode(this RecStatus status)
|
||||
{
|
||||
int code = (int)status;
|
||||
|
||||
if (Enum.IsDefined(typeof(HttpStatusCode), code))
|
||||
{
|
||||
return (HttpStatusCode)code;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsSuccess(this HttpStatusCode code)
|
||||
{
|
||||
int value = (int)code;
|
||||
return value >= 200 && value <= 299;
|
||||
}
|
||||
|
||||
public static bool IsSuccess(this RecStatus status)
|
||||
=> status switch
|
||||
{
|
||||
RecStatus.QuerySuccess => true,
|
||||
RecStatus.Failed => false,
|
||||
_ => status.ToHttpStatusCode() is HttpStatusCode httpStatus && httpStatus.IsSuccess()
|
||||
};
|
||||
|
||||
public static RecStatus ToRecStatus(this HttpStatusCode code) => (RecStatus)(short)code;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace ReC.Domain.Constants;
|
||||
|
||||
public enum ResultType
|
||||
public enum ResultType : byte
|
||||
{
|
||||
Pre = 1,
|
||||
Main,
|
||||
|
||||
@@ -25,7 +25,7 @@ public class ResultView
|
||||
public string? ProfileName { get; set; }
|
||||
|
||||
[Column("STATUS_ID")]
|
||||
public short? StatusCode { get; set; }
|
||||
public RecStatus Status { get; set; }
|
||||
|
||||
[Column("STATUS")]
|
||||
public string? StatusName { get; set; }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
|
||||
namespace ReC.Tests.Application.Behaviors;
|
||||
|
||||
@@ -211,46 +210,40 @@ public class InvokeActionTests
|
||||
#region ReplacePlaceholders - Exception Tests
|
||||
|
||||
[Test]
|
||||
public void ReplacePlaceholders_UnresolvableColumn_ThrowsPlaceholderResolutionException()
|
||||
public void ReplacePlaceholders_UnresolvableColumn_ReturnsNull()
|
||||
{
|
||||
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));
|
||||
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReplacePlaceholders_NoObjectsProvided_ThrowsPlaceholderResolutionException()
|
||||
public void ReplacePlaceholders_NoObjectsProvided_ReturnsNull()
|
||||
{
|
||||
var input = "WHERE X = {#INT#BAZ}";
|
||||
|
||||
Assert.Throws<PlaceholderResolutionException>(() =>
|
||||
input.ReplacePlaceholders());
|
||||
var result = input.ReplacePlaceholders();
|
||||
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ThrowsPlaceholderResolutionException()
|
||||
public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ReturnsNull()
|
||||
{
|
||||
var model = new NoColumnModel { Id = 1, Name = "Test" };
|
||||
var input = "WHERE X = {#INT#Id}";
|
||||
|
||||
Assert.Throws<PlaceholderResolutionException>(() =>
|
||||
input.ReplacePlaceholders(model));
|
||||
var result = input.ReplacePlaceholders(model);
|
||||
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ThrowsOnUnresolvable()
|
||||
public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ReturnsNullForUnresolvable()
|
||||
{
|
||||
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"));
|
||||
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||
Assert.That(result, Is.EqualTo("WHERE BAZ = 2 AND X = NULL"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -6,6 +7,7 @@ using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Domain.Constants;
|
||||
using ReC.Tests.Application;
|
||||
|
||||
namespace ReC.Tests.Application.Results;
|
||||
@@ -23,7 +25,7 @@ public class ResultProcedureTests : RecApplicationTestBase
|
||||
[Test]
|
||||
public async Task InsertResultProcedure_runs_via_mediator()
|
||||
{
|
||||
var procedure = new InsertResultCommand { ActionId = 1, StatusId = 200, Header = "h", Body = "b", Type = Domain.Constants.ResultType.Main };
|
||||
var procedure = new InsertResultCommand { ActionId = 1, Status = HttpStatusCode.OK.ToRecStatus(), Header = "h", Body = "b", Type = Domain.Constants.ResultType.Main };
|
||||
|
||||
var (sender, scope) = CreateScopedSender();
|
||||
using var _ = scope;
|
||||
|
||||
Reference in New Issue
Block a user