diff --git a/db/query.cpp b/db/query.cpp index f4aa9bd161b..5b4c4973092 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -389,15 +389,47 @@ namespace mongo { if ( m->op == Mod::INC ) { BSONElementManipulator( m->elt ).setNumber( e.number() + m->getn() ); m->setn( m->elt.number() ); + b2.appendAs( m->elt, m->fieldName ); } else if ( m->op == Mod::SET ) { - // nothing + b2.appendAs( m->elt, m->fieldName ); + } else if ( m->op == Mod::PUSH ) { + uassert( "Push can only be applied to an array", e.type() == Array ); + BSONObjBuilder arr; + BSONObjIterator i( e.embeddedObject() ); + const char *lastIndex = 0; + while( i.more() ) { + BSONElement arrI = i.next(); + if ( arrI.eoo() ) + break; + arr.append( arrI ); + lastIndex = arrI.fieldName(); + } + string nextIndex; + if ( !lastIndex ) + nextIndex = "0"; + else { + int index = strtol( lastIndex, 0, 10 ); + stringstream ss; + ss << index + 1; + nextIndex = ss.str(); + } + arr.appendAs( m->elt, nextIndex.c_str() ); + BSONObjBuilder encapsulatedArr; + encapsulatedArr.appendArray( "foo", arr.done() ); + b2.appendAs( encapsulatedArr.done().firstElement(), m->fieldName ); } - b2.appendAs( m->elt, m->fieldName ); ++m; ++p; } else if ( cmp < 0 ) { - // Here may be $inc or $set - b2.appendAs( m->elt, m->fieldName ); + if ( m->op == Mod::PUSH ) { + BSONObjBuilder arr; + arr.appendAs( m->elt, "0" ); + BSONObjBuilder encapsulatedArr; + encapsulatedArr.appendArray( "foo", arr.done() ); + b2.appendAs( encapsulatedArr.done().firstElement(), m->fieldName ); + } else { + b2.appendAs( m->elt, m->fieldName ); + } ++m; } else if ( cmp > 0 ) { if ( mayAddEmbedded( existing, p->first ) ) diff --git a/dbtests/updatetests.cpp b/dbtests/updatetests.cpp index 3a64a6039f7..d82ea301229 100644 --- a/dbtests/updatetests.cpp +++ b/dbtests/updatetests.cpp @@ -310,6 +310,33 @@ namespace UpdateTests { } }; + class PushInvalidEltType : public SetBase { + public: + void run() { + client().insert( ns(), fromjson( "{'_id':0,a:1}" ) ); + client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) ); + ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:1}" ) ) == 0 ); + } + }; + + class PushConflictsWithOtherMod : public SetBase { + public: + void run() { + client().insert( ns(), fromjson( "{'_id':0,a:[1]}" ) ); + client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 1 ) <<"$push" << BSON( "a" << 5 ) ) ); + ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:[1]}" ) ) == 0 ); + } + }; + + class PushFromNothing : public SetBase { + public: + void run() { + client().insert( ns(), fromjson( "{'_id':0}" ) ); + client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) ); + ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:[5]}" ) ) == 0 ); + } + }; + class All : public UnitTest::Suite { public: All() { @@ -341,6 +368,9 @@ namespace UpdateTests { add< InvalidEmbeddedSet >(); add< UpsertMissingEmbedded >(); add< Push >(); + add< PushInvalidEltType >(); + add< PushConflictsWithOtherMod >(); + add< PushFromNothing >(); } };