public bool IsValidDottedNameNode(DottedNameNode node, TexlBinding binding, OperationCapabilityMetadata metadata, IOpDelegationStrategy opDelStrategy) { Contracts.AssertValue(node); Contracts.AssertValue(binding); Contracts.AssertValueOrNull(opDelStrategy); var isRowScoped = binding.IsRowScope(node); if (!isRowScoped) { return(IsValidNode(node, binding)); } bool isRowScopedDelegationExempted; if (!IsValidRowScopedDottedNameNode(node, binding, metadata, out isRowScopedDelegationExempted)) { var telemetryMessage = string.Format("Kind:{0}, isRowScoped:{1}", node.Kind, isRowScoped); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); return(false); } if (isRowScopedDelegationExempted) { binding.SetBlockScopedConstantNode(node); return(true); } if (binding.TryGetFullRecordRowScopeAccessInfo(node, out var firstNameInfo)) { // This means that this row scoped field is from some parent scope which is non-delegatable. That should deny delegation at that point. // For this scope, this means that value will be provided from some other source. // For example, AddColumns(CDS As Left, "Column1", LookUp(CDS1, Left.Name in FirstName)) // CDS - *[Name:s], CDS1 - *[FirstName:s] if (GetCapabilityMetadata(firstNameInfo) == null) { return(true); } } if (!binding.GetType(node.Left).HasExpandInfo) { DPath columnPath; if (!BinderUtils.TryConvertNodeToDPath(binding, node, out columnPath) || !metadata.IsDelegationSupportedByColumn(columnPath, _function.FunctionDelegationCapability)) { var safeColumnName = CharacterUtils.MakeSafeForFormatString(columnPath.ToDottedSyntax()); var message = string.Format(StringResources.Get(TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn), safeColumnName); SuggestDelegationHintAndAddTelemetryMessage(node, binding, message, TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn, safeColumnName); TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, node, binding, _function, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(columnPath.ToDottedSyntax())); return(false); } // If there is any operator applied on this node then check if column supports operation. return(opDelStrategy?.IsOpSupportedByColumn(metadata, node, columnPath, binding) ?? true); } // If there is an entity reference then we need to do additional verification. IExpandInfo info = binding.GetType(node.Left).ExpandInfo.VerifyValue(); var dataSourceInfo = info.ParentDataSource; IDataEntityMetadata entityMetadata; if (!dataSourceInfo.DataEntityMetadataProvider.TryGetEntityMetadata(info.Identity, out entityMetadata)) { var telemetryMessage = string.Format("Kind:{0}, isRowScoped:{1}, no metadata found for entity {2}", node.Kind, isRowScoped, CharacterUtils.MakeSafeForFormatString(info.Identity)); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); return(false); } OperationCapabilityMetadata entityCapabilityMetadata = GetScopedOperationCapabilityMetadata(entityMetadata.DelegationMetadata); string maybeLogicalName; DName columnName = node.Right.Name; if (entityMetadata.DisplayNameMapping.TryGetFromSecond(node.Right.Name.Value, out maybeLogicalName)) { columnName = new DName(maybeLogicalName); } var entityColumnPath = DPath.Root.Append(columnName); if (!entityCapabilityMetadata.IsDelegationSupportedByColumn(entityColumnPath, _function.FunctionDelegationCapability)) { var safeColumnName = CharacterUtils.MakeSafeForFormatString(columnName.Value); var message = string.Format(StringResources.Get(TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn), safeColumnName); SuggestDelegationHintAndAddTelemetryMessage(node, binding, message, TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn, safeColumnName); TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, node, binding, _function, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(columnName)); return(false); } // If there is any operator applied on this node then check if column supports operation. return(opDelStrategy?.IsOpSupportedByColumn(entityCapabilityMetadata, node, entityColumnPath, binding) ?? true); }