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