public static void FromOperationResultAddUpdateValue(this ProcessingRulEngStore newState, JToken result, Guid destEntId) { // Create/Update a Value using destEnt.EntityId and result var detail = result; var value = newState.Values.FirstOrDefault(o => o.EntityId == destEntId); if (value != null) { if (detail != null) { value.Detail = detail; } value.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { value = new Value { EntityId = destEntId, Detail = detail, LastChanged = DateTime.UtcNow }; newState.Values.Add(value); } }
/// <summary> /// Perform all HasMeaningfulValue and Not HasMeaningfulValue Rules /// </summary> /// <param name="newState"></param> /// <param name="prescription"></param> /// <returns></returns> public static ProcessingRulEngStore AllHasMeaningfulValue(this ProcessingRulEngStore newState, ProcessHasMeaningfulValueRule prescription) { if (prescription == null) { return(newState); } var actionDate = DateTime.UtcNow; // First identify the potentially relevant Entities var entities = newState.Values.Select(v => (IEntity)v).ToList(); // Get all the rules to process var rulesToProcessList = newState.Rules.RulesToProcess(RuleType.HasMeaningfulValue, entities); foreach (var ruleToProcess in rulesToProcessList) { var refValue = newState.Values.FirstOrDefault(v => v.EntityId == ruleToProcess.ReferenceValues.EntityIds[0].EntityId); //var entitiesToAdd = ruleToProcess.ReferenceValues.Except(entities).ToList(); var newRuleResult = new RuleResult { RuleId = ruleToProcess.RuleId, LastChanged = actionDate, Detail = refValue.HasMeaningfulValue() }; newState.RuleResults.Add(newRuleResult); ruleToProcess.LastExecuted = actionDate; } return(newState); }
public static void FromOperationResultAddUpdateOperation(this ProcessingRulEngStore newState, JToken result, Guid destEntId) { // Create/Update an Operation using destEnt.EntityId and result var operationType = result["OperationType"]; var ruleResultId = result["RuleResultId"]; var operationTemplate = result["OperationTemplate"]; var operands = result["Operands"]; var opType = operationType?.ToObject <OperationType>() ?? OperationType.Unknown; var rlResId = ruleResultId?.ToObject <Guid>() ?? Guid.Empty; var opTempl = operationTemplate == null ? string.Empty : operationTemplate.ToString().Trim(); var oprndArray = operands == null ? ImmutableArray <OperandKey> .Empty : ImmutableArray.Create(operands.ToObject <OperandKey[]>()); if (ruleResultId == null || string.IsNullOrWhiteSpace(opTempl) || operands == null) { opType = OperationType.Error; } var operation = newState.Operations.FirstOrDefault(o => o.EntityId == destEntId); if (operation != null) { if (operationType != null) { operation.OperationType = opType; } if (ruleResultId != null) { operation.RuleResultId = rlResId; } if (operationTemplate != null) { operation.OperationTemplate = opTempl; } if (operands != null) { operation.Operands = oprndArray; } operation.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { operation = new Operation { EntityId = destEntId, OperationType = opType, RuleResultId = rlResId, OperationTemplate = opTempl, Operands = oprndArray, LastChanged = DateTime.UtcNow }; newState.Operations.Add(operation); } }
public static T GetEntityFromValue <T>(this ProcessingRulEngStore newState, OperandKey entity) where T : IEntity { var newEntity = default(T); var refValueId = entity.SourceEntityIds.FirstOrDefault(); if (refValueId != null) { newEntity = ((JProperty)newState.Values.FirstOrDefault(v => v.ValueId == refValueId).Detail).ToObject <T>(); } newEntity.EntityId = entity.EntityId; return(newEntity); }
public static void FromOperationResultAddUpdateRequest(this ProcessingRulEngStore newState, JToken result, Guid destEntId) { // Create/Update a Request using destEnt.EntityId and result var valueType = result["ValueType"]; var ruleResultId = result["RuleResultId"]; var query = result["Query"]; var vlType = valueType?.ToObject <JTokenType>() ?? JTokenType.None; var rlResId = ruleResultId?.ToObject <Guid>() ?? Guid.Empty; var qry = query?.ToObject <IObjectGraphType>(); if (ruleResultId == null || qry == null) { vlType = JTokenType.Undefined; } var request = newState.Requests.FirstOrDefault(o => o.EntityId == destEntId); if (request != null) { if (valueType != null) { request.ValueType = vlType; } if (ruleResultId != null) { request.RuleResultId = rlResId; } if (query != null) { request.Query = qry; } request.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { request = new Request { EntityId = destEntId, ValueType = vlType, Query = qry, RuleResultId = rlResId, LastChanged = DateTime.UtcNow }; newState.Requests.Add(request); } }
public static void FromOperationResultAddUpdateRule(this ProcessingRulEngStore newState, JToken result, Guid destEntId) { // Create/Update a rule using destEnt.EntityId and result var ruleType = result["RuleType"]; var negateResult = result["NegateResult"]; var referenceValues = result["ReferenceValues"]; var rlType = ruleType?.ToObject <RuleType>() ?? RuleType.Unknown; var refValArray = referenceValues?.ToObject <IRulePrescription>(); if (refValArray == null) { rlType = RuleType.Error; } var rule = newState.Rules.FirstOrDefault(r => r.EntityId == destEntId); if (rule != null) { if (negateResult != null) { rule.NegateResult = (bool)negateResult; } if (ruleType != null) { rule.RuleType = rlType; } if (referenceValues != null) { rule.ReferenceValues = refValArray; } rule.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { rule = new Rule { EntityId = destEntId, NegateResult = negateResult != null && (bool)negateResult, RuleType = rlType, ReferenceValues = refValArray, LastChanged = DateTime.UtcNow }; newState.Rules.Add(rule); } }
public static Operation FromSearchOperationAddUpdateOperation(this ProcessingRulEngStore newState, IEntity sourceEnt, List <string> entTags, OperationType opType, string operationTemplate, Guid destEntId) { // Create/Update an operation using destEnt.EntityId and result var ruleResultId = sourceEnt.EntityId; var opTempl = string.IsNullOrWhiteSpace(operationTemplate) ? string.Empty : operationTemplate.Trim(); entTags = (entTags == null || entTags.Count == 0) ? sourceEnt.EntTags : entTags; var refValArray = sourceEnt.RulePrescription <RuleUnary>(); var operation = newState.Operations.FirstOrDefault(r => r.EntityId == destEntId); if (operation != null) { operation.OperationId = destEntId; operation.OperationType = opType; operation.RuleResultId = ruleResultId; operation.OperationTemplate = opTempl; operation.EntTags = entTags; //operation.ReferenceValues = refValArray; operation.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { operation = new Operation { OperationId = destEntId, OperationType = opType, RuleResultId = ruleResultId, OperationTemplate = opTempl, EntTags = entTags, // Operands = oprndArray, LastChanged = DateTime.UtcNow }; newState.Operations.Add(operation); } return(operation); }
public static Rule FromSearchOperationAddUpdateExistsRule(this ProcessingRulEngStore newState, IEntity sourceEnt, List <string> entTags, Guid destEntId) { // Create/Update a rule using destEnt.EntityId and result const RuleType rlType = RuleType.Exists; entTags = (entTags == null || entTags.Count == 0) ? sourceEnt.EntTags : entTags; var refValArray = sourceEnt.RulePrescription <RuleUnary>(); var ruleName = $"Test for existence of {sourceEnt.EntType.ToString()} {(TypeKey)sourceEnt}"; var rule = newState.Rules.FirstOrDefault(r => r.EntityId == destEntId); if (rule != null) { rule.RuleName = ruleName; rule.NegateResult = false; rule.RuleType = rlType; rule.EntTags = entTags; rule.ReferenceValues = refValArray; rule.LastChanged = DateTime.UtcNow; // TODO: Confirm the existing entity is updated } else { rule = new Rule { EntityId = destEntId, RuleName = ruleName, NegateResult = false, RuleType = rlType, EntTags = entTags, ReferenceValues = refValArray, LastChanged = DateTime.UtcNow }; newState.Rules.Add(rule); } return(rule); }
private static ProcessingRulEngStore AllOperations(this ProcessingRulEngStore newState, RulEngStore previousState, IOpReqProcessing prescription) { // First identify RuleResults that have just been processed successfully var ruleResultIds = newState.RuleResults .Where(v => v.Detail) .Select(v => v.RuleResultId) .ToList(); var opType = prescription is OperationMxProcessing ? OperationType.CreateUpdate : prescription is OperationDxProcessing ? OperationType.Delete : prescription is OperationSxProcessing ? OperationType.Search : OperationType.Unknown; // When the prescription is for requests // Find all relevant operations/requests for the identified rule results and then filter down by execution date var possibleOps = newState.Operations .Where(a => ruleResultIds.Contains(a.RuleResultId) && a.OperationType == opType).ToList(); var operationprescriptionsToProcessList = ( from op in possibleOps let rr = newState.RuleResults.First(r => r.RuleResultId == op.RuleResultId) where rr.LastChanged > op.LastExecuted select op) .ToList(); var requestprescriptionsToProcessList = ( from rq in newState.Requests.Where(a => ruleResultIds.Contains(a.RuleResultId)) let rr = newState.RuleResults.First(r => r.RuleResultId == rq.RuleResultId) where rr.LastChanged > rq.LastExecuted select rq) .ToList(); // Restrict the Operation/Request Prescriptions to process to those that are guaranteed not to fail // Select those for which there is no conflict var destinationEntities = new List <TypeKey>(); foreach (var opPre in operationprescriptionsToProcessList) { destinationEntities.AddRange(opPre.Operands.Select(o => (TypeKey)o)); } foreach (var rqPre in requestprescriptionsToProcessList) { destinationEntities.Add(rqPre); } var groupedDestinations = destinationEntities .GroupBy(de => new EntMatch { EntityId = de.EntityId, EntType = de.EntType }) .Select(grp => new { grp.Key, Count = grp.Count() }) .ToList(); //var conflictDestinations = groupedDestinations // .Where(grp => grp.Count > 1) // .Select(grp => new TypeKey { EntityId = grp.Key.EntityId, EntTags = grp.Key.EntTags, EntType = grp.Key.EntType }) // .ToList(); var acceptableDestinations = groupedDestinations .Where(grp => grp.Count == 1) .Select(grp => grp.Key) .ToList(); if (prescription is OperationMxProcessing) { newState = OperationMxProcessing(newState, previousState, ruleResultIds, operationprescriptionsToProcessList, acceptableDestinations); } if (prescription is OperationDxProcessing) { newState = OperationDxProcessing(newState, ruleResultIds, operationprescriptionsToProcessList, acceptableDestinations); } if (prescription is OperationSxProcessing) { newState = OperationSxProcessing(newState, previousState, ruleResultIds, operationprescriptionsToProcessList, acceptableDestinations); } return(newState); }
private static ProcessingRulEngStore OperationSxProcessing(this ProcessingRulEngStore newState, RulEngStore previousState, List <Guid> ruleResultIds, List <Operation> operationprescriptionsToProcessList, List <EntMatch> acceptableDestinations) { // Get all of the sources from the previous state var acceptableSourceIds = new List <Guid>(); //foreach (var opPresProc in operationprescriptionsToProcessList) //{ // var opPresOperands = opPresProc.Operands; // var matchFound = false; // foreach (var opo in opPresOperands) // { // if (!acceptableDestinations // .Any(ad => ad.EntType == opo.EntType && (ad.EntityId == opo.EntityId || opo.EntityId == Guid.Empty))) // { // continue; // } // matchFound = true; // break; // } // if (!matchFound) // { // continue; // } // acceptableSourceIds.AddRange(opPresOperands.SelectMany(oo => oo.SourceValueIds)); //} //var acceptableSources = previousState.Values // .Where(v => acceptableSourceIds.Contains(v.EntityId)) // .ToList(); var e = new Engine(); foreach (var ruleResultIdToProcess in ruleResultIds) { // Get all of the operations relevant to the Rule var relevantOps = operationprescriptionsToProcessList .Where(o => o.RuleResultId == ruleResultIdToProcess) .ToList(); if (!relevantOps.Any()) { // TODO: confirm if we should be doing this if there was nothing relevant to process //newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); continue; } // Process the acceptable foreach (var relevantOp in relevantOps) { // Note: A Search operation does not specify an output destination as it does not 'know' in advance how many results will be found // However, it may specify a reduced set of Ids to search through. // These will be provided in the SourceValueIds field of each relevantOp.Operand // var firstEnt = new EntMatch // { // EntityId = relevantOp.Operands[0].EntityId, // EntType = relevantOp.Operands[0].EntType // }; // if (!acceptableDestinations.Any(ad => // ad.EntType == firstEnt.EntType && ad.EntityId == firstEnt.EntityId)) // { // continue; // } // var destEntsToProcess = relevantOp.Operands // .Select(de => new // { // de.EntityId, // EntType = Convert.ToInt32(de.EntType), // sourceValues = de.SourceValueIds // .Select(sv => JObject.Parse($"{{\"Id\":\"{sv}\",\"Value\":{acceptableSources.FirstOrDefault(a => a.EntityId == sv)?.Detail.ToString(Formatting.None)}}}")) // .ToArray() // }) // .ToList(); switch (relevantOp.Operands[0].SourceEntType) { case EntityType.Rule: e.SetValue("source", JsonConvert.SerializeObject(previousState.Rules.ToArray())); break; case EntityType.RuleResult: e.SetValue("source", JsonConvert.SerializeObject(previousState.RuleResults.ToArray())); break; case EntityType.Operation: e.SetValue("source", JsonConvert.SerializeObject(previousState.Operations.ToArray())); break; case EntityType.Request: e.SetValue("source", JsonConvert.SerializeObject(previousState.Requests.ToArray())); break; case EntityType.Value: e.SetValue("source", JsonConvert.SerializeObject(previousState.Values.ToArray())); break; } // The result must be a list of guids for the entities that met the search criteria var result = e .Execute(relevantOp.OperationTemplate) .GetCompletionValue(); var sourceGuids = result.ToString() .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(Guid.Parse) .ToList(); for (var ix = 0; ix < sourceGuids.Count; ix++) { var sourceEnt = new TypeKey { EntityId = sourceGuids[ix], EntType = relevantOp.Operands[0].SourceEntType, EntTags = relevantOp.EntTags } as IEntity; switch (relevantOp.Operands[0].EntType) { case EntityType.Rule: // Create/Update a rule using destEnt.EntityId and result var rl = newState.FromSearchOperationAddUpdateExistsRule(sourceEnt, relevantOp.EntTags, GuidHelpers.NewTimeUuid()); var rr = new RuleResult(rl); newState.RuleResults.Add(rr); break; case EntityType.Operation: // Create/Update an Operation using destEnt.EntityId and result var op = newState.FromSearchOperationAddUpdateOperation(sourceEnt, relevantOp.EntTags, OperationType.Delete, "", GuidHelpers.NewTimeUuid()); //var rr = new RuleResult(rl); //newState.RuleResults.Add(rr); //newState.FromOperationResultAddUpdateOperation(result, destEnt.EntityId); break; //case EntityType.Request: // // Create/Update a Request using destEnt.EntityId and result // newState.FromOperationResultAddUpdateRequest(result, destEnt.EntityId); // break; //case EntityType.Value: // // Create/Update a Value using destEnt.EntityId and result // newState.FromOperationResultAddUpdateValue(result, destEnt.EntityId); // break; // } } //var values = new List<string>(); //for (var i = 0; i < a.GetLength(); i++) //{ // values.Add(a.Get(i.ToString()).AsString()); //} //return values; Console.WriteLine(JsonConvert.SerializeObject(result)); // foreach (var destEnt in destEntsToProcess) // { // var sourceVals = destEnt.sourceValues; // var isSubstOk = true; // foreach (Match match in regexToken.Matches(jTempl)) // { // var token = match.Groups["Token"].Value; // var indexOk = int.TryParse(match.Groups["Index"].Value, out var index); // if (!indexOk) // { // break; // } // if (sourceVals.Length < index) // { // isSubstOk = false; // break; // } // jCode = jCode.Replace(token, sourceVals[index]["Value"].ToString(Formatting.None)); // } // if (!isSubstOk) // { // Console.WriteLine(jCode); // continue; // } // JToken result = null; // if (jCode.StartsWith("{")) // { // result = JObject.FromObject(e.Execute(jCode).GetCompletionValue().ToObject()); // } // if (jCode.StartsWith("[")) // { // result = JArray.FromObject(e.Execute(jCode).GetCompletionValue().ToObject()); // } // //Console.WriteLine(result); // switch ((EntityType)destEnt.EntType) // { // case EntityType.Rule: // // Create/Update a rule using destEnt.EntityId and result // newState.FromOperationResultAddUpdateRule(result, destEnt.EntityId); // break; // case EntityType.Operation: // // Create/Update an Operation using destEnt.EntityId and result // newState.FromOperationResultAddUpdateOperation(result, destEnt.EntityId); // break; // case EntityType.Request: // // Create/Update a Request using destEnt.EntityId and result // newState.FromOperationResultAddUpdateRequest(result, destEnt.EntityId); // break; // case EntityType.Value: // // Create/Update a Value using destEnt.EntityId and result // newState.FromOperationResultAddUpdateValue(result, destEnt.EntityId); // break; // } // // Mark the operation as Executed // var actionDate = DateTime.UtcNow; // // Mark this Rule as executed // relevantOp.LastExecuted = actionDate; // } } // newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); } } return(newState); }
private static ProcessingRulEngStore OperationDxProcessing(this ProcessingRulEngStore newState, List <Guid> ruleResultIds, List <Operation> operationprescriptionsToProcessList, List <EntMatch> acceptableDestinations) { foreach (var ruleResultIdToProcess in ruleResultIds) { // Get all of the operations relevant to the Rule var relevantOps = operationprescriptionsToProcessList .Where(o => o.RuleResultId == ruleResultIdToProcess) .ToList(); if (!relevantOps.Any()) { // TODO: confirm if we should be doing this if there was nothing relevant to process //newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); continue; } // Process the acceptable foreach (var relevantOp in relevantOps) { var firstEnt = new EntMatch { EntityId = relevantOp.Operands[0].EntityId, EntType = relevantOp.Operands[0].EntType }; if (!acceptableDestinations.Any(ad => ad.EntType == firstEnt.EntType && ad.EntityId == firstEnt.EntityId)) { continue; } //Console.WriteLine(result); switch (firstEnt.EntType) { case EntityType.Rule: var removeRl = newState.Rules.FirstOrDefault(r => r.RuleId == firstEnt.EntityId); var removeRr = newState.RuleResults.FirstOrDefault(r => r.RuleId == firstEnt.EntityId); var rrId = removeRr.RuleResultId; newState.Rules.Remove(removeRl); newState.RuleResults.Remove(removeRr); // The directly dependent Operations and Requests are now orphaned // They should be deleted, they will never execute again var removeOp = newState.Operations.Where(o => o.RuleResultId == rrId); var removeRq = newState.Requests.Where(r => r.RuleResultId == rrId); foreach (var op in removeOp) { newState.Operations.Remove(op); } foreach (var rq in removeRq) { newState.Requests.Remove(rq); } break; case EntityType.Operation: newState.Operations.RemoveWhere(r => r.OperationId == firstEnt.EntityId); break; case EntityType.Request: newState.Requests.RemoveWhere(r => r.RequestId == firstEnt.EntityId); break; case EntityType.Value: var removeVal = newState.Values.FirstOrDefault(v => v.ValueId == firstEnt.EntityId); newState.Values.Remove(removeVal); break; } // Mark the operation as Executed var actionDate = DateTime.UtcNow; // Mark this Rule as executed relevantOp.LastExecuted = actionDate; } // newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); } return(newState); }
private static ProcessingRulEngStore OperationMxProcessing(this ProcessingRulEngStore newState, RulEngStore previousState, List <Guid> ruleResultIds, List <Operation> operationprescriptionsToProcessList, List <EntMatch> acceptableDestinations) { // Get all of the sources from the previous state var acceptableSourceIds = new List <Guid>(); foreach (var opPresProc in operationprescriptionsToProcessList) { var opPresOperands = opPresProc.Operands; var matchFound = false; foreach (var opo in opPresOperands) { if (!acceptableDestinations .Any(ad => ad.EntType == opo.EntType && ad.EntityId == opo.EntityId)) { continue; } matchFound = true; break; } if (!matchFound) { continue; } acceptableSourceIds.AddRange(opPresOperands.SelectMany(oo => oo.SourceEntityIds)); } var acceptableSources = previousState.Values .Where(v => acceptableSourceIds.Contains(v.EntityId)) .ToList(); var e = new Engine(); var regexToken = new Regex(@".*?(?<Token>\$\{(?<Index>\d+)\}).*?"); foreach (var ruleResultIdToProcess in ruleResultIds) { // Get all of the operations relevant to the Rule var relevantOps = operationprescriptionsToProcessList .Where(o => o.RuleResultId == ruleResultIdToProcess) .ToList(); if (!relevantOps.Any()) { // TODO: confirm if we should be doing this if there was nothing relevant to process //newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); continue; } // Process the acceptable foreach (var relevantOp in relevantOps) { // Ensure the first entity in the operation is an acceptable destination EntMatch firstEnt = relevantOp.Operands[0]; if (!acceptableDestinations.Any(ad => ad.EntType == firstEnt.EntType && ad.EntityId == firstEnt.EntityId)) { continue; } var destEntsToProcess = relevantOp.Operands .Select(de => new { de.EntityId, EntType = Convert.ToInt32(de.EntType), sourceValues = de.SourceEntityIds .Select(sv => JObject.Parse($"{{\"Id\":\"{sv}\",\"Value\":{acceptableSources.FirstOrDefault(a => a.EntityId == sv)?.Detail.ToString(Formatting.None)}}}")) .ToArray() }) .ToList(); var jTempl = relevantOp.OperationTemplate; var jCode = jTempl; foreach (var destEnt in destEntsToProcess) { var sourceVals = destEnt.sourceValues; var isSubstOk = true; foreach (Match match in regexToken.Matches(jTempl)) { var token = match.Groups["Token"].Value; var indexOk = int.TryParse(match.Groups["Index"].Value, out var index); if (!indexOk) { break; } if (sourceVals.Length < index) { isSubstOk = false; break; } jCode = jCode.Replace(token, sourceVals[index]["Value"].ToString(Formatting.None)); } if (!isSubstOk) { Console.WriteLine(jCode); continue; } JToken result = null; if (jCode.StartsWith("{")) { result = JObject.FromObject(e.Execute(jCode).GetCompletionValue().ToObject()); } if (jCode.StartsWith("[")) { result = JArray.FromObject(e.Execute(jCode).GetCompletionValue().ToObject()); } //Console.WriteLine(result); switch ((EntityType)destEnt.EntType) { case EntityType.Rule: // Create/Update a rule using destEnt.EntityId and result newState.FromOperationResultAddUpdateRule(result, destEnt.EntityId); break; case EntityType.Operation: // Create/Update an Operation using destEnt.EntityId and result newState.FromOperationResultAddUpdateOperation(result, destEnt.EntityId); break; case EntityType.Request: // Create/Update a Request using destEnt.EntityId and result newState.FromOperationResultAddUpdateRequest(result, destEnt.EntityId); break; case EntityType.Value: // Create/Update a Value using destEnt.EntityId and result newState.FromOperationResultAddUpdateValue(result, destEnt.EntityId); break; } // Mark the operation as Executed var actionDate = DateTime.UtcNow; // Mark this Rule as executed relevantOp.LastExecuted = actionDate; } } // newState.RuleResults.RemoveWhere(r => r.RuleResultId == ruleResultIdToProcess); } return(newState); }
/// <summary> /// Perform all Compare Rules /// </summary> /// <param name="newState"></param> /// <param name="prescription"></param> /// <param name="ruleType"></param> /// <returns></returns> public static ProcessingRulEngStore AllCompare(this ProcessingRulEngStore newState, IRuleValueProcessing prescription, RuleType ruleType) { if (prescription == null) { return(newState); } var minEntitiesRequired = prescription.Entities.MinEntitiesRequired; if (prescription.Entities.EntityIds.Count < minEntitiesRequired) { return(newState); } var compareRuleTypes = new [] { RuleType.LessThan, RuleType.Equal, RuleType.GreaterThan, RuleType.RegularExpression }; if (!compareRuleTypes.Contains(ruleType)) { throw new ArgumentOutOfRangeException(nameof(ruleType), $"{nameof(ruleType)} must be a comparison RuleType"); } var actionDate = DateTime.UtcNow; // First get the potentially relevant entities (Values only) in a cleaned form var ruleResultId = prescription.Entities.RuleResultId; var ruleResultEntitySet = new { RuleResultId = ruleResultId, Entities = new List <Value>(), EntityIds = prescription.Entities.EntityIds .Where(ve => ve.EntType == EntityType.Value) .Select(ve => ve.EntityId) .ToList() }; ruleResultEntitySet.Entities .AddRange(newState.Values.Where(v => ruleResultEntitySet.EntityIds.Contains(v.EntityId))); var entities = ruleResultEntitySet.Entities .Select(v => (IEntity)v) .ToList(); // Get the corresponding Rules var rulesToProcessList = newState.Rules.RulesToProcess(ruleType, entities); var presEntities = ruleResultEntitySet.Entities.ToArray(); var ruleToProcess = rulesToProcessList .SingleOrDefault(r => r.ReferenceValues.RuleResultId == ruleResultId); RuleResult newRuleResult = null; switch (ruleType) { case RuleType.LessThan: newRuleResult = ruleToProcess.LessThanTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; case RuleType.Equal: newRuleResult = ruleToProcess.EqualTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; case RuleType.GreaterThan: newRuleResult = ruleToProcess.GreaterThanTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; case RuleType.RegularExpression: newRuleResult = ruleToProcess.RegexTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; } if (newRuleResult != null) { newState.RuleResults.Add(newRuleResult); } return(newState); }
/// <summary> /// Perform all Collection Rules /// </summary> /// <param name="newState"></param> /// <param name="prescription"></param> /// <param name="ruleType"></param> /// <returns></returns> public static ProcessingRulEngStore AllCollection(this ProcessingRulEngStore newState, IRuleRuleResultProcessing prescription, RuleType ruleType) { if (prescription == null) { return(newState); } var collectionRuleTypes = new[] { RuleType.And, RuleType.Or, RuleType.Xor }; if (!collectionRuleTypes.Contains(ruleType)) { throw new ArgumentOutOfRangeException(nameof(ruleType), $"{nameof(ruleType)} must be a collection RuleType"); } var minEntitiesRequired = prescription.Entities.MinEntitiesRequired; if (prescription.Entities.EntityIds.Count < minEntitiesRequired) { return(newState); } var actionDate = DateTime.UtcNow; // First get the potentially relevant entities in a cleaned form var ruleResultId = prescription.Entities.RuleResultId; var ruleResultEntitySet = new { RuleResultId = ruleResultId, Entities = new List <RuleResult>(), EntityIds = prescription.Entities.EntityIds .Where(ve => ve.EntType == EntityType.RuleResult) .Select(ve => ve.EntityId) }; ruleResultEntitySet.Entities .AddRange(newState.RuleResults.Where(v => ruleResultEntitySet.EntityIds.Contains(v.EntityId))); var entities = ruleResultEntitySet.Entities .Distinct() .Select(v => (IEntity)v) .ToList(); // Get the corresponding Rules var rulesToProcess = newState.Rules.RulesToProcess(ruleType, entities); var presEntities = ruleResultEntitySet.Entities.ToArray(); var ruleToProcess = rulesToProcess .SingleOrDefault(r => r.ReferenceValues.RuleResultId == ruleResultId); RuleResult newRuleResult = null; switch (ruleType) { case RuleType.And: newRuleResult = ruleToProcess.AndTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; case RuleType.Or: newRuleResult = ruleToProcess.OrTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; case RuleType.Xor: newRuleResult = ruleToProcess.XorTest(presEntities, ruleResultEntitySet.RuleResultId, actionDate); break; } if (newRuleResult == null) { return(newState); } // Get the Ids of all existing Rule Results that correspond to the Rule being processed var relRuleResultIds = newState.RuleResults .Where(rr => rr.RuleResultId == ruleToProcess.ReferenceValues.RuleResultId) .Select(rr => rr.RuleResultId) .ToList(); if (!relRuleResultIds.Any()) { // An unusual circumstance, no pre-existing RuleResult newState.RuleResults.Add(newRuleResult); } else { // Normal circumstances, we'd expect only one RuleResult foreach (var rrId in relRuleResultIds) { var relevantRuleResult = newState.RuleResults.Single(rr => rr.RuleResultId == rrId); relevantRuleResult.LastChanged = actionDate; relevantRuleResult.Detail = newRuleResult.Detail; } } return(newState); }
/// <summary> /// Perform all Exists and Not Exists Rules /// </summary> /// <param name="newState"></param> /// <param name="prescription"></param> /// <returns></returns> public static ProcessingRulEngStore AllExists(this ProcessingRulEngStore newState, ProcessExistsRule prescription) { if (prescription == null) { return(newState); } var actionDate = DateTime.UtcNow; // First identify the potentially relevant entities var entities = newState.Rules.Select(r => (IEntity)r).ToList(); entities.AddRange(newState.Values.Select(v => (IEntity)v)); entities.AddRange(newState.Operations.Select(o => (IEntity)o)); entities.AddRange(newState.Requests.Select(rq => (IEntity)rq)); // Get the corresponding Rules var rulesToProcess = newState.Rules.RulesToProcess(RuleType.Exists, entities); foreach (var ruleToProcess in rulesToProcess) { // Get the Ids of all existing Rule Results that correspond to the Rule being processed var relRuleResultIds = newState.RuleResults .Where(rr => rr.RuleResultId == ruleToProcess.ReferenceValues.RuleResultId) .Select(rr => rr.RuleResultId) .ToList(); if (!relRuleResultIds.Any()) { // An unusual circumstance, no pre-existing RuleResult // Create a new RuleResult using the provided ID // We are here because the result is true, so we write the opposite of NegateResult as the correct output var newRuleResult = new RuleResult { RuleId = ruleToProcess.RuleId, LastChanged = actionDate, Detail = !ruleToProcess.NegateResult }; newState.RuleResults.Add(newRuleResult); } else { // Normal circumstances, we'd expect only one RuleResult foreach (var rrId in relRuleResultIds) { var relevantRuleResult = newState.RuleResults.Single(rr => rr.RuleResultId == rrId); relevantRuleResult.LastChanged = actionDate; relevantRuleResult.Detail = !ruleToProcess.NegateResult; } } // Mark this Rule as executed ruleToProcess.LastExecuted = actionDate; } // Mark the entities within this prescription as dispensed // TODO: determine the relevance of this foreach (var entId in prescription.Entities.EntityIds) { entId.LastChanged = actionDate; } return(newState); }