using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
///
/// Default implementation (M9-T32c). Reads the
/// named JSON-Schema library directly from over a
/// fresh DI scope per query — mirroring AuditLogQueryService /
/// KpiHistoryQueryService so a value form's auto-load never races other reads on
/// the shared circuit-scoped DbContext. Read-only; no mutation goes through here.
///
public sealed class SchemaLibraryQueryService : ISchemaLibraryQueryService
{
private readonly IServiceScopeFactory _scopeFactory;
///
/// Initializes a new instance of the .
///
/// Factory used to open a fresh DI scope (and DbContext) per query.
public SchemaLibraryQueryService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
}
///
public async Task> GetSchemaMapAsync(
CancellationToken cancellationToken = default)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var repo = scope.ServiceProvider.GetRequiredService();
var all = await repo.ListAsync(cancellationToken);
// Ordinal-keyed to match the lib:Name resolver's exact-name lookup. Name is
// DB-unique, so a list yields at most one row per name and no real collision
// occurs; the indexer assignment is defensive only — should two rows ever share
// a name (e.g. a mid-write transient read), the later one in enumeration order
// overwrites the earlier rather than throwing.
var map = new Dictionary(StringComparer.Ordinal);
foreach (var schema in all)
{
map[schema.Name] = schema.SchemaJson;
}
return map;
}
///
public async Task ResolveAsync(string name, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
await using var scope = _scopeFactory.CreateAsyncScope();
var repo = scope.ServiceProvider.GetRequiredService();
var schema = await repo.GetByNameAsync(name, cancellationToken);
return schema?.SchemaJson;
}
}