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