using Admin.NET.Plugin.AiDOP.Entity.S8; using SqlSugar; namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess; /// /// LEGACY_SQL 取数抽象。抽出接口是为了让"STANDARD_DATASET 绝不回落 Legacy" /// 这条边界可以被测试真实验证(注入探针后断言调用次数为 0),而不是只靠代码审阅。 /// public interface IS8LegacySqlDataProvider { Task LoadAsync( long tenantId, long factoryId, AdoS8WatchRule rule, string ruleType, int timeoutSeconds, CancellationToken cancellationToken = default); } /// /// LEGACY_SQL 取数适配器:把既有"规则自带 expression + data_source_id"的取数结果 /// 转换为统一的 canonical 行集合,使 evaluator 不再直接依赖 。 /// /// 本类**逐行保留迁移前的行为**(数据源查询条件、失败 reason 码、异常消息措辞), /// 132 条历史规则的运行结果因此不发生变化。 /// public class S8LegacySqlDataProvider : IS8LegacySqlDataProvider, ITransient { private readonly SqlSugarRepository _dataSourceRep; private readonly S8DataSourceRowLoader _rowLoader; public S8LegacySqlDataProvider( SqlSugarRepository dataSourceRep, S8DataSourceRowLoader rowLoader) { _dataSourceRep = dataSourceRep; _rowLoader = rowLoader; } /// /// 按规则的 data_source_id + expression 取数。 /// 数据源不可用 → data_source_unavailable;SQL/API 执行失败 → query_failed。两者 reason 码与迁移前一致。 /// public async Task LoadAsync( long tenantId, long factoryId, AdoS8WatchRule rule, string ruleType, int timeoutSeconds, CancellationToken cancellationToken = default) { var dataSource = await _dataSourceRep.AsQueryable() .Where(x => x.Id == rule.DataSourceId && x.TenantId == tenantId && x.FactoryId == factoryId && x.Enabled) .FirstAsync(); if (dataSource == null || string.IsNullOrWhiteSpace(dataSource.Endpoint) || !S8DataSourceRowLoader.IsSupportedType(dataSource.Type)) { throw new S8RuleEvaluatorException( "data_source_unavailable", $"{ruleType} 规则 {rule.RuleCode} 数据源不可用(id={rule.DataSourceId})"); } System.Data.DataTable table; try { table = await _rowLoader.LoadAsync( dataSource, rule.Expression!, _dataSourceRep.Context.CurrentConnectionConfig.DbType, timeoutSeconds, cancellationToken); } catch (Exception ex) { throw new S8RuleEvaluatorException( "query_failed", $"{ruleType} 规则 {rule.RuleCode} 取数失败:{ex.Message}", ex); } return new S8MonitoringDataResult { RowSet = S8MonitoringRowSet.FromDataTable(table), DataSourceId = dataSource.Id, DataAccessMode = S8DataAccessMode.LegacySql }; } }