Example #1
0
        protected override ScalarExpression OnBuildQuery(QueryBuilderContext context)
        {
            // Currently this must be a literal
            var field = Right as ConstantEntityNode;

            if (field == null)
            {
                throw new ParseException("Field required.");
            }

            var queryNode = context.GetNode(Left);

            // Start workaround for #27148
            // If an aggregate operation is performed on a choice field, then we try to treat it like an entity
            // then we have a scenario that can't currently be represented in structured queries.
            // (Because sq aggregate operations get declared as expressions, but if it's an expression we can no longer use it as a sq node for other expressions).
            // This can happen if we use the choice-field in a comparison (e.g. max(choice)>whatever) because the compiler
            // will inject a field lookup to redirect to the ordering field.
            // For now, detect this specific scenario, and pass the aggregate expression directly through because the query engine
            // will defer to the ordering version of the SQL, which will in turn look up the enumOrder field.
            // However, ideally we should also be able to do things like max(choice).someOtherRelationshipOrField
            bool nodeIsAggregate     = Left is AggregateNode || Left is EntityTypeCast && Left.Arguments[0] is AggregateNode;
            bool fieldIsEnumOrdering = field.Instance.Id == WellKnownAliases.CurrentTenant.EnumOrder;

            if (nodeIsAggregate && fieldIsEnumOrdering)
            {
                return(Left.BuildQuery(context));
            }
            // End workaround

            var result = new ResourceDataColumn
            {
                FieldId = field.Instance,
                NodeId  = queryNode.NodeId
            };

            return(result);
        }
Example #2
0
        protected override ScalarExpression OnBuildQuery(QueryBuilderContext context)
        {
            ScalarExpression arg = Argument.BuildQuery(context);

            if (ResultType.Type == DataType.Entity)
            {
                return(arg);
            }

            // Special case for AggregateExpression, because if we aggregate a choicefield, then it presents
            // as an Entity type, therefore requesting this cast - but the query builder wants to receive the aggregate expression directly.
            if (arg is EDC.ReadiNow.Metadata.Query.Structured.AggregateExpression)
            {
                var result = new MutateExpression {
                    Expression = arg
                };

                switch (ResultType.Type)
                {
                case DataType.String:
                    result.MutateType = MutateType.DisplaySql;
                    break;

                case DataType.Bool:
                    result.MutateType = MutateType.BoolSql;
                    break;

                default:
                    throw new InvalidOperationException(ResultType.Type.ToString( ));
                }
                return(result);
            }

            // Just refer to the node
            var queryNode = context.GetNode(Argument);

            switch (ResultType.Type)
            {
            case DataType.String:
                var nameResult = new ResourceDataColumn
                {
                    FieldId = "core:name",
                    NodeId  = queryNode.NodeId
                };
                return(nameResult);

            case DataType.Bool:
                var boolResult = new CalculationExpression
                {
                    Operator    = CalculationOperator.IsNull,
                    Expressions = new List <ScalarExpression>
                    {
                        new IdExpression {
                            NodeId = queryNode.NodeId
                        }
                    }
                };
                return(boolResult);

            default:
                throw new InvalidOperationException(ResultType.Type.ToString());
            }
        }