Exemplo n.º 1
0
bool BSONElementIterator::more() {
    if (subCursorHasMore()) {
        return true;
    }

    if (!_next.element().eoo()) {
        return true;
    }

    if (_state == DONE) {
        return false;
    }

    if (_state == BEGIN) {
        if (_traversalStart.type() != Array) {
            _next.reset(_traversalStart, BSONElement());
            _state = DONE;
            return true;
        }

        // It's an array.

        _arrayIterationState.reset(_path->fieldRef(), _traversalStartIndex + 1);

        if (_arrayIterationState.hasMore &&
            _path->nonLeafArrayBehavior() != ElementPath::NonLeafArrayBehavior::kTraverse) {
            // Don't allow traversing the array.
            if (_path->nonLeafArrayBehavior() == ElementPath::NonLeafArrayBehavior::kMatchSubpath) {
                _next.reset(_traversalStart, BSONElement());
                _state = DONE;
                return true;
            }

            _state = DONE;
            return false;
        } else if (!_arrayIterationState.hasMore &&
                   _path->leafArrayBehavior() == ElementPath::LeafArrayBehavior::kNoTraversal) {
            // Return the leaf array.
            _next.reset(_traversalStart, BSONElement());
            _state = DONE;
            return true;
        }

        _arrayIterationState.startIterator(_traversalStart);
        _state = IN_ARRAY;

        invariant(_next.element().eoo());
    }

    if (_state == IN_ARRAY) {
        // We're traversing an array.  Look at each array element.

        while (_arrayIterationState.more()) {
            BSONElement eltInArray = _arrayIterationState.next();
            if (!_arrayIterationState.hasMore) {
                // Our path terminates at this array.  _next should point at the current array
                // element.
                _next.reset(eltInArray, eltInArray);
                return true;
            }

            // Our path does not terminate at this array; there's a subpath left over.  Inspect
            // the current array element to see if it could match the subpath.

            if (eltInArray.type() == Object) {
                // The current array element is a subdocument.  See if the subdocument generates
                // any elements matching the remaining subpath.
                _subCursorPath.reset(new ElementPath());
                _subCursorPath->init(_arrayIterationState.restOfPath);
                _subCursorPath->setLeafArrayBehavior(_path->leafArrayBehavior());

                _subCursor.reset(new BSONElementIterator(_subCursorPath.get(), eltInArray.Obj()));
                if (subCursorHasMore()) {
                    return true;
                }
            } else if (_arrayIterationState.isArrayOffsetMatch(eltInArray.fieldName())) {
                // The path we're traversing has an array offset component, and the current
                // array element corresponds to the offset we're looking for (for example: our
                // path has a ".0" component, and we're looking at the first element of the
                // array, so we should look inside this element).

                if (_arrayIterationState.nextEntireRest()) {
                    // Our path terminates at the array offset.  _next should point at the
                    // current array element. _next._arrayOffset should be EOO, since this is not an
                    // implicit array traversal.
                    _next.reset(eltInArray, BSONElement());
                    return true;
                }

                invariant(eltInArray.type() != Object);  // Handled above.
                if (eltInArray.type() == Array) {
                    // The current array element is itself an array.  See if the nested array
                    // has any elements matching the remainihng.
                    _subCursorPath.reset(new ElementPath());
                    _subCursorPath->init(_arrayIterationState.restOfPath.substr(
                        _arrayIterationState.nextPieceOfPath.size() + 1));
                    _subCursorPath->setLeafArrayBehavior(_path->leafArrayBehavior());
                    BSONElementIterator* real = new BSONElementIterator(
                        _subCursorPath.get(), _arrayIterationState._current.Obj());
                    _subCursor.reset(real);
                    real->_arrayIterationState.reset(_subCursorPath->fieldRef(), 0);
                    real->_arrayIterationState.startIterator(eltInArray);
                    real->_state = IN_ARRAY;

                    // Set _arrayIterationState._current to EOO. This is not an implicit array
                    // traversal, so we should not override the array offset of the subcursor with
                    // the current array offset.
                    _arrayIterationState._current = BSONElement();

                    if (subCursorHasMore()) {
                        return true;
                    }
                }
            }
        }

        if (_arrayIterationState.hasMore) {
            return false;
        }

        _next.reset(_arrayIterationState._theArray, BSONElement());
        _state = DONE;
        return true;
    }

    return false;
}
Exemplo n.º 2
0
bool BSONElementIterator::more() {
    if (subCursorHasMore()) {
        return true;
    }

    if (!_next.element().eoo()) {
        return true;
    }

    if (_state == DONE) {
        return false;
    }

    if (_state == BEGIN) {
        size_t idxPath = 0;
        BSONElement e = getFieldDottedOrArray(_context, _path->fieldRef(), &idxPath);

        if (e.type() != Array) {
            _next.reset(e, BSONElement(), false);
            _state = DONE;
            return true;
        }

        // It's an array.

        _arrayIterationState.reset(_path->fieldRef(), idxPath + 1);

        if (_arrayIterationState.hasMore && !_path->shouldTraverseNonleafArrays()) {
            // Don't allow traversing the array.
            _state = DONE;
            return false;
        } else if (!_arrayIterationState.hasMore && !_path->shouldTraverseLeafArray()) {
            // Return the leaf array.
            _next.reset(e, BSONElement(), true);
            _state = DONE;
            return true;
        }

        _arrayIterationState.startIterator(e);
        _state = IN_ARRAY;

        invariant(_next.element().eoo());
    }

    if (_state == IN_ARRAY) {
        // We're traversing an array.  Look at each array element.

        while (_arrayIterationState.more()) {
            BSONElement eltInArray = _arrayIterationState.next();
            if (!_arrayIterationState.hasMore) {
                // Our path terminates at this array.  _next should point at the current array
                // element.
                _next.reset(eltInArray, eltInArray, false);
                return true;
            }

            // Our path does not terminate at this array; there's a subpath left over.  Inspect
            // the current array element to see if it could match the subpath.

            if (eltInArray.type() == Object) {
                // The current array element is a subdocument.  See if the subdocument generates
                // any elements matching the remaining subpath.
                _subCursorPath.reset(new ElementPath());
                _subCursorPath->init(_arrayIterationState.restOfPath);
                _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray());

                _subCursor.reset(new BSONElementIterator(_subCursorPath.get(), eltInArray.Obj()));
                if (subCursorHasMore()) {
                    return true;
                }
            } else if (_arrayIterationState.isArrayOffsetMatch(eltInArray.fieldName())) {
                // The path we're traversing has an array offset component, and the current
                // array element corresponds to the offset we're looking for (for example: our
                // path has a ".0" component, and we're looking at the first element of the
                // array, so we should look inside this element).

                if (_arrayIterationState.nextEntireRest()) {
                    // Our path terminates at the array offset.  _next should point at the
                    // current array element.
                    _next.reset(eltInArray, eltInArray, false);
                    return true;
                }

                invariant(eltInArray.type() != Object);  // Handled above.
                if (eltInArray.type() == Array) {
                    // The current array element is itself an array.  See if the nested array
                    // has any elements matching the remainihng.
                    _subCursorPath.reset(new ElementPath());
                    _subCursorPath->init(_arrayIterationState.restOfPath.substr(
                        _arrayIterationState.nextPieceOfPath.size() + 1));
                    _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray());
                    BSONElementIterator* real = new BSONElementIterator(
                        _subCursorPath.get(), _arrayIterationState._current.Obj());
                    _subCursor.reset(real);
                    real->_arrayIterationState.reset(_subCursorPath->fieldRef(), 0);
                    real->_arrayIterationState.startIterator(eltInArray);
                    real->_state = IN_ARRAY;
                    _arrayIterationState._current = BSONElement();
                    if (subCursorHasMore()) {
                        return true;
                    }
                }
            }
        }

        if (_arrayIterationState.hasMore) {
            return false;
        }

        _next.reset(_arrayIterationState._theArray, BSONElement(), true);
        _state = DONE;
        return true;
    }

    return false;
}