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
};
}
}