private IDelegationMetadata GetCapabilityMetadata(FirstNameInfo info) { Contracts.AssertValue(info); IDelegationMetadata metadata = null; if (info.Data is DelegationMetadata.DelegationMetadata) { return(info.Data as DelegationMetadata.DelegationMetadata); } if (info.Data is IExpandInfo) { var entityInfo = (info.Data as IExpandInfo).VerifyValue(); Contracts.AssertValue(entityInfo.ParentDataSource); Contracts.AssertValue(entityInfo.ParentDataSource.DataEntityMetadataProvider); var metadataProvider = entityInfo.ParentDataSource.DataEntityMetadataProvider; IDataEntityMetadata entityMetadata; var result = metadataProvider.TryGetEntityMetadata(entityInfo.Identity, out entityMetadata); Contracts.Assert(result); metadata = entityMetadata.VerifyValue().DelegationMetadata.VerifyValue(); } return(metadata); }
private OperationCapabilityMetadata GetScopedOperationCapabilityMetadata(IDelegationMetadata delegationMetadata) { if (Function.FunctionDelegationCapability.HasCapability(DelegationCapability.Sort) || Function.FunctionDelegationCapability.HasCapability(DelegationCapability.SortAscendingOnly)) { return(delegationMetadata.SortDelegationMetadata); } return(delegationMetadata.FilterDelegationMetadata); }
// Verifies if given callnode can be server delegatable or not. // Return true if // - Arg0 is delegatable ds and supports filter operation. // - All predicates to filter are delegatable if each firstname/binary/unary/dottedname/call node in each predicate satisfies delegation criteria set by delegation strategy for each node. public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); if (!CheckArgsCount(callNode, binding)) { return(false); } IExternalDataSource dataSource; FilterOpMetadata metadata = null; IDelegationMetadata delegationMetadata = null; if (TryGetEntityMetadata(callNode, binding, out delegationMetadata)) { if (!binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled || !TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.ArrayLookup, out _)) { SuggestDelegationHint(callNode, binding); return(false); } metadata = delegationMetadata.FilterDelegationMetadata.VerifyValue(); } else { if (!TryGetValidDataSourceForDelegation(callNode, binding, FunctionDelegationCapability, out dataSource)) { return(false); } metadata = dataSource.DelegationMetadata.FilterDelegationMetadata; } TexlNode[] args = callNode.Args.Children.VerifyValue(); if (args.Length > 2 && binding.IsDelegatable(args[2])) { SuggestDelegationHint(args[2], binding); return(false); } if (args.Length < 2) { return(false); } return(IsValidDelegatableFilterPredicateNode(args[1], binding, metadata)); }
// Verifies if provided column node supports delegation. protected bool IsDelegatableColumnNode(FirstNameNode node, TexlBinding binding, IOpDelegationStrategy opDelStrategy, DelegationCapability capability) { Contracts.AssertValue(node); Contracts.AssertValue(binding); Contracts.AssertValueOrNull(opDelStrategy); Contracts.Assert(binding.IsRowScope(node)); FirstNameInfo firstNameInfo = binding.GetInfo(node.AsFirstName()); if (firstNameInfo == null) { return(false); } IDelegationMetadata metadata = GetCapabilityMetadata(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, "Column1", LookUp(CDS1, Name in FirstName)) // CDS - *[Name:s], CDS1 - *[FirstName:s] if (metadata == null) { return(true); } var columnName = firstNameInfo.Name; Contracts.AssertValid(columnName); var columnPath = DPath.Root.Append(columnName); if (!metadata.FilterDelegationMetadata.IsDelegationSupportedByColumn(columnPath, capability)) { 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(firstNameInfo)); return(false); } // If there is any operator applied on this node then check if column supports operation. if (opDelStrategy != null && !opDelStrategy.IsOpSupportedByColumn(metadata.FilterDelegationMetadata, node.AsFirstName(), columnPath, binding)) { return(false); } return(true); }
public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); if (binding.ErrorContainer.HasErrors(callNode)) { return(false); } if (!CheckArgsCount(callNode, binding)) { return(false); } SortOpMetadata metadata = null; IDelegationMetadata delegationMetadata = null; IExternalDataSource dataSource; if (TryGetEntityMetadata(callNode, binding, out delegationMetadata)) { if (!binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled || !TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.ArrayLookup, out _)) { SuggestDelegationHint(callNode, binding); return(false); } metadata = delegationMetadata.SortDelegationMetadata.VerifyValue(); } else { if (!TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.Sort, out dataSource)) { return(false); } metadata = dataSource.DelegationMetadata.SortDelegationMetadata; } TexlNode[] args = callNode.Args.Children.VerifyValue(); int cargs = args.Count(); const string defaultSortOrder = Microsoft.PowerFx.Core.Utils.LanguageConstants.AscendingSortOrderString; for (int i = 1; i < cargs; i += 2) { if (!IsValidSortableColumnNode(args[i], binding, metadata)) { SuggestDelegationHint(args[i], binding); return(false); } string columnName = args[i].AsStrLit().VerifyValue().Value; TexlNode sortOrderNode = (i + 1) < cargs ? args[i + 1] : null; string sortOrder = sortOrderNode == null ? defaultSortOrder : ""; if (sortOrderNode != null) { if (!IsValidSortOrderNode(sortOrderNode, metadata, binding, DPath.Root.Append(new DName(columnName)))) { SuggestDelegationHint(sortOrderNode, binding); return(false); } } else if (!IsSortOrderSuppportedByColumn(sortOrder, metadata, DPath.Root.Append(new DName(columnName)))) { SuggestDelegationHint(args[i], binding); return(false); } } return(true); }
public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); if (!CheckArgsCount(callNode, binding)) { return(false); } SortOpMetadata metadata = null; IDelegationMetadata delegationMetadata = null; IExternalDataSource dataSource; if (TryGetEntityMetadata(callNode, binding, out delegationMetadata)) { if (!binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled || !TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.ArrayLookup, out _)) { SuggestDelegationHint(callNode, binding); return(false); } metadata = delegationMetadata.SortDelegationMetadata.VerifyValue(); } else { if (!TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.Sort, out dataSource)) { return(false); } metadata = dataSource.DelegationMetadata.SortDelegationMetadata; } TexlNode[] args = callNode.Args.Children.VerifyValue(); TexlNode arg1 = args[1].VerifyValue(); // For now, we are only supporting delegation for Sort operations where second argument is column name. // For example, Sort(CDS, Value) FirstNameNode firstName = arg1.AsFirstName(); if (firstName == null) { SuggestDelegationHint(arg1, binding); AddSuggestionMessageToTelemetry("Arg1 is not a FirstName node.", arg1, binding); DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.UnSupportedSortArg, arg1, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo()); return(false); } FirstNameInfo firstNameInfo = binding.GetInfo(firstName); if (firstNameInfo == null) { return(false); } DPath columnName = DPath.Root.Append(firstNameInfo.Name); if (!metadata.IsDelegationSupportedByColumn(columnName, DelegationCapability.Sort)) { SuggestDelegationHint(firstName, binding); DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, firstName, binding, this, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(firstNameInfo)); return(false); } const string defaultSortOrder = LanguageConstants.AscendingSortOrderString; int cargs = args.Count(); // Verify that the third argument (If present) is an Enum or string literal. if (cargs < 3 && IsSortOrderSuppportedByColumn(callNode, binding, defaultSortOrder, metadata, columnName)) { return(true); } // TASK: 6237100 - Binder: Propagate errors in subtree of the callnode to the call node itself // Only FirstName, DottedName and StrLit non-async nodes are supported for arg2. TexlNode arg2 = args[2].VerifyValue(); if (!IsValidSortOrderNode(arg2, metadata, binding, columnName)) { SuggestDelegationHint(arg2, binding); return(false); } return(true); }
public override bool TryGetDelegationMetadata(CallNode node, TexlBinding binding, out IDelegationMetadata metadata) { Contracts.AssertValue(node); Contracts.AssertValue(binding); metadata = null; // Get metadata if it's an entity. IExpandInfo entityInfo; if (binding.TryGetEntityInfo(node.Args.Children[0], out entityInfo)) { Contracts.AssertValue(entityInfo.ParentDataSource); Contracts.AssertValue(entityInfo.ParentDataSource.DataEntityMetadataProvider); var metadataProvider = entityInfo.ParentDataSource.DataEntityMetadataProvider; IDataEntityMetadata entityMetadata; if (!metadataProvider.TryGetEntityMetadata(entityInfo.Identity, out entityMetadata)) { return(false); } metadata = entityMetadata.DelegationMetadata.VerifyValue(); return(true); } if (!TryGetValidDataSourceForDelegation(node, binding, FunctionDelegationCapability, out var ds)) { return(false); } metadata = ds.DelegationMetadata; return(true); }