DeleteOp parseDeleteCommand(StringData dbName, const BSONObj& cmd) { BSONElement deletes; DeleteOp op; parseWriteCommand(dbName, cmd, "deletes", &deletes, &op); checkBSONType(Array, deletes); for (auto doc : deletes.Obj()) { checkTypeInArray(Object, doc, deletes); op.deletes.emplace_back(); auto& del = op.deletes.back(); // delete is a reserved word. bool haveQ = false; bool haveLimit = false; for (auto field : doc.Obj()) { const StringData fieldName = field.fieldNameStringData(); if (fieldName == "q") { haveQ = true; checkBSONType(Object, field); del.query = field.Obj(); } else if (fieldName == "collation") { checkBSONType(Object, field); del.collation = field.Obj(); } else if (fieldName == "limit") { haveLimit = true; uassert(ErrorCodes::TypeMismatch, str::stream() << "The limit field in delete objects must be a number. Got a " << typeName(field.type()), field.isNumber()); // Using a double to avoid throwing away illegal fractional portion. Don't want to // accept 0.5 here. const double limit = field.numberDouble(); uassert(ErrorCodes::FailedToParse, str::stream() << "The limit field in delete objects must be 0 or 1. Got " << limit, limit == 0 || limit == 1); del.multi = (limit == 0); } else { uasserted(ErrorCodes::FailedToParse, str::stream() << "Unrecognized field in delete operation: " << fieldName); } } uassert(ErrorCodes::FailedToParse, "The 'q' field is required for all deletes", haveQ); uassert( ErrorCodes::FailedToParse, "The 'limit' field is required for all deletes", haveLimit); } checkOpCountForCommand(op.deletes.size()); return op; }
UpdateOp parseUpdateCommand(StringData dbName, const BSONObj& cmd) { BSONElement updates; UpdateOp op; parseWriteCommand(dbName, cmd, "updates", &updates, &op); checkBSONType(Array, updates); for (auto doc : updates.Obj()) { checkTypeInArray(Object, doc, updates); op.updates.emplace_back(); auto& update = op.updates.back(); bool haveQ = false; bool haveU = false; for (auto field : doc.Obj()) { const StringData fieldName = field.fieldNameStringData(); if (fieldName == "q") { haveQ = true; checkBSONType(Object, field); update.query = field.Obj(); } else if (fieldName == "u") { haveU = true; checkBSONType(Object, field); update.update = field.Obj(); } else if (fieldName == "collation") { checkBSONType(Object, field); update.collation = field.Obj(); } else if (fieldName == "arrayFilters") { checkBSONType(Array, field); for (auto arrayFilter : field.Obj()) { checkBSONType(Object, arrayFilter); update.arrayFilters.push_back(arrayFilter.Obj()); } } else if (fieldName == "multi") { checkBSONType(Bool, field); update.multi = field.Bool(); } else if (fieldName == "upsert") { checkBSONType(Bool, field); update.upsert = field.Bool(); } else { uasserted(ErrorCodes::FailedToParse, str::stream() << "Unrecognized field in update operation: " << fieldName); } } uassert(ErrorCodes::FailedToParse, "The 'q' field is required for all updates", haveQ); uassert(ErrorCodes::FailedToParse, "The 'u' field is required for all updates", haveU); } checkOpCountForCommand(op.updates.size()); return op; }
InsertOp parseInsertCommand(StringData dbName, const BSONObj& cmd) { BSONElement documents; InsertOp op; parseWriteCommand(dbName, cmd, "documents", &documents, &op); checkType(Array, documents); for (auto doc : documents.Obj()) { checkTypeInArray(Object, doc, documents); op.documents.push_back(doc.Obj()); } checkOpCountForCommand(op.documents.size()); if (op.ns.isSystemDotIndexes()) { // This is only for consistency with sharding. uassert(ErrorCodes::InvalidLength, "Insert commands to system.indexes are limited to a single insert", op.documents.size() == 1); } return op; }