namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess;
///
/// 数据集能力声明,分两层:
///
/// A. 机制能力(SupportsXxx):该数据集打算支撑哪几类规则判定。
/// B. 字段能力(HasXxx):该数据集实际能提供哪些 canonical 字段。
///
/// 分两层的理由:单一布尔位不可信。声明 SupportsTimeout=true 却拿不出 due_at 是一种
/// 自相矛盾的配置,运行期只会表现为"永不命中"的静默失效。两层交叉校验才能在启用前发现。
///
/// 字段能力回答的是"这个数据集有没有这个字段",与"某一行该字段值为 NULL"是两件事:
/// 前者是能力问题(规则不能启用),后者由 evaluator 按原规则跳过该行。
///
public sealed class S8DatasetCapabilities
{
// ---------- A. 机制能力 ----------
/// 可支撑 TIMEOUT。
public bool SupportsTimeout { get; init; }
/// 可支撑 SHORTAGE。
public bool SupportsShortage { get; init; }
/// 可支撑 OUT_OF_RANGE。
public bool SupportsOutOfRange { get; init; }
// ---------- B. 字段能力 ----------
/// 能提供 source_object_id(对象身份 + DedupKey 输入)。
public bool HasSourceObjectId { get; init; }
/// 能提供 related_object_code。
public bool HasRelatedObjectCode { get; init; }
/// 能提供 due_at。
public bool HasDueAt { get; init; }
/// 能提供 status。
public bool HasStatus { get; init; }
/// 能提供 measured_value。
public bool HasMeasuredValue { get; init; }
/// 能提供 target_qty。
public bool HasTargetQty { get; init; }
/// 能提供 actual_qty。
public bool HasActualQty { get; init; }
/// 该数据集是否声明支持给定规则类型(仅机制层,未校验字段是否齐备)。
public bool Supports(string? ruleType)
{
if (string.IsNullOrWhiteSpace(ruleType)) return false;
return ruleType.Trim().ToUpperInvariant() switch
{
"TIMEOUT" => SupportsTimeout,
"SHORTAGE" => SupportsShortage,
"OUT_OF_RANGE" => SupportsOutOfRange,
_ => false
};
}
/// 该数据集是否能提供给定 canonical 字段。
public bool HasField(string? canonicalColumn)
{
if (string.IsNullOrWhiteSpace(canonicalColumn)) return false;
return canonicalColumn.Trim().ToLowerInvariant() switch
{
S8CanonicalColumns.SourceObjectId => HasSourceObjectId,
S8CanonicalColumns.RelatedObjectCode => HasRelatedObjectCode,
S8CanonicalColumns.DueAt => HasDueAt,
S8CanonicalColumns.Status => HasStatus,
S8CanonicalColumns.MeasuredValue => HasMeasuredValue,
S8CanonicalColumns.TargetQty => HasTargetQty,
S8CanonicalColumns.ActualQty => HasActualQty,
_ => false
};
}
///
/// 返回该规则类型缺少的 canonical 字段。空集合表示字段能力齐备。
/// 未知规则类型返回 null(由调用方按 unknown_rule_type 处理,与"字段缺失"区分)。
///
public IReadOnlyList? MissingFieldsFor(string? ruleType)
{
var required = S8RuleTypeFieldRequirements.For(ruleType);
if (required == null) return null;
return required.Where(field => !HasField(field)).ToList();
}
/// 机制能力与字段能力是否都满足该规则类型。
public bool CanServe(string? ruleType)
{
if (!Supports(ruleType)) return false;
var missing = MissingFieldsFor(ruleType);
return missing != null && missing.Count == 0;
}
}