V13-FE-011: finalize search list layout slice
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
using FastEndpoints;
|
||||
using Kbx.Shared.ExternalData;
|
||||
using Kbx.Shared.ExternalData.Generated;
|
||||
using Kbx.Shared.Runtime;
|
||||
using Shared.Problems;
|
||||
|
||||
namespace Kbx.Modules.Common.ExternalData.Refresh;
|
||||
|
||||
public sealed record Response(string DatasetId,string Status);
|
||||
public sealed class Endpoint(IKbxExternalDataRefreshScheduler scheduler):EndpointWithoutRequest<Response>
|
||||
{
|
||||
public override void Configure(){Post("/api/kbx/external-data/{datasetId}/refresh");Permissions("common.external-data.refresh");}
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var datasetId=Route<string>("datasetId")!;
|
||||
if(!KbxExternalDataCatalog.All.TryGetValue(datasetId,out var dataset))
|
||||
{ await Send.ResponseAsync(KbxNotFoundProblem.Create("EXTERNAL_DATASET_NOT_FOUND","외부 데이터셋을 찾을 수 없습니다."),404,cancellation:ct); return; }
|
||||
if(dataset.FreshnessMode=="provider-defined" && dataset.FreshForSeconds is null)
|
||||
{ await Send.ResponseAsync(KbxBusinessProblem.Create("EXTERNAL_DATA_POLICY_REQUIRED","승인된 서비스별 신선도 정책이 먼저 필요합니다.","KRX 범용 데이터셋에는 임의 TTL을 적용하지 않습니다."),422,cancellation:ct); return; }
|
||||
await scheduler.ScheduleDatasetAsync(RuntimeIdentity.TenantId(User),datasetId,ct);
|
||||
await Send.ResponseAsync(new Response(datasetId,"queued"),202,cancellation:ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Dapper;
|
||||
using FastEndpoints;
|
||||
using Npgsql;
|
||||
using Kbx.Shared.ExternalData.Generated;
|
||||
using Kbx.Shared.Runtime;
|
||||
|
||||
namespace Kbx.Modules.Common.ExternalData.Status;
|
||||
|
||||
public sealed record Row(string DatasetId,string ProviderId,string SourceLabel,string State,long CacheEntries,DateTimeOffset? LastReceivedAt,DateTimeOffset? OldestFreshUntil,long StaleEntries,long UnavailableEntries);
|
||||
public sealed record Response(IReadOnlyList<Row> Items);
|
||||
file sealed record DbRow(string DatasetId,string ProviderId,string State,long CacheEntries,DateTimeOffset? LastReceivedAt,DateTimeOffset? OldestFreshUntil,long StaleEntries,long UnavailableEntries);
|
||||
|
||||
public sealed class Endpoint(NpgsqlDataSource dataSource):EndpointWithoutRequest<Response>
|
||||
{
|
||||
public override void Configure(){Get("/api/kbx/external-data/status");Permissions("common.external-data.read");}
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
const string sql="""
|
||||
select dataset_id as DatasetId, provider_id as ProviderId,
|
||||
case
|
||||
when bool_or(fresh_until is not null and now() <= fresh_until) then 'fresh'
|
||||
when bool_or(usable_until is not null and now() <= usable_until) then 'stale'
|
||||
when bool_or(state='unavailable') then 'unavailable'
|
||||
else 'expired'
|
||||
end as State,
|
||||
count(*) as CacheEntries,
|
||||
max(received_at) as LastReceivedAt,
|
||||
min(fresh_until) as OldestFreshUntil,
|
||||
count(*) filter(where fresh_until is not null and now()>fresh_until and usable_until is not null and now()<=usable_until) as StaleEntries,
|
||||
count(*) filter(where state='unavailable') as UnavailableEntries
|
||||
from kbx.external_data_cache
|
||||
where tenant_id=@TenantId
|
||||
group by dataset_id,provider_id
|
||||
""";
|
||||
await using var connection=await dataSource.OpenConnectionAsync(ct);
|
||||
var db=(await connection.QueryAsync<DbRow>(new CommandDefinition(sql,new{TenantId=RuntimeIdentity.TenantId(User)},cancellationToken:ct))).ToDictionary(x=>x.DatasetId,StringComparer.Ordinal);
|
||||
var rows=KbxExternalDataCatalog.All.Values.OrderBy(x=>x.Id,StringComparer.Ordinal).Select(dataset=>{
|
||||
if(db.TryGetValue(dataset.Id,out var current))return new Row(dataset.Id,dataset.ProviderId,dataset.SourceLabel,current.State,current.CacheEntries,current.LastReceivedAt,current.OldestFreshUntil,current.StaleEntries,current.UnavailableEntries);
|
||||
var state=dataset.FreshnessMode=="provider-defined" && dataset.FreshForSeconds is null ? "unavailable" : "expired";
|
||||
return new Row(dataset.Id,dataset.ProviderId,dataset.SourceLabel,state,0,null,null,0,state=="unavailable"?1:0);
|
||||
}).ToArray();
|
||||
await Send.OkAsync(new Response(rows),ct);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user