diff options
-rw-r--r-- | src/mongo/db/ops/modifier_inc.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_inc.h | 15 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_inc_test.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_table.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_table.h | 1 |
5 files changed, 56 insertions, 11 deletions
diff --git a/src/mongo/db/ops/modifier_inc.cpp b/src/mongo/db/ops/modifier_inc.cpp index 44ee713e430..5f8efc2d768 100644 --- a/src/mongo/db/ops/modifier_inc.cpp +++ b/src/mongo/db/ops/modifier_inc.cpp @@ -57,8 +57,9 @@ namespace mongo { bool noOp; }; - ModifierInc::ModifierInc() + ModifierInc::ModifierInc(ModifierIncMode mode) : ModifierInterface () + , _mode(mode) , _fieldRef() , _posDollar(0) , _val() { @@ -166,7 +167,10 @@ namespace mongo { const SafeNum currentValue = _preparedState->elemFound.getValueSafeNum(); // Update newValue w.r.t to the current value of the found element. - _preparedState->newValue += currentValue; + if (_mode == MODE_INC) + _preparedState->newValue += currentValue; + else + _preparedState->newValue *= currentValue; // If the result of the addition is invalid, we must return an error. if (!_preparedState->newValue.isValid()) @@ -236,7 +240,7 @@ namespace mongo { _preparedState->newValue); if (!logElement.ok()) { - return Status(ErrorCodes::InternalError, "cannot append details for $inc mod"); + return Status(ErrorCodes::InternalError, "cannot append details for $inc/$mul mod"); } // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} segment. diff --git a/src/mongo/db/ops/modifier_inc.h b/src/mongo/db/ops/modifier_inc.h index 0425f0c3a35..6a3fece395c 100644 --- a/src/mongo/db/ops/modifier_inc.h +++ b/src/mongo/db/ops/modifier_inc.h @@ -33,7 +33,19 @@ namespace mongo { public: - ModifierInc(); + // TODO: This is a shortcut to implementing $mul by hijacking $inc. In the near future, + // we should consider either pulling $mul into its own operator, or creating a general + // purpose "numeric binary op" operator. Potentially, that operator could also subsume + // $bit (thought there are some subtleties, like that $bit can have multiple + // operations, and doing so with arbirary math operations introduces potential + // associativity difficulties). At the very least, if this mechanism is retained, then + // this class should be renamed at some point away from ModifierInc. + enum ModifierIncMode { + MODE_INC, + MODE_MUL + }; + + ModifierInc(ModifierIncMode mode = MODE_INC); virtual ~ModifierInc(); /** @@ -58,6 +70,7 @@ namespace mongo { virtual Status log(LogBuilder* logBuilder) const; private: + const ModifierIncMode _mode; // Access to each component of fieldName that's the target of this mod. FieldRef _fieldRef; diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp index d81d0f0337d..62d34bcb0e3 100644 --- a/src/mongo/db/ops/modifier_inc_test.cpp +++ b/src/mongo/db/ops/modifier_inc_test.cpp @@ -46,12 +46,13 @@ namespace { /** Helper to build and manipulate a $inc mod. */ class Mod { public: - Mod() : _mod() {} explicit Mod(BSONObj modObj) : _modObj(modObj) - , _mod() { - ASSERT_OK(_mod.init(_modObj["$inc"].embeddedObject().firstElement(), + , _mod(mongoutils::str::equals(modObj.firstElement().fieldName(), "$mul") ? + ModifierInc::MODE_MUL : ModifierInc::MODE_INC) { + const StringData& modName = modObj.firstElement().fieldName(); + ASSERT_OK(_mod.init(_modObj[modName].embeddedObject().firstElement(), ModifierInterface::Options::normal())); } @@ -418,4 +419,25 @@ namespace { ASSERT_EQUALS(fromjson("{ a : 2 }"), doc2); } + // Given the current implementation of $mul, we really only need one test for + // $mul. However, in the future, we should probably write additional ones, or, perhaps find + // a way to run all the obove tests in both modes. + TEST(Multiplication, ApplyAndLogSimpleDocument) { + Document doc(fromjson("{ a : { b : 2 } }")); + Mod incMod(fromjson("{ $mul: { 'a.b' : 3 } }")); + + ModifierInterface::ExecInfo execInfo; + ASSERT_OK(incMod.prepare(doc.root(), "", &execInfo)); + ASSERT_FALSE(execInfo.noOp); + + ASSERT_OK(incMod.apply()); + ASSERT_TRUE(doc.isInPlaceModeEnabled()); + ASSERT_EQUALS(fromjson("{ a : { b : 6 } }"), doc); + + Document logDoc; + LogBuilder logBuilder(logDoc.root()); + ASSERT_OK(incMod.log(&logBuilder)); + ASSERT_EQUALS(fromjson("{ $set : { 'a.b' : 6 } }"), logDoc); + } + } // namespace diff --git a/src/mongo/db/ops/modifier_table.cpp b/src/mongo/db/ops/modifier_table.cpp index 9fa968a8d53..9108cddc22e 100644 --- a/src/mongo/db/ops/modifier_table.cpp +++ b/src/mongo/db/ops/modifier_table.cpp @@ -59,6 +59,12 @@ namespace modifiertable { ModifierEntry* entryBit = new ModifierEntry("$bit", MOD_BIT); nameMap->insert(make_pair(StringData(entryBit->name), entryBit)); + ModifierEntry* entryInc = new ModifierEntry("$inc", MOD_INC); + nameMap->insert(make_pair(StringData(entryInc->name), entryInc)); + + ModifierEntry* entryMul = new ModifierEntry("$mul", MOD_MUL); + nameMap->insert(make_pair(StringData(entryMul->name), entryMul)); + ModifierEntry* entryPop = new ModifierEntry("$pop", MOD_POP); nameMap->insert(make_pair(StringData(entryPop->name), entryPop)); @@ -74,9 +80,6 @@ namespace modifiertable { ModifierEntry* entryPushAll = new ModifierEntry("$pushAll", MOD_PUSH_ALL); nameMap->insert(make_pair(StringData(entryPushAll->name), entryPushAll)); - ModifierEntry* entryInc = new ModifierEntry("$inc", MOD_INC); - nameMap->insert(make_pair(StringData(entryInc->name), entryInc)); - ModifierEntry* entrySet = new ModifierEntry("$set", MOD_SET); nameMap->insert(make_pair(StringData(entrySet->name), entrySet)); @@ -114,7 +117,9 @@ namespace modifiertable { case MOD_BIT: return new ModifierBit; case MOD_INC: - return new ModifierInc; + return new ModifierInc(ModifierInc::MODE_INC); + case MOD_MUL: + return new ModifierInc(ModifierInc::MODE_MUL); case MOD_POP: return new ModifierPop; case MOD_PULL: diff --git a/src/mongo/db/ops/modifier_table.h b/src/mongo/db/ops/modifier_table.h index cd25dc552bb..3f81a64014f 100644 --- a/src/mongo/db/ops/modifier_table.h +++ b/src/mongo/db/ops/modifier_table.h @@ -25,6 +25,7 @@ namespace modifiertable { MOD_ADD_TO_SET, MOD_BIT, MOD_INC, + MOD_MUL, MOD_POP, MOD_PULL, MOD_PULL_ALL, |