Status AuthzManagerExternalStateMock::remove(
            OperationContext* txn,
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj&,
            int* numRemoved) {
        int n = 0;
        BSONObjCollection::iterator iter;
        while (_findOneIter(collectionName, query, &iter).isOK()) {
            BSONObj idQuery = (*iter)["_id"].wrap();
            _documents[collectionName].erase(iter);
            ++n;

            if (_authzManager) {
                _authzManager->logOp(
                        txn,
                        "d",
                        collectionName.ns().c_str(),
                        idQuery,
                        NULL);
            }

        }
        *numRemoved = n;
        return Status::OK();
    }
Status AuthzManagerExternalStateMock::updateOne(OperationContext* opCtx,
                                                const NamespaceString& collectionName,
                                                const BSONObj& query,
                                                const BSONObj& updatePattern,
                                                bool upsert,
                                                const BSONObj& writeConcern) {
    namespace mmb = mutablebson;
    const CollatorInterface* collator = nullptr;
    boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator));
    UpdateDriver driver(std::move(expCtx));
    std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
    driver.parse(updatePattern, arrayFilters);

    BSONObjCollection::iterator iter;
    Status status = _findOneIter(opCtx, collectionName, query, &iter);
    mmb::Document document;
    if (status.isOK()) {
        document.reset(*iter, mmb::Document::kInPlaceDisabled);
        const bool validateForStorage = false;
        const FieldRefSet emptyImmutablePaths;
        const bool isInsert = false;
        BSONObj logObj;
        status = driver.update(
            StringData(), &document, validateForStorage, emptyImmutablePaths, isInsert, &logObj);
        if (!status.isOK())
            return status;
        BSONObj newObj = document.getObject().copy();
        *iter = newObj;
        BSONObj idQuery = newObj["_id"_sd].Obj();

        if (_authzManager) {
            _authzManager->logOp(opCtx, "u", collectionName, logObj, &idQuery);
        }

        return Status::OK();
    } else if (status == ErrorCodes::NoMatchingDocument && upsert) {
        if (query.hasField("_id")) {
            document.root().appendElement(query["_id"]).transitional_ignore();
        }
        const FieldRef idFieldRef("_id");
        FieldRefSet immutablePaths;
        invariant(immutablePaths.insert(&idFieldRef));
        status = driver.populateDocumentWithQueryFields(opCtx, query, immutablePaths, document);
        if (!status.isOK()) {
            return status;
        }

        const bool validateForStorage = false;
        const FieldRefSet emptyImmutablePaths;
        const bool isInsert = false;
        status = driver.update(
            StringData(), &document, validateForStorage, emptyImmutablePaths, isInsert);
        if (!status.isOK()) {
            return status;
        }
        return insert(opCtx, collectionName, document.getObject(), writeConcern);
    } else {
        return status;
    }
}
    Status AuthzManagerExternalStateMock::updateOne(
            OperationContext* txn,
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj& updatePattern,
            bool upsert,
            const BSONObj& writeConcern) {

        namespace mmb = mutablebson;
        UpdateDriver::Options updateOptions;
        UpdateDriver driver(updateOptions);
        Status status = driver.parse(updatePattern);
        if (!status.isOK())
            return status;

        BSONObjCollection::iterator iter;
        status = _findOneIter(collectionName, query, &iter);
        mmb::Document document;
        if (status.isOK()) {
            document.reset(*iter, mmb::Document::kInPlaceDisabled);
            BSONObj logObj;
            status = driver.update(StringData(), &document, &logObj);
            if (!status.isOK())
                return status;
            BSONObj newObj = document.getObject().copy();
            *iter = newObj;
            BSONObj idQuery = driver.makeOplogEntryQuery(newObj, false);

            if (_authzManager) {
                _authzManager->logOp(
                        txn,
                        "u",
                        collectionName.ns().c_str(),
                        logObj,
                        &idQuery);
            }

            return Status::OK();
        }
        else if (status == ErrorCodes::NoMatchingDocument && upsert) {
            if (query.hasField("_id")) {
                document.root().appendElement(query["_id"]);
            }
            status = driver.populateDocumentWithQueryFields(query, NULL, document);
            if (!status.isOK()) {
                return status;
            }
            status = driver.update(StringData(), &document);
            if (!status.isOK()) {
                return status;
            }
            return insert(txn, collectionName, document.getObject(), writeConcern);
        }
        else {
            return status;
        }
    }
Status AuthzManagerExternalStateMock::findOne(OperationContext* opCtx,
                                              const NamespaceString& collectionName,
                                              const BSONObj& query,
                                              BSONObj* result) {
    BSONObjCollection::iterator iter;
    Status status = _findOneIter(collectionName, query, &iter);
    if (!status.isOK())
        return status;
    *result = iter->copy();
    return Status::OK();
}
 Status AuthzManagerExternalStateMock::remove(
         const NamespaceString& collectionName,
         const BSONObj& query,
         const BSONObj&,
         int* numRemoved) {
     int n = 0;
     BSONObjCollection::iterator iter;
     while (_findOneIter(collectionName, query, &iter).isOK()) {
         _documents[collectionName].erase(iter);
         ++n;
     }
     *numRemoved = n;
     return Status::OK();
 }
    Status AuthzManagerExternalStateMock::updateOne(
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj& updatePattern,
            bool upsert,
            const BSONObj& writeConcern) {

        namespace mmb = mutablebson;
        UpdateDriver::Options updateOptions;
        updateOptions.upsert = upsert;
        UpdateDriver driver(updateOptions);
        Status status = driver.parse(updatePattern);
        if (!status.isOK())
            return status;

        BSONObjCollection::iterator iter;
        status = _findOneIter(collectionName, query, &iter);
        mmb::Document document;
        if (status.isOK()) {
            document.reset(*iter, mmb::Document::kInPlaceDisabled);
            status = driver.update(StringData(), &document, NULL);
            if (!status.isOK())
                return status;
            *iter = document.getObject().copy();
            return Status::OK();
        }
        else if (status == ErrorCodes::NoMatchingDocument && upsert) {
            if (query.hasField("_id")) {
                document.root().appendElement(query["_id"]);
            }
            status = driver.createFromQuery(query, document);
            if (!status.isOK()) {
                return status;
            }
            status = driver.update(StringData(), &document, NULL);
            if (!status.isOK()) {
                return status;
            }
            return insert(collectionName, document.getObject(), writeConcern);
        }
        else {
            return status;
        }
    }
Status AuthzManagerExternalStateMock::updateOne(OperationContext* opCtx,
                                                const NamespaceString& collectionName,
                                                const BSONObj& query,
                                                const BSONObj& updatePattern,
                                                bool upsert,
                                                const BSONObj& writeConcern) {
    namespace mmb = mutablebson;
    UpdateDriver::Options updateOptions;
    UpdateDriver driver(updateOptions);
    std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
    Status status = driver.parse(updatePattern, arrayFilters);
    if (!status.isOK())
        return status;

    BSONObjCollection::iterator iter;
    status = _findOneIter(collectionName, query, &iter);
    mmb::Document document;
    if (status.isOK()) {
        document.reset(*iter, mmb::Document::kInPlaceDisabled);
        const BSONObj emptyOriginal;
        const bool validateForStorage = false;
        const FieldRefSet emptyImmutablePaths;
        BSONObj logObj;
        status = driver.update(StringData(),
                               emptyOriginal,
                               &document,
                               validateForStorage,
                               emptyImmutablePaths,
                               &logObj);
        if (!status.isOK())
            return status;
        BSONObj newObj = document.getObject().copy();
        *iter = newObj;
        BSONObj idQuery = driver.makeOplogEntryQuery(newObj, false);

        if (_authzManager) {
            _authzManager->logOp(opCtx, "u", collectionName, logObj, &idQuery);
        }

        return Status::OK();
    } else if (status == ErrorCodes::NoMatchingDocument && upsert) {
        if (query.hasField("_id")) {
            document.root().appendElement(query["_id"]).transitional_ignore();
        }
        const FieldRef idFieldRef("_id");
        FieldRefSet immutablePaths;
        invariant(immutablePaths.insert(&idFieldRef));
        status = driver.populateDocumentWithQueryFields(opCtx, query, immutablePaths, document);
        if (!status.isOK()) {
            return status;
        }

        // The original document can be empty because it is only needed for validation of immutable
        // paths.
        const BSONObj emptyOriginal;
        const bool validateForStorage = false;
        const FieldRefSet emptyImmutablePaths;
        status = driver.update(
            StringData(), emptyOriginal, &document, validateForStorage, emptyImmutablePaths);
        if (!status.isOK()) {
            return status;
        }
        return insert(opCtx, collectionName, document.getObject(), writeConcern);
    } else {
        return status;
    }
}