V13-FE-011: finalize search list layout slice
This commit is contained in:
+91
@@ -0,0 +1,91 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Shared.Operations;
|
||||
|
||||
public sealed record UpsertWorkItem(
|
||||
string TenantId,
|
||||
string SourceModule,
|
||||
string SourceType,
|
||||
string SourceId,
|
||||
string ReferenceNo,
|
||||
string? SourceScreenId,
|
||||
long? SourceVersion,
|
||||
string Code,
|
||||
string Title,
|
||||
string? Detail,
|
||||
string Severity,
|
||||
DateTimeOffset OccurredAt,
|
||||
DateTimeOffset? DueAt = null,
|
||||
string? RetryActionKey = null,
|
||||
bool AllowManualResolution = false,
|
||||
object? Context = null);
|
||||
|
||||
public sealed class OperationsProjectionWriter(NpgsqlDataSource dataSource)
|
||||
{
|
||||
public async Task<Guid> UpsertAsync(UpsertWorkItem item, CancellationToken ct)
|
||||
{
|
||||
await using var connection = await dataSource.OpenConnectionAsync(ct);
|
||||
var id = Guid.NewGuid();
|
||||
const string sql = """
|
||||
insert into kbx.work_items(
|
||||
id, tenant_id, source_module, source_type, source_id, reference_no, source_screen_id, source_version,
|
||||
code, title, detail, severity, status, retry_action_key, allow_manual_resolution,
|
||||
context, occurred_at, due_at)
|
||||
values(
|
||||
@Id, @TenantId, @SourceModule, @SourceType, @SourceId, @ReferenceNo, @SourceScreenId, @SourceVersion,
|
||||
@Code, @Title, @Detail, @Severity, 'open', @RetryActionKey, @AllowManualResolution,
|
||||
cast(@Context as jsonb), @OccurredAt, @DueAt)
|
||||
on conflict(tenant_id, source_module, source_type, source_id, code)
|
||||
do update set
|
||||
source_version = excluded.source_version,
|
||||
reference_no = excluded.reference_no,
|
||||
source_screen_id = excluded.source_screen_id,
|
||||
title = excluded.title,
|
||||
detail = excluded.detail,
|
||||
severity = excluded.severity,
|
||||
status = case when kbx.work_items.status = 'resolved' then 'open' else kbx.work_items.status end,
|
||||
retry_action_key = excluded.retry_action_key,
|
||||
allow_manual_resolution = excluded.allow_manual_resolution,
|
||||
context = excluded.context,
|
||||
occurred_at = excluded.occurred_at,
|
||||
due_at = excluded.due_at,
|
||||
resolved_at = null,
|
||||
resolution_reason = null,
|
||||
version = kbx.work_items.version + 1,
|
||||
updated_at = now()
|
||||
where excluded.source_version is null
|
||||
or kbx.work_items.source_version is null
|
||||
or excluded.source_version > kbx.work_items.source_version
|
||||
returning id;
|
||||
""";
|
||||
var args = new {
|
||||
Id = id,
|
||||
item.TenantId, item.SourceModule, item.SourceType, item.SourceId, item.ReferenceNo, item.SourceScreenId, item.SourceVersion,
|
||||
item.Code, item.Title, item.Detail, item.Severity, item.RetryActionKey, item.AllowManualResolution,
|
||||
Context = JsonSerializer.Serialize(item.Context ?? new { }), item.OccurredAt, item.DueAt
|
||||
};
|
||||
var changedId = await connection.ExecuteScalarAsync<Guid?>(new CommandDefinition(sql, args, cancellationToken: ct));
|
||||
if (changedId is not null) return changedId.Value;
|
||||
return await connection.ExecuteScalarAsync<Guid>(new CommandDefinition("""
|
||||
select id from kbx.work_items
|
||||
where tenant_id=@TenantId and source_module=@SourceModule and source_type=@SourceType
|
||||
and source_id=@SourceId and code=@Code;
|
||||
""", args, cancellationToken: ct));
|
||||
}
|
||||
|
||||
public async Task ResolveBySourceAsync(string tenantId, string sourceModule, string sourceType, string sourceId, string code, string reason, long? sourceVersion, CancellationToken ct)
|
||||
{
|
||||
await using var connection = await dataSource.OpenConnectionAsync(ct);
|
||||
await connection.ExecuteAsync(new CommandDefinition("""
|
||||
update kbx.work_items
|
||||
set status = 'resolved', resolved_at = now(), resolution_reason = @Reason,
|
||||
source_version = coalesce(@SourceVersion, source_version),
|
||||
version = version + 1, updated_at = now()
|
||||
where tenant_id = @TenantId and source_module = @SourceModule and source_type = @SourceType
|
||||
and source_id = @SourceId and code = @Code and status <> 'resolved'
|
||||
and (@SourceVersion is null or source_version is null or @SourceVersion >= source_version);
|
||||
""", new { TenantId = tenantId, SourceModule = sourceModule, SourceType = sourceType, SourceId = sourceId, Code = code, Reason = reason, SourceVersion = sourceVersion }, cancellationToken: ct));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user