| Home | API Documentation |
Internal: Mug · ThorsMug · ThorsSlack · NisseServer · NisseHTTP · ThorsSocket · ThorsCrypto · ThorsSerializer · ThorsMongo · ThorsLogging · ThorsIOUtil
Detailed architecture, message flow, cursor/range mechanics, and class-level documentation for the ThorsMongo MongoDB client.
Source: third/ThorsMongo/src/ThorsMongo/
| File | Purpose |
|---|---|
ThorsMongo.h/.cpp |
Public entry point (ThorsMongo, DB, Collection) and connection-owned cursor helpers (getMore(), killCursor()). |
ConnectionMongo.h/.cpp |
ConnectionMongo stream wrapper around a MongoDB TCP connection (built on ThorsSocket iostreams). |
ConnectionBufferMongo.h/.cpp |
std::streambuf implementation tuned for Mongo wire protocol framing and buffering. |
MessageHandler.h/.cpp |
MessageHandler base + MongoActionWriteInterface / MongoActionReadInterface used by all commands. Builds OP_MSG / OP_COMPRESSED. |
Authenticate.h/.cpp |
High-level authentication orchestration. |
AuthenticateScramSha.h/.cpp |
SCRAM-SHA-* implementation (currently the primary mechanism in this codebase). |
AuthInfo.h |
Authentication payload types (username/password, certificates, etc.). |
AuthClient.h/.cpp |
Client metadata sent to server during handshake (Auth::Client). |
MongoUtil.h |
Macro machinery for field-access generation and for creating filter/update types (ThorsMongo_CreateFieldAccess, ThorsMongo_FilterFromAccess, ThorsMongo_UpdateFromAccess). Also common enums (op codes, compression, flags). |
MongoQuery.h |
Query operator types (e.g. Eq, Gt, And, Exists, …) + Query<T> wrapper used by remove and some commands. |
MongoUpdate.h |
Update operator types (e.g. Set, Inc, Unset, Push, …). |
ThorsMongoCommon.h/.cpp |
Shared types: CmdReplyBase, sort/projection helpers, ActionConfig<> base for command configs, cluster time metadata, write error structures. |
MongoCursor.h |
Cursor model + generic Range<R> and input iterator + CursorData<T> lifetime and paging logic. |
ThorsMongoInsert.h/.tpp |
insert command builder + InsertResult. |
ThorsMongoFind.h/.tpp |
find command builder + FindRange<T> and FindResult<T> glue. |
ThorsMongoGetMore.h/.tpp |
getMore paging command. |
ThorsMongoKillCursor.h/.tpp |
killCursors cleanup command. |
ThorsMongoRemove.h/.tpp |
delete/remove command builder. |
ThorsMongoFindAndModify.h/.tpp |
findAndModify family (findAndReplaceOne, findAndRemoveOne, findAndUpdateOne). |
ThorsMongoCount.h/.tpp |
countDocuments command builder. |
ThorsMongoDistinct.h/.tpp |
distinct command builder. |
ThorsMongoListDatabase.h/.tpp |
listDatabases command builder + range wrapper. |
ThorsMongoListCollection.h/.tpp |
listCollections command builder + range wrapper. |
ThorsMongoAdmin.h/.tpp |
Admin commands like renameCollection, drop, createCollection. |
ReadConcern.h / WriteConcern.h |
Read/write concern payloads. |
test/* |
Unit + integration tests and generated mocking hooks. |
At a high level, ThorsMongo is a thin command layer over:
┌───────────────────────────────────────────────────────────┐
│ Application code │
│ ThorsMongo / DB / Collection │
│ Filters (QueryOp + field access macros) │
│ Updates (QueryOp + field access macros) │
├───────────────────────────────────────────────────────────┤
│ Command builder objects │
│ Insert / Find / Remove / FindAndModify / Distinct / ... │
├───────────────────────────────────────────────────────────┤
│ MessageHandler (OP_MSG / OP_COMPRESSED / checksum) │
├───────────────────────────────────────────────────────────┤
│ ConnectionMongo (iostream) + ConnectionBufferMongo │
│ built on ThorsSocket::BaseSocketStream │
├───────────────────────────────────────────────────────────┤
│ TCP socket │
└───────────────────────────────────────────────────────────┘
ThorsMongoFile: ThorsMongo.h
Owns:
MongoMessageHandler messageHandler (transport + framing)readConcern / writeConcernExposes:
operator[](std::string dbName) -> DBlistDatabases(...) -> DBRangegetMore(...), killCursor(...) used by cursor-backed rangesDBFile: ThorsMongo.h
Lightweight handle consisting of:
ThorsMongo& mongoServerstd::string nameExposes:
operator[](std::string collectionName) -> CollectionlistCollections(...) -> LCRangecreateCollection(...) -> AdminResultCollectionFile: ThorsMongo.h
Lightweight handle consisting of:
ThorsMongo& mongoServerstd::string name storing a combined db/collection name (db + "::" + collection)Exposes the core data operations:
insert, find, removefindAndReplaceOne, findAndRemoveOne, findAndUpdateOnecountDocuments, distinctrename, dropAlso exposes helpers:
dbName() and colName() views derived from the combined name.ConnectionMongoFile: ConnectionMongo.h
ConnectionMongo is a std::iostream (via ThorsSocket::BaseSocketStream<ConnectionBufferMongo>) that connects to the MongoDB host/port.
Key points:
ConnectionBufferMongo) is responsible for efficient reading/writing and for exposing stream-like semantics to the rest of the stack.MongoMessageHandlerFile: ThorsMongo.h
Concrete MessageHandler that owns a ConnectionMongo and returns it via getStream().
This is the bridge between:
MongoActionWriteInterface / MongoActionReadInterfaceFile: MessageHandler.h
These are the internal “capability” interfaces for any object that can be sent to or received from MongoDB:
For most command objects and reply objects, ThorsMongo uses trivial adapters:
MongoActionWriteInterfaceTrivialImpl<T> uses bsonGetPrintSize() + bsonExporter()MongoActionReadInterfaceTrivialImpl<T> uses bsonImporter()This keeps command classes simple: they just need to be ThorsSerializer-trait’d.
MessageHandlerFile: MessageHandler.h/.cpp
Responsibilities:
OP_MSG)OP_COMPRESSED depending on negotiated compressionHigh-level flow:
Command object (traits) ──writeBson()──► MessageHandler ──► ConnectionMongo stream
Reply object (traits) ◄──readBson()── MessageHandler ◄── ConnectionMongo stream
Each MongoDB command is represented by a small “command object” that:
MessageHandler::sendMessage()MessageHandler::recvMessage()Common patterns:
FindConfig, InsertConfig, …) derived from ActionConfig<>CmdReplyBase so they share the standard isOk() / getHRErrorMessage() / operator bool() behaviorImportant nuance:
File: MongoCursor.h
MongoDB cursors are represented as:
Cursor (metadata: id, namespace, partial results flag)CursorFirst<T> (first batch of data)CursorNext<T> (next batches from getMore)Only the CursorFirst<T> instance is kept in the long-lived cursor state; when getMore returns, CursorNext<T> is swapped/moved into CursorFirst<T>.
Range<R> and CursorIteratorFile: MongoCursor.h
Range<R> is the shared implementation used by multiple “range results”:
FindRange<T> (find results)It holds a std::shared_ptr<R>; copying the range shares the same cursor state.
Iteration uses a single-pass input iterator:
operator* returns cursorData.get().get(index)operator++ advances index and calls checkAvailable(index)CursorData<T> paging and cleanupFile: MongoCursor.h (class), ThorsMongo.h (destructor + paging glue)
CursorData<T> owns:
CursorFirst<T> batch storagegetMore and killCursor configsThorsMongo (so it can call getMore() and killCursor())Two key behaviors:
checkAvailable() triggers a getMore() and swaps in the next batch.CursorData<T>::~CursorData() calls killCursor() if the cursor id is non-zero.This is why ThorsMongo::getMore() / killCursor() are private but CursorData<T> is a friend.
File: MongoQuery.h
Mongo query operators are modeled as small types in ThorsAnvil::DB::Mongo::QueryOp:
Eq, Ne, Gt, Gte, Lt, Lte, In, NinAnd, Or, Nor, NotExists, TypeAll, ElemMatch, SizeAllClear, AllSet, AnyClear, AnySetEach operator type:
using Query = bool; marker used by concepts$op key.File: MongoUpdate.h
Updates follow the same idea but emit update documents ($set, $inc, …). Examples include:
Set, Unset, Inc, Min, Max, MulPush, Pull, AddToSet, PopFront, PopBack, plus helpers like Each, Position, Slice, SortFile: MongoUtil.h
The key ergonomics trick is: you declare a “field access” once, and then derive many query/update types from it.
ThorsMongo_CreateFieldAccess(Type, field, ...)
ThorsAnvil::FieldAccess::...::Access<T> wrapper"a.b.c" in BSON keysThorsMongo_FilterFromAccess(Op, Type, field, ...)
Eq, Gt, …)ThorsMongo_UpdateFromAccess(Op, Type, field, ...)
Set, Inc, …)Internally these macros:
Traits<...> metadatastd::optional<T> fields so you match/update the underlying TThorsAnvil_Template_MakeOverride(...)CmdReplyBaseFile: MongoUtil.h / ThorsMongoCommon.h
Most results derive from CmdReplyBase which provides:
double ok (Mongo replies use ok: 1.0 on success)errmsg, codeName, codeisOk() and operator bool()getHRErrorMessage() and operator<<This is what enables the idiom:
auto result = collection.insert(data);
if (!result) {
std::cerr << "Error: " << result << "\n";
}
ActionConfig<T>File: ThorsMongoCommon.h
All command-specific config types derive from ActionConfig<>, which centralizes low-level behavior:
PrinterConfig / ParserConfig overrides (otherwise defaults are used)OP_MsgFlag bits (checksum, exhaust, etc.)serverErrorAreExceptions toggleCommand config classes then add their own optional parameters and expose fluent setters.
ThorsMongo supports setting defaults and overrides at multiple levels:
ThorsMongoThorsMongodb::collection name inside ThorsMongoTypes involved:
ReadConcern (ReadConcern.h)WriteConcern (WriteConcern.h)ReadPreference (ThorsMongoCommon.h)The DB and Collection handles implement get*/set* by delegating into those maps via the shared owning ThorsMongo.
MongoDB wire protocol and BSON are little-endian. The code enforces that at compile time:
static_assert(std::endian::little == std::endian::native, ...) in ThorsMongo.hIf big-endian support is needed in the future, all “write integers to wire” helpers in the message framing path need to be audited and endian-corrected.
ThorsMongo can be built in a “header-only” configuration when ThorsSerializer is in header-only mode.
Pattern:
*.source implementations behind:#if defined(THORS_SERIALIZER_HEADER_ONLY) && THORS_SERIALIZER_HEADER_ONLY == 1
// ...
#include "ThorsMongo.source"
#endif
This mirrors the approach used across ThorsAnvil libraries: it avoids separate compilation while keeping a single code path.
Tests live under third/ThorsMongo/src/ThorsMongo/test/ and include:
Mocking infrastructure is generated into src/ThorsMongo/coverage/MockHeaders.h and included by test/MockHeaderInclude.h. In non-test builds, mock macros resolve to the real underlying functions; in test builds, they can be redirected to injected lambdas.