Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
            }
        }
Beispiel #3
0
        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);
        }