TEST(Path, NestedNoLeaf1) { ElementPath p; ASSERT(p.init("a.b").isOK()); p.setTraverseLeafArray(false); BSONObj doc = BSON("a" << BSON_ARRAY(BSON("b" << 5) << 3 << BSONObj() << BSON("b" << BSON_ARRAY(9 << 11)) << BSON("b" << 7))); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(5, e.element().numberInt()); ASSERT(!e.outerArray()); ASSERT(cursor.more()); e = cursor.next(); ASSERT(e.element().eoo()); ASSERT_EQUALS((string) "2", e.arrayOffset().fieldName()); ASSERT(!e.outerArray()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT_EQUALS(2, e.element().Obj().nFields()); ASSERT(e.outerArray()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(7, e.element().numberInt()); ASSERT(!e.outerArray()); ASSERT(!cursor.more()); }
// When the path (partially or in its entirety) refers to an array, // the iteration logic does not return an EOO. // what we want ideally. TEST(Path, NestedPartialMatchArray) { ElementPath p; ASSERT(p.init("a.b").isOK()); BSONObj doc = BSON("a" << BSON_ARRAY(4)); BSONElementIterator cursor(&p, doc); ASSERT(!cursor.more()); }
TEST(Path, Root1) { ElementPath p; ASSERT(p.init("a").isOK()); BSONObj doc = BSON("x" << 4 << "a" << 5); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); ElementIterator::Context e = cursor.next(); ASSERT_EQUALS((string) "a", e.element().fieldName()); ASSERT_EQUALS(5, e.element().numberInt()); ASSERT(!cursor.more()); }
TEST(Path, ArrayIndex2) { ElementPath p; ASSERT(p.init("a.1").isOK()); BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON_ARRAY(2 << 4) << 3)); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT(!cursor.more()); }
TEST(Path, RootArray2) { ElementPath p; ASSERT(p.init("a").isOK()); p.setTraverseLeafArray(false); BSONObj doc = BSON("x" << 4 << "a" << BSON_ARRAY(5 << 6)); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT(e.element().type() == Array); ASSERT(!cursor.more()); }
TEST(Path, ArrayIndexNested2) { ElementPath p; ASSERT(p.init("a.1.b").isOK()); BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON_ARRAY(BSON("b" << 4)) << 3)); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(4, e.element().numberInt()); ASSERT(!cursor.more()); }
// Note that this describes existing behavior and not necessarily TEST(Path, NestedEmptyArray) { ElementPath p; ASSERT(p.init("a.b").isOK()); BSONObj doc = BSON("a" << BSON("b" << BSONArray())); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT_EQUALS(0, e.element().Obj().nFields()); ASSERT(e.outerArray()); ASSERT(!cursor.more()); }
TEST(Path, NestedPartialMatchScalar) { ElementPath p; ASSERT(p.init("a.b").isOK()); BSONObj doc = BSON("a" << 4); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT(e.element().eoo()); ASSERT(e.arrayOffset().eoo()); ASSERT(!e.outerArray()); ASSERT(!cursor.more()); }
static BSONElement extractKeyElementFromMatchable(const MatchableDocument& matchable, const StringData& pathStr) { ElementPath path; path.init(pathStr); path.setTraverseNonleafArrays(false); path.setTraverseLeafArray(false); MatchableDocument::IteratorHolder matchIt(&matchable, &path); if (!matchIt->more()) return BSONElement(); BSONElement matchEl = matchIt->next().element(); // We shouldn't have more than one element - we don't expand arrays dassert(!matchIt->more()); return matchEl; }
// SERVER-15899: test iteration using a path that generates no elements, but traverses a long // array containing subdocuments with nested arrays. TEST(Path, NonMatchingLongArrayOfSubdocumentsWithNestedArrays) { ElementPath p; ASSERT(p.init("a.b.x").isOK()); // Build the document {a: [{b: []}, {b: []}, {b: []}, ...]}. BSONObj subdoc = BSON("b" << BSONArray()); BSONArrayBuilder builder; for (int i = 0; i < 100 * 1000; ++i) { builder.append(subdoc); } BSONObj doc = BSON("a" << builder.arr()); BSONElementIterator cursor(&p, doc); // The path "a.b.x" matches no elements. ASSERT(!cursor.more()); }
// When multiple arrays are traversed implicitly in the same path, // ElementIterator::Context::arrayOffset() should always refer to the current offset of the // outermost array that is implicitly traversed. TEST(Path, NestedArrayImplicitTraversal) { ElementPath p; ASSERT(p.init("a.b").isOK()); BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); ElementIterator::Context e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(2, e.element().numberInt()); ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(3, e.element().numberInt()); ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT_BSONOBJ_EQ(BSON("0" << 2 << "1" << 3), e.element().Obj()); ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(4, e.element().numberInt()); ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(5, e.element().numberInt()); ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT_BSONOBJ_EQ(BSON("0" << 4 << "1" << 5), e.element().Obj()); ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); ASSERT(!cursor.more()); }
TEST(Path, ArrayIndex3) { ElementPath p; ASSERT(p.init("a.1").isOK()); BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON("1" << 4) << 3)); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(4, e.element().numberInt()); ASSERT(!e.outerArray()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_BSONOBJ_EQ(BSON("1" << 4), e.element().Obj()); ASSERT(e.outerArray()); ASSERT(!cursor.more()); }
TEST(Path, RootArray1) { ElementPath p; ASSERT(p.init("a").isOK()); BSONObj doc = BSON("x" << 4 << "a" << BSON_ARRAY(5 << 6)); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); BSONElementIterator::Context e = cursor.next(); ASSERT_EQUALS(5, e.element().numberInt()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(6, e.element().numberInt()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT(!cursor.more()); }
// SERVER-14886: when an array is being traversed explictly at the same time that a nested array // is being traversed implicitly, ElementIterator::Context::arrayOffset() should return the // current offset of the array being implicitly traversed. TEST(Path, ArrayOffsetWithImplicitAndExplicitTraversal) { ElementPath p; ASSERT(p.init("a.0.b").isOK()); BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); BSONElementIterator cursor(&p, doc); ASSERT(cursor.more()); ElementIterator::Context e = cursor.next(); ASSERT_EQUALS(EOO, e.element().type()); ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); // First elt of outer array. ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(2, e.element().numberInt()); ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); // First elt of inner array. ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(NumberInt, e.element().type()); ASSERT_EQUALS(3, e.element().numberInt()); ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); // Second elt of inner array. ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(Array, e.element().type()); ASSERT_BSONOBJ_EQ(BSON("0" << 2 << "1" << 3), e.element().Obj()); ASSERT(e.arrayOffset().eoo()); ASSERT(cursor.more()); e = cursor.next(); ASSERT_EQUALS(EOO, e.element().type()); ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); // Second elt of outer array. ASSERT(!cursor.more()); }