public Node optimizeNode()

in source/com.microsoft.tfs.core/src/com/microsoft/tfs/core/clients/workitem/internal/wiqlparse/WIQLAdapter.java [647:848]


    public Node optimizeNode(Node node, final NodeTableName tableContext, final NodeFieldName fieldContext) {
        if (node.getNodeType() == NodeType.FIELD_CONDITION) {
            final NodeCondition nodeCondition = (NodeCondition) node;

            // convert (A in B) block to the multiple blocks
            if (nodeCondition.getCondition() == Condition.IN) {
                // create new Or node
                final NodeOrOperator nodeOr = new NodeOrOperator();
                final NodeValueList valueList = (NodeValueList) nodeCondition.getRight();

                // process all values inside value list
                for (final Iterator<Node> it = valueList.iterator(); it.hasNext();) {
                    final Node valueItem = it.next();
                    nodeOr.add(new NodeCondition(Condition.EQUALS, nodeCondition.getLeft(), valueItem));
                }

                // optimize new "Or" group
                return nodeOr.optimize(this, tableContext, fieldContext);
            } else if (nodeCondition.getCondition() == Condition.CONTAINS
                || nodeCondition.getCondition() == Condition.CONTAINS_WORDS) {
                // optimize contains
                final String s = nodeCondition.getRight().getConstStringValue();
                if (s != null && s.length() == 0) {
                    // empty pattern - always true
                    return new NodeBoolConst(true);
                }
            }

            // field usage is a tag of the left part
            final NodeFieldName field = nodeCondition.getLeft();
            final FieldDefinitionImpl fd = (FieldDefinitionImpl) field.getTag();

            // convert Project-field condition to Area Path conditions
            if (fd.getID() == CoreFields.TEAM_PROJECT) {
                final String pathValue = nodeCondition.getRight().getConstStringValue();
                if (pathValue != null) {
                    final FieldDefinitionImpl pathField =
                        witContext.getFieldDefinitions().getFieldDefinitionInternal(CoreFields.AREA_PATH);

                    // construct new condition
                    node = new NodeCondition(
                        Condition.UNDER,
                        new NodeFieldName(field.getPrefix(), pathField.getName()),
                        new NodeString(pathValue));

                    if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
                        node = new NodeNotOperator(node);
                    }

                    // Bind new operator
                    node.bind(this, tableContext, fieldContext);
                }
            }

            if (isNonNullableField(fd.getID())) {
                // optimize contains
                final String s = nodeCondition.getRight().getConstStringValue();
                if (s != null && s.length() == 0) {
                    if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
                        // it always not empty
                        return new NodeBoolConst(true);
                    }
                }
            }

            if (dayPrecision && (field.getDataType() == DataType.DATE)) {
                // check time part of a constant -- must be 0
                final String rightString = nodeCondition.getRight().getConstStringValue();
                if (rightString != null && rightString.length() != 0) {
                    Date d = DateTime.parse(rightString, getLocale(), getTimeZone());
                    final Calendar calendar = Calendar.getInstance();
                    calendar.setTimeZone(getTimeZone());
                    calendar.setTime(d);

                    final boolean nonZeroTime = (calendar.get(Calendar.HOUR_OF_DAY) != 0)
                        || (calendar.get(Calendar.MINUTE) != 0)
                        || (calendar.get(Calendar.SECOND) != 0)
                        || (calendar.get(Calendar.MILLISECOND) != 0);
                    Tools.ensureSyntax(!nonZeroTime, SyntaxError.NON_ZERO_TIME, node);

                    // Create constants for start and end of period
                    final NodeString startDay = new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));

                    // TODO: Handle d == 31/12/9999 case (VS Bug 613231)

                    // Add a day
                    final Calendar c = Calendar.getInstance();
                    c.setTime(d);
                    c.setTimeZone(getTimeZone());
                    c.add(Calendar.DAY_OF_MONTH, 1);
                    d = c.getTime();

                    final NodeString nextDay = new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));

                    if (nodeCondition.getCondition() == Condition.EQUALS) {
                        // Convert to a pair of conditions
                        final NodeAndOperator nodeAnd = new NodeAndOperator();
                        nodeAnd.add(new NodeCondition(Condition.GREATER_OR_EQUALS, nodeCondition.getLeft(), startDay));
                        nodeAnd.add(new NodeCondition(Condition.LESS, nodeCondition.getLeft(), nextDay));
                        node = nodeAnd;
                        node.bind(this, tableContext, fieldContext);
                    } else if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
                        final NodeOrOperator nodeOr = new NodeOrOperator();
                        nodeOr.add(new NodeCondition(Condition.LESS, nodeCondition.getLeft(), startDay));
                        nodeOr.add(new NodeCondition(Condition.GREATER_OR_EQUALS, nodeCondition.getLeft(), nextDay));
                        node = nodeOr;
                        node.bind(this, tableContext, fieldContext);
                    } else if (nodeCondition.getCondition() == Condition.LESS
                        || nodeCondition.getCondition() == Condition.GREATER_OR_EQUALS) {
                        nodeCondition.setRight(startDay);
                    } else if (nodeCondition.getCondition() == Condition.GREATER) {
                        nodeCondition.setCondition(Condition.GREATER_OR_EQUALS);
                        nodeCondition.setRight(nextDay);
                    } else if (nodeCondition.getCondition() == Condition.LESS_OR_EQUALS) {
                        nodeCondition.setCondition(Condition.LESS);
                        nodeCondition.setRight(nextDay);
                    } else {
                        Tools.ensureSyntax(false, SyntaxError.INVALID_CONDITIONAL_OPERATOR, node);
                    }
                }
            }
        } else if (node.getNodeType() == NodeType.VARIABLE) {
            final NodeVariable nodeVariable = (NodeVariable) node;
            if (context != null) {
                final Object o = context.get(nodeVariable.getTag());
                if (o != null) {
                    if ((o instanceof Integer) || (o instanceof Double)) {
                        return new NodeNumber(o.toString());
                    }
                    return new NodeString(o.toString());
                }
            }
            if (ME.equals(nodeVariable.getTag())) {
                // replace "me" with user name
                return new NodeString(witContext.getCurrentUserDisplayName());
            }
            if (TODAY.equals(nodeVariable.getTag())) {
                final Date today = DateTime.today(getTimeZone());
                return new NodeString(DateTime.formatRoundTripLocal(today, getTimeZone()));
            }
        } else if (node.getNodeType() == NodeType.ARITHMETIC) {
            final NodeArithmetic a = (NodeArithmetic) node;
            final NodeNumber right = (NodeNumber) a.getRight();

            if (fieldContext == null || fieldContext.getDataType() == DataType.NUMERIC) {
                final NodeNumber left = (NodeNumber) a.getLeft();
                double d = Double.parseDouble(left.getValue());
                final double inc = Double.parseDouble(right.getValue());
                if (a.getArithmetic() == Arithmetic.ADD) {
                    d += inc;
                } else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
                    d -= inc;
                } else {
                    throw new RuntimeException();
                }
                return new NodeNumber(String.valueOf(d));
            }

            if (fieldContext != null && fieldContext.getDataType() == DataType.DATE) {
                final NodeString left = (NodeString) a.getLeft();
                Date d = DateTime.parse(left.getValue(), getLocale(), getTimeZone());

                boolean isIntegerDays = false;
                int integerDays = -1;
                try {
                    integerDays = Integer.parseInt(right.getValue());
                    isIntegerDays = true;
                } catch (final NumberFormatException ex) {
                }

                if (isIntegerDays) {
                    final Calendar calendar = Calendar.getInstance();
                    calendar.setTime(d);
                    calendar.setTimeZone(getTimeZone());

                    if (a.getArithmetic() == Arithmetic.ADD) {
                        calendar.add(Calendar.DAY_OF_MONTH, integerDays);
                    } else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
                        calendar.add(Calendar.DAY_OF_MONTH, -1 * integerDays);
                    } else {
                        throw new UnsupportedOperationException();
                    }

                    d = calendar.getTime();
                } else {
                    final double doubleDays = Double.parseDouble(right.getValue());
                    final long millis = (long) ((doubleDays * (60 * 60 * 24 * 1000)) + 0.5);
                    if (a.getArithmetic() == Arithmetic.ADD) {
                        d = new Date(d.getTime() + millis);
                    } else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
                        d = new Date(d.getTime() - millis);
                    } else {
                        throw new UnsupportedOperationException();
                    }
                }

                return new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));
            }
        }

        return node;
    }