Пример #1
0
        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);
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
            }
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
        }
Пример #13
0
        /// <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);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        /// <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);
        }