protected bool IsValidNode(TexlNode node, TexlBinding binding) { Contracts.AssertValue(node); Contracts.AssertValue(binding); bool isAsync = binding.IsAsync(node); bool isPure = binding.IsPure(node); if (node is DottedNameNode && ((binding.GetType(node.AsDottedName().Left).Kind == DKind.OptionSet && binding.GetType(node).Kind == DKind.OptionSetValue) || (binding.GetType(node.AsDottedName().Left).Kind == DKind.View && binding.GetType(node).Kind == DKind.ViewValue))) { // OptionSet and View Access are delegable despite being async return(true); } if (node is CallNode && (binding.IsBlockScopedConstant(node) || (binding.GetInfo(node as CallNode).Function is AsTypeFunction))) { // AsType is delegable despite being async return(true); } // Async predicates and impure nodes are not supported. // Let CallNodes for User() be marked as being Valid to allow // expressions with User() calls to be delegated if (!(IsUserCallNodeDelegable(node, binding)) && (isAsync || !isPure)) { var telemetryMessage = string.Format("Kind:{0}, isAsync:{1}, isPure:{2}", node.Kind, isAsync, isPure); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); if (isAsync) { TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.AsyncPredicate, node, binding, _function); } if (!isPure) { TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.ImpureNode, node, binding, _function, DelegationTelemetryInfo.CreateImpureNodeTelemetryInfo(node, binding)); } return(false); } return(true); }
private bool IsValidSortOrderNode(TexlNode node, SortOpMetadata metadata, TexlBinding binding, DPath columnPath) { Contracts.AssertValue(node); Contracts.AssertValue(metadata); Contracts.AssertValue(binding); Contracts.AssertValid(columnPath); if (binding.IsAsync(node)) { var message = string.Format("Function:{0}, SortOrderNode is async", Name); AddSuggestionMessageToTelemetry(message, node, binding); return(false); } string sortOrder; switch (node.Kind) { case NodeKind.FirstName: case NodeKind.StrLit: return(_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) && IsSortOrderSuppportedByColumn(sortOrder, metadata, columnPath)); case NodeKind.DottedName: case NodeKind.Call: if (_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) && IsSortOrderSuppportedByColumn(sortOrder, metadata, columnPath)) { return(true); } // If both ascending and descending are supported then we can support this. return(IsSortOrderSuppportedByColumn(Microsoft.PowerFx.Core.Utils.LanguageConstants.DescendingSortOrderString, metadata, columnPath) && IsSortOrderSuppportedByColumn(Microsoft.PowerFx.Core.Utils.LanguageConstants.AscendingSortOrderString, metadata, columnPath)); default: AddSuggestionMessageToTelemetry("Unsupported sortorder node.", node, binding); return(false); } }
private bool IsValidSortOrderNode(TexlNode node, SortOpMetadata metadata, TexlBinding binding, DPath columnPath) { Contracts.AssertValue(node); Contracts.AssertValue(metadata); Contracts.AssertValue(binding); Contracts.AssertValid(columnPath); if (binding.IsAsync(node)) { AddSuggestionMessageToTelemetry("Async sortorder node.", node, binding); DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.AsyncSortOrder, node, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo()); return(false); } string sortOrder; switch (node.Kind) { case NodeKind.FirstName: case NodeKind.StrLit: return(_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) && IsSortOrderSuppportedByColumn(node, binding, sortOrder, metadata, columnPath)); case NodeKind.DottedName: case NodeKind.Call: if (_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) && IsSortOrderSuppportedByColumn(node, binding, sortOrder, metadata, columnPath)) { return(true); } // If both ascending and descending are supported then we can support this. return(IsSortOrderSuppportedByColumn(node, binding, LanguageConstants.DescendingSortOrderString, metadata, columnPath) && IsSortOrderSuppportedByColumn(node, binding, LanguageConstants.AscendingSortOrderString, metadata, columnPath)); default: AddSuggestionMessageToTelemetry("Unsupported sortorder node kind.", node, binding); return(false); } }
// Verifies if given kind of node is supported by function delegation. private bool IsSupportedNode(TexlNode node, OperationCapabilityMetadata metadata, TexlBinding binding, IOpDelegationStrategy opDelStrategy, bool isRHSNode) { Contracts.AssertValue(node); Contracts.AssertValue(metadata); Contracts.AssertValue(binding); Contracts.AssertValue(opDelStrategy); if (!binding.IsRowScope(node)) { // Check whether this is - // 1) in operator delegation and // 2) it is verifying if RHS node is supported and // 3) it is not an async node and // 4) it is a single column table and // 5) metadata belongs to cds datasource that supports delegation of CdsIn // If this check fails, verify if it is simply a valid node.. // Eg of valid delegation functions - // Filter(Accounts, 'Account Name' in ["Foo", Bar"]) - Direct table use // Set(Names, ["Foo", Bar"]); Filter(Accounts, 'Account Name' in Names) - Using variable of type table // ClearCollect(Names, Accounts); Filter(Accounts, 'Account Name' in Names.'Account Name') - using column from collection. // This won't be delegated - Filter(Accounts, 'Account Name' in Accounts.'Account Name') as Accounts.'Account Name' is async. if ((binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled && isRHSNode && (opDelStrategy as BinaryOpDelegationStrategy)?.Op == BinaryOp.In && !binding.IsAsync(node) && binding.GetType(node).IsTable&& binding.GetType(node).IsColumn&& metadata.IsDelegationSupportedByTable(DelegationCapability.CdsIn)) || IsValidNode(node, binding)) { return(true); } } switch (node.Kind) { case NodeKind.DottedName: { if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding)) { return(false); } var dottedNodeValStrategy = _function.GetDottedNameNodeDelegationStrategy(); return(dottedNodeValStrategy.IsValidDottedNameNode(node.AsDottedName(), binding, metadata, opDelStrategy)); } case NodeKind.Call: { if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding)) { return(false); } var cNodeValStrategy = _function.GetCallNodeDelegationStrategy(); return(cNodeValStrategy.IsValidCallNode(node.AsCall(), binding, metadata)); } case NodeKind.FirstName: { var firstNameNodeValStrategy = _function.GetFirstNameNodeDelegationStrategy(); return(firstNameNodeValStrategy.IsValidFirstNameNode(node.AsFirstName(), binding, opDelStrategy)); } case NodeKind.UnaryOp: { if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding)) { return(false); } var unaryopNode = node.AsUnaryOpLit(); IOpDelegationStrategy unaryOpNodeDelegationStrategy = _function.GetOpDelegationStrategy(unaryopNode.Op); return(unaryOpNodeDelegationStrategy.IsSupportedOpNode(unaryopNode, metadata, binding)); } case NodeKind.BinaryOp: { if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding)) { return(false); } var binaryOpNode = node.AsBinaryOp().VerifyValue(); opDelStrategy = _function.GetOpDelegationStrategy(binaryOpNode.Op, binaryOpNode); var binaryOpDelStrategy = (opDelStrategy as BinaryOpDelegationStrategy).VerifyValue(); Contracts.Assert(binaryOpNode.Op == binaryOpDelStrategy.Op); if (!opDelStrategy.IsSupportedOpNode(node, metadata, binding)) { SuggestDelegationHint(binaryOpNode, binding); return(false); } break; } default: { var kind = node.Kind; if (kind != NodeKind.BoolLit && kind != NodeKind.StrLit && kind != NodeKind.NumLit) { var telemetryMessage = string.Format("NodeKind {0} unsupported.", kind); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); return(false); } break; } } return(true); }