/// <summary>
        /// Fetch metadata for a single calculated field.
        /// </summary>
        /// <param name="provider">The calculated field metadata provider being extended.</param>
        /// <param name="fieldId">The field to load.</param>
        /// <param name="settings">Additional settings.</param>
        /// <returns>Calculation results.</returns>
        public static CalculatedFieldMetadata GetCalculatedFieldMetadata(this ICalculatedFieldMetadataProvider provider, long fieldId, CalculatedFieldSettings settings)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider"); // assert false
            }
            var fields = new[] { fieldId };

            // Call provider
            var metadatas = provider.GetCalculatedFieldMetadata(fields, settings);

            // Extract results
            CalculatedFieldMetadata metadata = metadatas.FirstOrDefault();

            return(metadata);
        }
Exemple #2
0
        /// <summary>
        /// Get the calculated field value for the specified entities.
        /// </summary>
        /// <param name="fieldMetadata">The metadata for the calculated field.</param>
        /// <param name="entityIDs">Entities</param>
        /// <param name="evalSettings">Evaluation settings</param>
        /// <returns>List of results.</returns>
        private IReadOnlyCollection <CalculatedFieldSingleResult> GetSingleFieldValues(CalculatedFieldMetadata fieldMetadata, IReadOnlyCollection <long> entityIDs, EvaluationSettings evalSettings)
        {
            if (fieldMetadata == null)
            {
                throw new ArgumentNullException("fieldMetadata");
            }
            if (entityIDs == null)
            {
                throw new ArgumentNullException("entityIDs");
            }

            // Handle statically broken calculated-fields
            // (may be null due to not being a calculated field, or the script failing to compile)
            if (fieldMetadata.Expression == null)
            {
                // If the calculated field was somehow invalid, return null for values.
                return(entityIDs.Select(id => new CalculatedFieldSingleResult(id, null)).ToArray());
            }

            // Load entities
            IReadOnlyCollection <IEntity> entities;

            entities = _entityRepository.Get(entityIDs);

            var results = new List <CalculatedFieldSingleResult>(entities.Count);

            // Perform calculations
            foreach (IEntity entity in entities)
            {
                ExpressionRunResult         runResult;
                CalculatedFieldSingleResult singleResult;

                evalSettings.ContextEntity = entity;

                try
                {
                    runResult    = _expressionRunner.Run(fieldMetadata.Expression, evalSettings);
                    singleResult = new CalculatedFieldSingleResult(entity.Id, runResult.Value);
                }
                catch (EvaluationException ex)
                {
                    singleResult = new CalculatedFieldSingleResult(entity.Id, ex);
                }

                results.Add(singleResult);
            }

            return(results);
        }
        /// <summary>
        /// Creates the evaluator for a single calculated field.
        /// </summary>
        /// <param name="calculatedField">Entity for the calculated field.</param>
        /// <param name="settings">Settings.</param>
        /// <returns></returns>
        private CalculatedFieldMetadata GetSingleCalculatedFieldMetadata(Field calculatedField, CalculatedFieldSettings settings)
        {
            string          calculation = null;
            IExpression     expression  = null;
            ParseException  exception   = null;
            BuilderSettings builderSettings;

            try
            {
                // Get calculation
                calculation = calculatedField.FieldCalculation;
                if (string.IsNullOrEmpty(calculation))
                {
                    throw new ArgumentException("The field has no calculation script. It may not be a calculated field.");
                }

                // Get settings
                builderSettings = CreateBuilderSettingsForField(calculatedField, settings);

                // Compile
                expression = _expressionCompiler.Compile(calculation, builderSettings);

                // Register cache invalidations
                if (CacheContext.IsSet())
                {
                    CalculationDependencies dependencies = _expressionCompiler.GetCalculationDependencies(expression);

                    using (CacheContext cacheContext = CacheContext.GetContext())
                    {
                        cacheContext.Entities.Add(calculatedField.Id);
                        cacheContext.Entities.Add(dependencies.IdentifiedEntities);
                        cacheContext.Entities.Add(builderSettings.RootContextType.EntityTypeId);
                    }
                }
            }
            catch (InvalidMemberParseException ex)
            {
                exception = ex;

                // If a parse-exception resulted from being unable to look up a member name, then it may be corrected by renaming some arbitrary field or relationship
                // that could not be otherwise detected by dependencies.IdentifiedEntities. So invalidate parse exceptions if any field/relationship changes.
                if (CacheContext.IsSet())
                {
                    using (CacheContext cacheContext = CacheContext.GetContext())
                    {
                        cacheContext.Entities.Add(ex.TypeId);
                        // TODO: ideally just listen for all fields/relationships attached to type
                        var fieldTypes = PerTenantEntityTypeCache.Instance.GetDescendantsAndSelf(new EntityRef("core:field").Id);
                        cacheContext.EntityTypes.Add(fieldTypes);
                        cacheContext.EntityTypes.Add(new EntityRef("core:relationship").Id);
                    }
                }
            }
            catch (ParseException ex)
            {
                exception = ex;
            }

            // Build metadata
            CalculatedFieldMetadata metadata = new CalculatedFieldMetadata(calculatedField.Id, calculation, expression, exception);

            return(metadata);
        }