mirror of
https://github.com/pocoproject/poco.git
synced 2025-12-07 00:44:17 +01:00
4781 mongodb remove obsolete protocol and modernise (#5067)
* feature(MongoDB): Remove obsolete legacy wire protocol. * enh(MongoDB): Use more C++17 features, comments about thread safety. * enh(MongoDB) Performance improvements (std::set --> std::vector, improved few internal functions). * enh(MongoDB) Performance improvements (Document member index for fast search, optimised serialisation in OpMsgMessage). * enh(MongoDB) Performance improvements (move semantics for Document::addElement, improved toString(), use noexcept where appropriate). * enh(MongoDB): Introduce enums for binary subtypes and more user friendly printout of UUIDs. * enh(MongoDB) Performance improvements (move semantics in Element, improved implementation of toString()). * enh(MongoDB) Performance improvements (ObjectId and RegularExpression.). * enh(MongoDB): add createIndex that uses new wire protocol.
This commit is contained in:
@@ -81,19 +81,19 @@ public:
|
|||||||
return Document::get<T>(Poco::NumberFormatter::format(pos), deflt);
|
return Document::get<T>(Poco::NumberFormatter::format(pos), deflt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element::Ptr get(std::size_t pos) const;
|
[[nodiscard]] Element::Ptr get(std::size_t pos) const;
|
||||||
/// Returns the element at the given index.
|
/// Returns the element at the given index.
|
||||||
/// An empty element will be returned if the element is not found.
|
/// An empty element will be returned if the element is not found.
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool isType(std::size_t pos) const
|
[[nodiscard]] bool isType(std::size_t pos) const
|
||||||
/// Returns true if the type of the element equals the TypeId of ElementTrait,
|
/// Returns true if the type of the element equals the TypeId of ElementTrait,
|
||||||
/// otherwise false.
|
/// otherwise false.
|
||||||
{
|
{
|
||||||
return Document::isType<T>(Poco::NumberFormatter::format(pos));
|
return Document::isType<T>(Poco::NumberFormatter::format(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(int indent = 0) const override;
|
[[nodiscard]] std::string toString(int indent = 0) const override;
|
||||||
/// Returns a string representation of the Array.
|
/// Returns a string representation of the Array.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
_reader >> t;
|
_reader >> t;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readCString();
|
[[nodiscard]] std::string readCString();
|
||||||
/// Reads a cstring from the reader.
|
/// Reads a cstring from the reader.
|
||||||
/// A cstring is a string terminated with a 0x00.
|
/// A cstring is a string terminated with a 0x00.
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,19 @@ class MongoDB_API Binary
|
|||||||
public:
|
public:
|
||||||
using Ptr = SharedPtr<Binary>;
|
using Ptr = SharedPtr<Binary>;
|
||||||
|
|
||||||
|
/// BSON Binary subtypes
|
||||||
|
enum Subtype
|
||||||
|
{
|
||||||
|
SUBTYPE_GENERIC = 0x00, /// Generic binary data
|
||||||
|
SUBTYPE_FUNCTION = 0x01, /// Function
|
||||||
|
SUBTYPE_BINARY_OLD = 0x02, /// Binary (Old)
|
||||||
|
SUBTYPE_UUID_OLD = 0x03, /// UUID (Old)
|
||||||
|
SUBTYPE_UUID = 0x04, /// UUID
|
||||||
|
SUBTYPE_MD5 = 0x05, /// MD5
|
||||||
|
SUBTYPE_ENCRYPTED = 0x06, /// Encrypted BSON value
|
||||||
|
SUBTYPE_USER_DEFINED = 0x80 /// User defined (start of range)
|
||||||
|
};
|
||||||
|
|
||||||
Binary();
|
Binary();
|
||||||
/// Creates an empty Binary with subtype 0.
|
/// Creates an empty Binary with subtype 0.
|
||||||
|
|
||||||
@@ -57,19 +70,22 @@ public:
|
|||||||
Buffer<unsigned char>& buffer();
|
Buffer<unsigned char>& buffer();
|
||||||
/// Returns a reference to the internal buffer
|
/// Returns a reference to the internal buffer
|
||||||
|
|
||||||
unsigned char subtype() const;
|
[[nodiscard]] unsigned char subtype() const;
|
||||||
/// Returns the subtype.
|
/// Returns the subtype.
|
||||||
|
|
||||||
void subtype(unsigned char type);
|
void subtype(unsigned char type);
|
||||||
/// Sets the subtype.
|
/// Sets the subtype.
|
||||||
|
|
||||||
std::string toString(int indent = 0) const;
|
[[nodiscard]] std::string toString(int indent = 0) const;
|
||||||
/// Returns the contents of the Binary as Base64-encoded string.
|
/// Returns the contents of the Binary as a string.
|
||||||
|
/// For UUID subtype (SUBTYPE_UUID), returns a formatted UUID string
|
||||||
|
/// wrapped in UUID() (e.g., UUID("550e8400-e29b-41d4-a716-446655440000")).
|
||||||
|
/// For other subtypes, returns Base64-encoded data.
|
||||||
|
|
||||||
std::string toRawString() const;
|
[[nodiscard]] std::string toRawString() const;
|
||||||
/// Returns the raw content of the Binary as a string.
|
/// Returns the raw content of the Binary as a string.
|
||||||
|
|
||||||
UUID uuid() const;
|
[[nodiscard]] UUID uuid() const;
|
||||||
/// Returns the UUID when the binary subtype is 0x04.
|
/// Returns the UUID when the binary subtype is 0x04.
|
||||||
/// Otherwise, throws a Poco::BadCastException.
|
/// Otherwise, throws a Poco::BadCastException.
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
#include "Poco/Net/SocketAddress.h"
|
#include "Poco/Net/SocketAddress.h"
|
||||||
#include "Poco/Net/StreamSocket.h"
|
#include "Poco/Net/StreamSocket.h"
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/MongoDB/ResponseMessage.h"
|
|
||||||
#include "Poco/MongoDB/OpMsgMessage.h"
|
#include "Poco/MongoDB/OpMsgMessage.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -35,6 +33,17 @@ class MongoDB_API Connection
|
|||||||
///
|
///
|
||||||
/// See https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/
|
/// See https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/
|
||||||
/// for more information on the wire protocol.
|
/// for more information on the wire protocol.
|
||||||
|
///
|
||||||
|
/// THREAD SAFETY:
|
||||||
|
/// This class is NOT thread-safe. A single Connection instance must not be
|
||||||
|
/// used concurrently from multiple threads without external synchronization.
|
||||||
|
/// Concurrent calls to sendRequest() will result in interleaved data on the
|
||||||
|
/// socket and corrupted responses.
|
||||||
|
///
|
||||||
|
/// For multi-threaded applications, use one of these patterns:
|
||||||
|
/// - Each thread has its own Connection instance
|
||||||
|
/// - Use ObjectPool<Connection> with PooledConnection for connection pooling
|
||||||
|
/// - Protect shared Connection with external mutex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Ptr = Poco::SharedPtr<Connection>;
|
using Ptr = Poco::SharedPtr<Connection>;
|
||||||
@@ -86,7 +95,7 @@ public:
|
|||||||
virtual ~Connection();
|
virtual ~Connection();
|
||||||
/// Destroys the Connection.
|
/// Destroys the Connection.
|
||||||
|
|
||||||
Poco::Net::SocketAddress address() const;
|
[[nodiscard]] Poco::Net::SocketAddress address() const;
|
||||||
/// Returns the address of the MongoDB server.
|
/// Returns the address of the MongoDB server.
|
||||||
|
|
||||||
void connect(const std::string& hostAndPort);
|
void connect(const std::string& hostAndPort);
|
||||||
@@ -107,8 +116,7 @@ public:
|
|||||||
/// a SecureStreamSocket must be supplied.
|
/// a SecureStreamSocket must be supplied.
|
||||||
/// - connectTimeoutMS: Socket connection timeout in milliseconds.
|
/// - connectTimeoutMS: Socket connection timeout in milliseconds.
|
||||||
/// - socketTimeoutMS: Socket send/receive timeout in milliseconds.
|
/// - socketTimeoutMS: Socket send/receive timeout in milliseconds.
|
||||||
/// - authMechanism: Authentication mechanism. Only "SCRAM-SHA-1" (default)
|
/// - authMechanism: Authentication mechanism. Only "SCRAM-SHA-1" is supported.
|
||||||
/// and "MONGODB-CR" are supported.
|
|
||||||
///
|
///
|
||||||
/// Unknown options are silently ignored.
|
/// Unknown options are silently ignored.
|
||||||
///
|
///
|
||||||
@@ -129,24 +137,13 @@ public:
|
|||||||
void disconnect();
|
void disconnect();
|
||||||
/// Disconnects from the MongoDB server.
|
/// Disconnects from the MongoDB server.
|
||||||
|
|
||||||
void sendRequest(RequestMessage& request);
|
|
||||||
/// Sends a request to the MongoDB server.
|
|
||||||
///
|
|
||||||
/// Used for one-way requests without a response.
|
|
||||||
|
|
||||||
void sendRequest(RequestMessage& request, ResponseMessage& response);
|
|
||||||
/// Sends a request to the MongoDB server and receives the response.
|
|
||||||
///
|
|
||||||
/// Use this when a response is expected: only a "query" or "getmore"
|
|
||||||
/// request will return a response.
|
|
||||||
|
|
||||||
void sendRequest(OpMsgMessage& request, OpMsgMessage& response);
|
void sendRequest(OpMsgMessage& request, OpMsgMessage& response);
|
||||||
/// Sends a request to the MongoDB server and receives the response
|
/// Sends a request to the MongoDB server and receives the response
|
||||||
/// using newer wire protocol with OP_MSG.
|
/// using OP_MSG wire protocol.
|
||||||
|
|
||||||
void sendRequest(OpMsgMessage& request);
|
void sendRequest(OpMsgMessage& request);
|
||||||
/// Sends an unacknowledged request to the MongoDB server using newer
|
/// Sends an unacknowledged request to the MongoDB server using
|
||||||
/// wire protocol with OP_MSG.
|
/// OP_MSG wire protocol.
|
||||||
/// No response is sent by the server.
|
/// No response is sent by the server.
|
||||||
|
|
||||||
void readResponse(OpMsgMessage& response);
|
void readResponse(OpMsgMessage& response);
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
//
|
|
||||||
// Cursor.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: Cursor
|
|
||||||
//
|
|
||||||
// Definition of the Cursor class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_Cursor_INCLUDED
|
|
||||||
#define MongoDB_Cursor_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/Connection.h"
|
|
||||||
#include "Poco/MongoDB/QueryRequest.h"
|
|
||||||
#include "Poco/MongoDB/ResponseMessage.h"
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
class POCO_DEPRECATED("Use new wire protocol") Cursor;
|
|
||||||
|
|
||||||
class MongoDB_API Cursor: public Document
|
|
||||||
/// Cursor is an helper class for querying multiple documents.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Cursor(const std::string& dbname, const std::string& collectionName, QueryRequest::Flags flags = QueryRequest::QUERY_DEFAULT);
|
|
||||||
/// Creates a Cursor for the given database and collection, using the specified flags.
|
|
||||||
|
|
||||||
Cursor(const std::string& fullCollectionName, QueryRequest::Flags flags = QueryRequest::QUERY_DEFAULT);
|
|
||||||
/// Creates a Cursor for the given database and collection ("database.collection"), using the specified flags.
|
|
||||||
|
|
||||||
Cursor(const Document& aggregationResponse);
|
|
||||||
/// Creates a Cursor for the given agregation query response.
|
|
||||||
|
|
||||||
virtual ~Cursor();
|
|
||||||
/// Destroys the Cursor.
|
|
||||||
|
|
||||||
ResponseMessage& next(Connection& connection);
|
|
||||||
/// Tries to get the next documents. As long as ResponseMessage has a
|
|
||||||
/// cursor ID next can be called to retrieve the next bunch of documents.
|
|
||||||
///
|
|
||||||
/// The cursor must be killed (see kill()) when not all documents are needed.
|
|
||||||
|
|
||||||
QueryRequest& query();
|
|
||||||
/// Returns the associated query.
|
|
||||||
|
|
||||||
void kill(Connection& connection);
|
|
||||||
/// Kills the cursor and reset it so that it can be reused.
|
|
||||||
|
|
||||||
private:
|
|
||||||
QueryRequest _query;
|
|
||||||
ResponseMessage _response;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline QueryRequest& Cursor::query()
|
|
||||||
{
|
|
||||||
return _query;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_Cursor_INCLUDED
|
|
||||||
@@ -21,14 +21,10 @@
|
|||||||
#include "Poco/MongoDB/MongoDB.h"
|
#include "Poco/MongoDB/MongoDB.h"
|
||||||
#include "Poco/MongoDB/Connection.h"
|
#include "Poco/MongoDB/Connection.h"
|
||||||
#include "Poco/MongoDB/Document.h"
|
#include "Poco/MongoDB/Document.h"
|
||||||
#include "Poco/MongoDB/QueryRequest.h"
|
|
||||||
#include "Poco/MongoDB/InsertRequest.h"
|
|
||||||
#include "Poco/MongoDB/UpdateRequest.h"
|
|
||||||
#include "Poco/MongoDB/DeleteRequest.h"
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/OpMsgMessage.h"
|
#include "Poco/MongoDB/OpMsgMessage.h"
|
||||||
#include "Poco/MongoDB/OpMsgCursor.h"
|
#include "Poco/MongoDB/OpMsgCursor.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace MongoDB {
|
namespace MongoDB {
|
||||||
|
|
||||||
@@ -39,104 +35,74 @@ class MongoDB_API Database
|
|||||||
/// the database.
|
/// the database.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum IndexOptions {
|
||||||
|
INDEX_UNIQUE = 1 << 0,
|
||||||
|
INDEX_SPARSE = 1 << 1,
|
||||||
|
INDEX_BACKGROUND = 1 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
using FieldIndex = std::tuple<std::string, bool>;
|
||||||
|
/// name of the field to index, ascending order (true), descending order (false)
|
||||||
|
|
||||||
|
using IndexedFields = std::vector<FieldIndex>;
|
||||||
|
/// Vector of fields to create index on
|
||||||
|
|
||||||
explicit Database(const std::string& name);
|
explicit Database(const std::string& name);
|
||||||
/// Creates a Database for the database with the given name.
|
/// Creates a Database for the database with the given name.
|
||||||
|
|
||||||
virtual ~Database();
|
virtual ~Database();
|
||||||
/// Destroys the Database.
|
/// Destroys the Database.
|
||||||
|
|
||||||
const std::string& name() const;
|
[[nodiscard]] const std::string& name() const;
|
||||||
/// Database name
|
/// Database name
|
||||||
|
|
||||||
bool authenticate(Connection& connection, const std::string& username, const std::string& password, const std::string& method = AUTH_SCRAM_SHA1);
|
bool authenticate(Connection& connection, const std::string& username, const std::string& password, const std::string& method = AUTH_SCRAM_SHA1);
|
||||||
/// Authenticates against the database using the given connection,
|
/// Authenticates against the database using the given connection,
|
||||||
/// username and password, as well as authentication method.
|
/// username and password, as well as authentication method.
|
||||||
///
|
///
|
||||||
/// "MONGODB-CR" (default prior to MongoDB 3.0) and
|
/// "SCRAM-SHA-1" (default starting in MongoDB 3.0) is the only supported
|
||||||
/// "SCRAM-SHA-1" (default starting in 3.0) are the only supported
|
/// authentication method. "MONGODB-CR" is no longer supported as it
|
||||||
/// authentication methods.
|
/// requires the legacy wire protocol.
|
||||||
///
|
///
|
||||||
/// Returns true if authentication was successful, otherwise false.
|
/// Returns true if authentication was successful, otherwise false.
|
||||||
///
|
///
|
||||||
/// May throw a Poco::ProtocolException if authentication fails for a reason other than
|
/// May throw a Poco::ProtocolException if authentication fails for a reason other than
|
||||||
/// invalid credentials.
|
/// invalid credentials.
|
||||||
|
|
||||||
Document::Ptr queryBuildInfo(Connection& connection) const;
|
[[nodiscard]] Document::Ptr queryBuildInfo(Connection& connection) const;
|
||||||
/// Queries server build info (all wire protocols)
|
/// Queries server build info using OP_MSG protocol.
|
||||||
|
|
||||||
Document::Ptr queryServerHello(Connection& connection) const;
|
[[nodiscard]] Document::Ptr queryServerHello(Connection& connection) const;
|
||||||
/// Queries hello response from server (all wire protocols)
|
/// Queries hello response from server using OP_MSG protocol.
|
||||||
|
|
||||||
Int64 count(Connection& connection, const std::string& collectionName) const;
|
[[nodiscard]] Int64 count(Connection& connection, const std::string& collectionName) const;
|
||||||
/// Sends a count request for the given collection to MongoDB. (old wire protocol)
|
/// Sends a count request for the given collection to MongoDB using OP_MSG protocol.
|
||||||
///
|
///
|
||||||
/// If the command fails, -1 is returned.
|
/// If the command fails, -1 is returned.
|
||||||
|
|
||||||
//[[deprecated]]
|
[[nodiscard]] SharedPtr<OpMsgMessage> createOpMsgMessage(const std::string& collectionName) const;
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> createCommand() const;
|
/// Creates OpMsgMessage for the given collection.
|
||||||
/// Creates a QueryRequest for a command. (old wire protocol)
|
|
||||||
|
|
||||||
//[[deprecated]]
|
[[nodiscard]] SharedPtr<OpMsgMessage> createOpMsgMessage() const;
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> createCountRequest(const std::string& collectionName) const;
|
/// Creates OpMsgMessage for database commands that do not require collection as an argument.
|
||||||
/// Creates a QueryRequest to count the given collection.
|
|
||||||
/// The collectionname must not contain the database name. (old wire protocol)
|
|
||||||
|
|
||||||
POCO_DEPRECATED("Use new wire protocol")
|
[[nodiscard]] SharedPtr<OpMsgCursor> createOpMsgCursor(const std::string& collectionName) const;
|
||||||
Poco::SharedPtr<Poco::MongoDB::DeleteRequest> createDeleteRequest(const std::string& collectionName) const;
|
/// Creates OpMsgCursor for the given collection.
|
||||||
/// Creates a DeleteRequest to delete documents in the given collection.
|
|
||||||
/// The collectionname must not contain the database name. (old wire protocol)
|
|
||||||
|
|
||||||
//[[deprecated]]
|
Document::Ptr createIndex(
|
||||||
Poco::SharedPtr<Poco::MongoDB::InsertRequest> createInsertRequest(const std::string& collectionName) const;
|
Connection& connection,
|
||||||
/// Creates an InsertRequest to insert new documents in the given collection.
|
|
||||||
/// The collectionname must not contain the database name. (old wire protocol)
|
|
||||||
|
|
||||||
//[[deprecated]]
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> createQueryRequest(const std::string& collectionName) const;
|
|
||||||
/// Creates a QueryRequest. (old wire protocol)
|
|
||||||
/// The collectionname must not contain the database name.
|
|
||||||
|
|
||||||
POCO_DEPRECATED("Use new wire protocol")
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::UpdateRequest> createUpdateRequest(const std::string& collectionName) const;
|
|
||||||
/// Creates an UpdateRequest. (old wire protocol)
|
|
||||||
/// The collectionname must not contain the database name.
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> createOpMsgMessage(const std::string& collectionName) const;
|
|
||||||
/// Creates OpMsgMessage. (new wire protocol)
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> createOpMsgMessage() const;
|
|
||||||
/// Creates OpMsgMessage for database commands that do not require collection as an argument. (new wire protocol)
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::OpMsgCursor> createOpMsgCursor(const std::string& collectionName) const;
|
|
||||||
/// Creates OpMsgCursor. (new wire protocol)
|
|
||||||
|
|
||||||
Poco::MongoDB::Document::Ptr ensureIndex(Connection& connection,
|
|
||||||
const std::string& collection,
|
const std::string& collection,
|
||||||
const std::string& indexName,
|
const IndexedFields& indexedFields,
|
||||||
Poco::MongoDB::Document::Ptr keys,
|
const std::string &indexName,
|
||||||
bool unique = false,
|
unsigned long options = 0,
|
||||||
bool background = false,
|
int expirationSeconds = 0,
|
||||||
int version = 0,
|
int version = 0);
|
||||||
int ttl = 0);
|
/// Creates an index. The document returned is the response body..
|
||||||
/// Creates an index. The document returned is the result of a getLastError call.
|
/// For more info look at the createIndex information on the MongoDB website. (new wire protocol)
|
||||||
/// For more info look at the ensureIndex information on the MongoDB website. (old wire protocol)
|
|
||||||
|
|
||||||
//[[deprecated]]
|
|
||||||
Document::Ptr getLastErrorDoc(Connection& connection) const;
|
|
||||||
/// Sends the getLastError command to the database and returns the error document.
|
|
||||||
/// (old wire protocol)
|
|
||||||
|
|
||||||
//[[deprecated]]
|
|
||||||
std::string getLastError(Connection& connection) const;
|
|
||||||
/// Sends the getLastError command to the database and returns the err element
|
|
||||||
/// from the error document. When err is null, an empty string is returned.
|
|
||||||
/// (old wire protocol)
|
|
||||||
|
|
||||||
static const std::string AUTH_MONGODB_CR;
|
|
||||||
/// Default authentication mechanism prior to MongoDB 3.0.
|
|
||||||
|
|
||||||
static const std::string AUTH_SCRAM_SHA1;
|
static const std::string AUTH_SCRAM_SHA1;
|
||||||
/// Default authentication mechanism for MongoDB 3.0.
|
/// Default authentication mechanism for MongoDB 3.0 and later.
|
||||||
|
|
||||||
enum WireVersion
|
enum WireVersion
|
||||||
/// Wire version as reported by the command hello.
|
/// Wire version as reported by the command hello.
|
||||||
@@ -153,14 +119,13 @@ public:
|
|||||||
VER_42 = 8,
|
VER_42 = 8,
|
||||||
VER_44 = 9,
|
VER_44 = 9,
|
||||||
VER_50 = 13,
|
VER_50 = 13,
|
||||||
VER_51 = 14, ///< First wire version that supports only OP_MSG
|
VER_51 = 14, ///< First wire version that supports *only* OP_MSG
|
||||||
VER_52 = 15,
|
VER_52 = 15,
|
||||||
VER_53 = 16,
|
VER_53 = 16,
|
||||||
VER_60 = 17
|
VER_60 = 17
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool authCR(Connection& connection, const std::string& username, const std::string& password);
|
|
||||||
bool authSCRAM(Connection& connection, const std::string& username, const std::string& password);
|
bool authSCRAM(Connection& connection, const std::string& username, const std::string& password);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -177,60 +142,25 @@ inline const std::string& Database::name() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::QueryRequest> Database::createCommand() const
|
inline SharedPtr<OpMsgMessage>
|
||||||
{
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> cmd = createQueryRequest("$cmd");
|
|
||||||
cmd->setNumberToReturn(1);
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::DeleteRequest>
|
|
||||||
Database::createDeleteRequest(const std::string& collectionName) const
|
|
||||||
{
|
|
||||||
return new Poco::MongoDB::DeleteRequest(_dbname + '.' + collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::InsertRequest>
|
|
||||||
Database::createInsertRequest(const std::string& collectionName) const
|
|
||||||
{
|
|
||||||
return new Poco::MongoDB::InsertRequest(_dbname + '.' + collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::QueryRequest>
|
|
||||||
Database::createQueryRequest(const std::string& collectionName) const
|
|
||||||
{
|
|
||||||
return new Poco::MongoDB::QueryRequest(_dbname + '.' + collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::UpdateRequest>
|
|
||||||
Database::createUpdateRequest(const std::string& collectionName) const
|
|
||||||
{
|
|
||||||
return new Poco::MongoDB::UpdateRequest(_dbname + '.' + collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- New wire protocol commands
|
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::OpMsgMessage>
|
|
||||||
Database::createOpMsgMessage(const std::string& collectionName) const
|
Database::createOpMsgMessage(const std::string& collectionName) const
|
||||||
{
|
{
|
||||||
return new Poco::MongoDB::OpMsgMessage(_dbname, collectionName);
|
return new OpMsgMessage(_dbname, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::OpMsgMessage>
|
|
||||||
|
inline SharedPtr<OpMsgMessage>
|
||||||
Database::createOpMsgMessage() const
|
Database::createOpMsgMessage() const
|
||||||
{
|
{
|
||||||
// Collection name for database commands is not needed.
|
// Collection name for database commands is not needed.
|
||||||
return createOpMsgMessage("");
|
return createOpMsgMessage("");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Poco::SharedPtr<Poco::MongoDB::OpMsgCursor>
|
|
||||||
|
inline SharedPtr<OpMsgCursor>
|
||||||
Database::createOpMsgCursor(const std::string& collectionName) const
|
Database::createOpMsgCursor(const std::string& collectionName) const
|
||||||
{
|
{
|
||||||
return new Poco::MongoDB::OpMsgCursor(_dbname, collectionName);
|
return new OpMsgCursor(_dbname, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
//
|
|
||||||
// DeleteRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: DeleteRequest
|
|
||||||
//
|
|
||||||
// Definition of the DeleteRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_DeleteRequest_INCLUDED
|
|
||||||
#define MongoDB_DeleteRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/MongoDB/Document.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class POCO_DEPRECATED("Use new wire protocol") DeleteRequest;
|
|
||||||
|
|
||||||
class MongoDB_API DeleteRequest: public RequestMessage
|
|
||||||
/// A DeleteRequest is used to delete one ore more documents from a database.
|
|
||||||
///
|
|
||||||
/// Specific flags for this request
|
|
||||||
/// - DELETE_DEFAULT: default delete operation
|
|
||||||
/// - DELETE_SINGLE_REMOVE: delete only the first document
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
DELETE_DEFAULT = 0,
|
|
||||||
/// Default
|
|
||||||
|
|
||||||
DELETE_SINGLE_REMOVE = 1
|
|
||||||
/// Delete only the first document.
|
|
||||||
};
|
|
||||||
|
|
||||||
DeleteRequest(const std::string& collectionName, Flags flags = DELETE_DEFAULT);
|
|
||||||
/// Creates a DeleteRequest for the given collection using the given flags.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar".
|
|
||||||
|
|
||||||
DeleteRequest(const std::string& collectionName, bool justOne);
|
|
||||||
/// Creates a DeleteRequest for the given collection.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar".
|
|
||||||
///
|
|
||||||
/// If justOne is true, only the first matching document will
|
|
||||||
/// be removed (the same as using flag DELETE_SINGLE_REMOVE).
|
|
||||||
|
|
||||||
virtual ~DeleteRequest();
|
|
||||||
/// Destructor
|
|
||||||
|
|
||||||
Flags flags() const;
|
|
||||||
/// Returns the flags.
|
|
||||||
|
|
||||||
void flags(Flags flag);
|
|
||||||
/// Sets the flags.
|
|
||||||
|
|
||||||
Document& selector();
|
|
||||||
/// Returns the selector document.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
/// Writes the OP_DELETE request to the writer.
|
|
||||||
|
|
||||||
private:
|
|
||||||
Flags _flags;
|
|
||||||
std::string _fullCollectionName;
|
|
||||||
Document _selector;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// inlines
|
|
||||||
///
|
|
||||||
inline DeleteRequest::Flags DeleteRequest::flags() const
|
|
||||||
{
|
|
||||||
return _flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void DeleteRequest::flags(DeleteRequest::Flags flags)
|
|
||||||
{
|
|
||||||
_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document& DeleteRequest::selector()
|
|
||||||
{
|
|
||||||
return _selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_DeleteRequest_INCLUDED
|
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "Poco/MongoDB/Element.h"
|
#include "Poco/MongoDB/Element.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@@ -51,6 +53,13 @@ private:
|
|||||||
|
|
||||||
class MongoDB_API Document
|
class MongoDB_API Document
|
||||||
/// Represents a MongoDB (BSON) document.
|
/// Represents a MongoDB (BSON) document.
|
||||||
|
///
|
||||||
|
/// THREAD SAFETY:
|
||||||
|
/// This class is NOT thread-safe. Document instances must not be accessed
|
||||||
|
/// concurrently from multiple threads without external synchronization.
|
||||||
|
/// Concurrent modifications to the element list will cause undefined behavior.
|
||||||
|
///
|
||||||
|
/// Each thread should use its own Document instances.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Ptr = SharedPtr<Document>;
|
using Ptr = SharedPtr<Document>;
|
||||||
@@ -77,6 +86,18 @@ public:
|
|||||||
return addElement(new ConcreteElement<T>(name, value));
|
return addElement(new ConcreteElement<T>(name, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename std::enable_if<!std::is_same<typename std::decay<T>::type, const char*>::value, Document&>::type
|
||||||
|
add(std::string&& name, T value)
|
||||||
|
/// Creates an element with the given name (moved) and value and
|
||||||
|
/// adds it to the document. Move semantics for efficiency.
|
||||||
|
/// Disabled for const char* to avoid ambiguity.
|
||||||
|
///
|
||||||
|
/// The active document is returned to allow chaining of the add methods.
|
||||||
|
{
|
||||||
|
return addElement(new ConcreteElement<T>(std::move(name), value));
|
||||||
|
}
|
||||||
|
|
||||||
Document& add(const std::string& name, const char* value)
|
Document& add(const std::string& name, const char* value)
|
||||||
/// Creates an element with the given name and value and
|
/// Creates an element with the given name and value and
|
||||||
/// adds it to the document.
|
/// adds it to the document.
|
||||||
@@ -95,16 +116,16 @@ public:
|
|||||||
/// Create a new array and add it to this document.
|
/// Create a new array and add it to this document.
|
||||||
/// Method returns a reference to the new array.
|
/// Method returns a reference to the new array.
|
||||||
|
|
||||||
void clear();
|
void clear() noexcept;
|
||||||
/// Removes all elements from the document.
|
/// Removes all elements from the document.
|
||||||
|
|
||||||
void elementNames(std::vector<std::string>& keys) const;
|
void elementNames(std::vector<std::string>& keys) const;
|
||||||
/// Puts all element names into std::vector.
|
/// Puts all element names into std::vector.
|
||||||
|
|
||||||
bool empty() const;
|
[[nodiscard]] bool empty() const noexcept;
|
||||||
/// Returns true if the document doesn't contain any documents.
|
/// Returns true if the document doesn't contain any documents.
|
||||||
|
|
||||||
bool exists(const std::string& name) const;
|
[[nodiscard]] bool exists(const std::string& name) const noexcept;
|
||||||
/// Returns true if the document has an element with the given name.
|
/// Returns true if the document has an element with the given name.
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -157,11 +178,11 @@ public:
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element::Ptr get(const std::string& name) const;
|
[[nodiscard]] Element::Ptr get(const std::string& name) const;
|
||||||
/// Returns the element with the given name.
|
/// Returns the element with the given name.
|
||||||
/// An empty element will be returned when the element is not found.
|
/// An empty element will be returned when the element is not found.
|
||||||
|
|
||||||
Int64 getInteger(const std::string& name) const;
|
[[nodiscard]] Int64 getInteger(const std::string& name) const;
|
||||||
/// Returns an integer. Useful when MongoDB returns Int32, Int64
|
/// Returns an integer. Useful when MongoDB returns Int32, Int64
|
||||||
/// or double for a number (count for example). This method will always
|
/// or double for a number (count for example). This method will always
|
||||||
/// return an Int64. When the element is not found, a
|
/// return an Int64. When the element is not found, a
|
||||||
@@ -186,17 +207,26 @@ public:
|
|||||||
void read(BinaryReader& reader);
|
void read(BinaryReader& reader);
|
||||||
/// Reads a document from the reader
|
/// Reads a document from the reader
|
||||||
|
|
||||||
std::size_t size() const;
|
[[nodiscard]] std::size_t size() const noexcept;
|
||||||
/// Returns the number of elements in the document.
|
/// Returns the number of elements in the document.
|
||||||
|
|
||||||
virtual std::string toString(int indent = 0) const;
|
[[nodiscard]] virtual std::string toString(int indent = 0) const;
|
||||||
/// Returns a String representation of the document.
|
/// Returns a String representation of the document.
|
||||||
|
|
||||||
void write(BinaryWriter& writer);
|
void write(BinaryWriter& writer);
|
||||||
/// Writes a document to the reader
|
/// Writes a document to the reader
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
const ElementSet& elements() const noexcept;
|
||||||
|
/// Returns const reference to elements for read-only access by derived classes.
|
||||||
|
/// Direct modification is not allowed to maintain synchronization with hash map.
|
||||||
|
|
||||||
|
private:
|
||||||
ElementSet _elements;
|
ElementSet _elements;
|
||||||
|
std::unordered_map<std::string, Element::Ptr> _elementMap;
|
||||||
|
/// Hash map for O(1) element lookups by name.
|
||||||
|
/// Maintained in sync with _elements for fast access.
|
||||||
|
/// These are private to ensure derived classes cannot break synchronization.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -206,6 +236,7 @@ protected:
|
|||||||
inline Document& Document::addElement(Element::Ptr element)
|
inline Document& Document::addElement(Element::Ptr element)
|
||||||
{
|
{
|
||||||
_elements.push_back(element);
|
_elements.push_back(element);
|
||||||
|
_elementMap[element->name()] = element; // O(1) insert for fast lookups
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,13 +249,14 @@ inline Document& Document::addNewDocument(const std::string& name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void Document::clear()
|
inline void Document::clear() noexcept
|
||||||
{
|
{
|
||||||
_elements.clear();
|
_elements.clear();
|
||||||
|
_elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Document::empty() const
|
inline bool Document::empty() const noexcept
|
||||||
{
|
{
|
||||||
return _elements.empty();
|
return _elements.empty();
|
||||||
}
|
}
|
||||||
@@ -232,6 +264,7 @@ inline bool Document::empty() const
|
|||||||
|
|
||||||
inline void Document::elementNames(std::vector<std::string>& keys) const
|
inline void Document::elementNames(std::vector<std::string>& keys) const
|
||||||
{
|
{
|
||||||
|
keys.reserve(keys.size() + _elements.size()); // Pre-allocate to avoid reallocations
|
||||||
for (const auto & _element : _elements)
|
for (const auto & _element : _elements)
|
||||||
{
|
{
|
||||||
keys.push_back(_element->name());
|
keys.push_back(_element->name());
|
||||||
@@ -239,29 +272,43 @@ inline void Document::elementNames(std::vector<std::string>& keys) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Document::exists(const std::string& name) const
|
inline bool Document::exists(const std::string& name) const noexcept
|
||||||
{
|
{
|
||||||
return std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name)) != _elements.end();
|
// O(1) lookup using hash map instead of O(n) linear search
|
||||||
|
return _elementMap.find(name) != _elementMap.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Document::remove(const std::string& name)
|
inline bool Document::remove(const std::string& name)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name));
|
// Remove from hash map first (O(1))
|
||||||
if (it == _elements.end())
|
auto mapIt = _elementMap.find(name);
|
||||||
|
if (mapIt == _elementMap.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
_elementMap.erase(mapIt);
|
||||||
|
|
||||||
|
// Then remove from vector (O(n) but unavoidable for order preservation)
|
||||||
|
auto it = std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name));
|
||||||
|
if (it != _elements.end())
|
||||||
_elements.erase(it);
|
_elements.erase(it);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t Document::size() const
|
inline std::size_t Document::size() const noexcept
|
||||||
{
|
{
|
||||||
return _elements.size();
|
return _elements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const ElementSet& Document::elements() const noexcept
|
||||||
|
{
|
||||||
|
return _elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// BSON Embedded Document
|
// BSON Embedded Document
|
||||||
// spec: document
|
// spec: document
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -47,16 +47,19 @@ public:
|
|||||||
explicit Element(const std::string& name);
|
explicit Element(const std::string& name);
|
||||||
/// Creates the Element with the given name.
|
/// Creates the Element with the given name.
|
||||||
|
|
||||||
|
explicit Element(std::string&& name);
|
||||||
|
/// Creates the Element with the given name (move semantics).
|
||||||
|
|
||||||
virtual ~Element();
|
virtual ~Element();
|
||||||
/// Destructor
|
/// Destructor
|
||||||
|
|
||||||
const std::string& name() const;
|
[[nodiscard]] const std::string& name() const noexcept;
|
||||||
/// Returns the name of the element.
|
/// Returns the name of the element.
|
||||||
|
|
||||||
virtual std::string toString(int indent = 0) const = 0;
|
[[nodiscard]] virtual std::string toString(int indent = 0) const = 0;
|
||||||
/// Returns a string representation of the element.
|
/// Returns a string representation of the element.
|
||||||
|
|
||||||
virtual int type() const = 0;
|
[[nodiscard]] virtual int type() const noexcept = 0;
|
||||||
/// Returns the MongoDB type of the element.
|
/// Returns the MongoDB type of the element.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -71,13 +74,13 @@ private:
|
|||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
inline const std::string& Element::name() const
|
inline const std::string& Element::name() const noexcept
|
||||||
{
|
{
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using ElementSet = std::list<Element::Ptr>;
|
using ElementSet = std::vector<Element::Ptr>;
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -110,51 +113,76 @@ struct ElementTraits<std::string>
|
|||||||
|
|
||||||
static std::string toString(const std::string& value, int indent = 0)
|
static std::string toString(const std::string& value, int indent = 0)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
// Fast path: check if escaping is needed at all
|
||||||
|
bool needsEscaping = false;
|
||||||
oss << '"';
|
for (char c : value)
|
||||||
|
|
||||||
for (char it : value)
|
|
||||||
{
|
{
|
||||||
switch (it)
|
if (c == '"' || c == '\\' || c == '\b' || c == '\f' ||
|
||||||
|
c == '\n' || c == '\r' || c == '\t' || (c > 0 && c <= 0x1F))
|
||||||
|
{
|
||||||
|
needsEscaping = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast path: no escaping needed - just wrap in quotes
|
||||||
|
if (!needsEscaping)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
result.reserve(value.size() + 2);
|
||||||
|
result += '"';
|
||||||
|
result += value;
|
||||||
|
result += '"';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow path: escaping needed
|
||||||
|
std::string result;
|
||||||
|
result.reserve(value.size() * 2 + 2); // Pessimistic estimate
|
||||||
|
result += '"';
|
||||||
|
|
||||||
|
for (char c : value)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
{
|
{
|
||||||
case '"':
|
case '"':
|
||||||
oss << "\\\"";
|
result += "\\\"";
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
oss << "\\\\";
|
result += "\\\\";
|
||||||
break;
|
break;
|
||||||
case '\b':
|
case '\b':
|
||||||
oss << "\\b";
|
result += "\\b";
|
||||||
break;
|
break;
|
||||||
case '\f':
|
case '\f':
|
||||||
oss << "\\f";
|
result += "\\f";
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
oss << "\\n";
|
result += "\\n";
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
oss << "\\r";
|
result += "\\r";
|
||||||
break;
|
break;
|
||||||
case '\t':
|
case '\t':
|
||||||
oss << "\\t";
|
result += "\\t";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (c > 0 && c <= 0x1F)
|
||||||
{
|
{
|
||||||
if ( it > 0 && it <= 0x1F )
|
// Unicode escape sequence
|
||||||
{
|
char buf[7]; // "\uXXXX" + null terminator
|
||||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(it);
|
std::snprintf(buf, sizeof(buf), "\\u%04X", static_cast<unsigned char>(c));
|
||||||
|
result += buf;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
oss << it;
|
result += c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
result += '"';
|
||||||
oss << '"';
|
return result;
|
||||||
return oss.str();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -233,9 +261,10 @@ struct ElementTraits<Timestamp>
|
|||||||
static std::string toString(const Timestamp& value, int indent = 0)
|
static std::string toString(const Timestamp& value, int indent = 0)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
result.append(1, '"');
|
result.reserve(32); // Pre-allocate for typical timestamp string length
|
||||||
result.append(DateTimeFormatter::format(value, "%Y-%m-%dT%H:%M:%s%z"));
|
result += '"';
|
||||||
result.append(1, '"');
|
result += DateTimeFormatter::format(value, "%Y-%m-%dT%H:%M:%s%z");
|
||||||
|
result += '"';
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -304,11 +333,12 @@ struct ElementTraits<BSONTimestamp>
|
|||||||
static std::string toString(const BSONTimestamp& value, int indent = 0)
|
static std::string toString(const BSONTimestamp& value, int indent = 0)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
result.append(1, '"');
|
result.reserve(48); // Pre-allocate for timestamp + space + increment + quotes
|
||||||
result.append(DateTimeFormatter::format(value.ts, "%Y-%m-%dT%H:%M:%s%z"));
|
result += '"';
|
||||||
result.append(1, ' ');
|
result += DateTimeFormatter::format(value.ts, "%Y-%m-%dT%H:%M:%s%z");
|
||||||
result.append(NumberFormatter::format(value.inc));
|
result += ' ';
|
||||||
result.append(1, '"');
|
result += NumberFormatter::format(value.inc);
|
||||||
|
result += '"';
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -359,22 +389,28 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConcreteElement(std::string&& name, T&& init):
|
||||||
|
Element(std::move(name)),
|
||||||
|
_value(std::move(init))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
~ConcreteElement() override = default;
|
~ConcreteElement() override = default;
|
||||||
|
|
||||||
|
|
||||||
const T& value() const
|
const T& value() const noexcept
|
||||||
{
|
{
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string toString(int indent = 0) const override
|
[[nodiscard]] std::string toString(int indent = 0) const override
|
||||||
{
|
{
|
||||||
return ElementTraits<T>::toString(_value, indent);
|
return ElementTraits<T>::toString(_value, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int type() const override
|
[[nodiscard]] int type() const noexcept override
|
||||||
{
|
{
|
||||||
return ElementTraits<T>::TypeId;
|
return ElementTraits<T>::TypeId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// GetMoreRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: GetMoreRequest
|
|
||||||
//
|
|
||||||
// Definition of the GetMoreRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_GetMoreRequest_INCLUDED
|
|
||||||
#define MongoDB_GetMoreRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class [[deprecated]] GetMoreRequest;
|
|
||||||
class GetMoreRequest;
|
|
||||||
|
|
||||||
class MongoDB_API GetMoreRequest: public RequestMessage
|
|
||||||
/// A GetMoreRequest is used to query the database for more documents in a collection
|
|
||||||
/// after a query request is send (OP_GETMORE).
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GetMoreRequest(const std::string& collectionName, Int64 cursorID);
|
|
||||||
/// Creates a GetMoreRequest for the give collection and cursor.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar". The cursorID has been returned by the response on the query request.
|
|
||||||
/// By default the numberToReturn is set to 100.
|
|
||||||
|
|
||||||
virtual ~GetMoreRequest();
|
|
||||||
/// Destroys the GetMoreRequest.
|
|
||||||
|
|
||||||
Int32 getNumberToReturn() const;
|
|
||||||
/// Returns the limit of returned documents.
|
|
||||||
|
|
||||||
void setNumberToReturn(Int32 n);
|
|
||||||
/// Sets the limit of returned documents.
|
|
||||||
|
|
||||||
Int64 cursorID() const;
|
|
||||||
/// Returns the cursor ID.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string _fullCollectionName;
|
|
||||||
Int32 _numberToReturn;
|
|
||||||
Int64 _cursorID;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline Int32 GetMoreRequest::getNumberToReturn() const
|
|
||||||
{
|
|
||||||
return _numberToReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void GetMoreRequest::setNumberToReturn(Int32 n)
|
|
||||||
{
|
|
||||||
_numberToReturn = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Int64 GetMoreRequest::cursorID() const
|
|
||||||
{
|
|
||||||
return _cursorID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_GetMoreRequest_INCLUDED
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
// InsertRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: InsertRequest
|
|
||||||
//
|
|
||||||
// Definition of the InsertRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_InsertRequest_INCLUDED
|
|
||||||
#define MongoDB_InsertRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/MongoDB/Document.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class [[deprecated]] InsertRequest;
|
|
||||||
class InsertRequest;
|
|
||||||
|
|
||||||
class MongoDB_API InsertRequest: public RequestMessage
|
|
||||||
/// A request for inserting one or more documents to the database
|
|
||||||
/// (OP_INSERT).
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
INSERT_DEFAULT = 0,
|
|
||||||
/// If specified, perform a normal insert operation.
|
|
||||||
|
|
||||||
INSERT_CONTINUE_ON_ERROR = 1
|
|
||||||
/// If set, the database will not stop processing a bulk insert if one
|
|
||||||
/// fails (e.g. due to duplicate IDs). This makes bulk insert behave similarly
|
|
||||||
/// to a series of single inserts, except lastError will be set if any insert
|
|
||||||
/// fails, not just the last one. If multiple errors occur, only the most
|
|
||||||
/// recent will be reported.
|
|
||||||
};
|
|
||||||
|
|
||||||
InsertRequest(const std::string& collectionName, Flags flags = INSERT_DEFAULT);
|
|
||||||
/// Creates an InsertRequest.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar".
|
|
||||||
|
|
||||||
virtual ~InsertRequest();
|
|
||||||
/// Destroys the InsertRequest.
|
|
||||||
|
|
||||||
Document& addNewDocument();
|
|
||||||
/// Adds a new document for insertion. A reference to the empty document is
|
|
||||||
/// returned. InsertRequest is the owner of the Document and will free it
|
|
||||||
/// on destruction.
|
|
||||||
|
|
||||||
Document::Vector& documents();
|
|
||||||
/// Returns the documents to insert into the database.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Int32 _flags;
|
|
||||||
std::string _fullCollectionName;
|
|
||||||
Document::Vector _documents;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline Document& InsertRequest::addNewDocument()
|
|
||||||
{
|
|
||||||
Document::Ptr doc = new Document();
|
|
||||||
_documents.push_back(doc);
|
|
||||||
return *doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document::Vector& InsertRequest::documents()
|
|
||||||
{
|
|
||||||
return _documents;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_InsertRequest_INCLUDED
|
|
||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
void setCode(const std::string& code);
|
void setCode(const std::string& code);
|
||||||
/// Sets the JavaScript code.
|
/// Sets the JavaScript code.
|
||||||
|
|
||||||
std::string getCode() const;
|
[[nodiscard]] std::string getCode() const;
|
||||||
/// Returns the JavaScript code.
|
/// Returns the JavaScript code.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
//
|
|
||||||
// KillCursorsRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: KillCursorsRequest
|
|
||||||
//
|
|
||||||
// Definition of the KillCursorsRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_KillCursorsRequest_INCLUDED
|
|
||||||
#define MongoDB_KillCursorsRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
class MongoDB_API KillCursorsRequest: public RequestMessage
|
|
||||||
/// Class for creating an OP_KILL_CURSORS client request. This
|
|
||||||
/// request is used to kill cursors, which are still open,
|
|
||||||
/// returned by query requests.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KillCursorsRequest();
|
|
||||||
/// Creates a KillCursorsRequest.
|
|
||||||
|
|
||||||
virtual ~KillCursorsRequest();
|
|
||||||
/// Destroys the KillCursorsRequest.
|
|
||||||
|
|
||||||
std::vector<Int64>& cursors();
|
|
||||||
/// The internal list of cursors.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
std::vector<Int64> _cursors;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline std::vector<Int64>& KillCursorsRequest::cursors()
|
|
||||||
{
|
|
||||||
return _cursors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_KillCursorsRequest_INCLUDED
|
|
||||||
@@ -40,7 +40,7 @@ public:
|
|||||||
virtual ~Message();
|
virtual ~Message();
|
||||||
/// Destructor
|
/// Destructor
|
||||||
|
|
||||||
MessageHeader& header();
|
[[nodiscard]] MessageHeader& header();
|
||||||
/// Returns the message header
|
/// Returns the message header
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -38,25 +38,6 @@ public:
|
|||||||
|
|
||||||
enum OpCode
|
enum OpCode
|
||||||
{
|
{
|
||||||
#if false
|
|
||||||
// Opcodes deprecated in MongoDB 5.0
|
|
||||||
OP_REPLY [[deprecated]] = 1,
|
|
||||||
OP_UPDATE [[deprecated]] = 2001,
|
|
||||||
OP_INSERT [[deprecated]] = 2002,
|
|
||||||
OP_QUERY [[deprecated]] = 2004,
|
|
||||||
OP_GET_MORE [[deprecated]] = 2005,
|
|
||||||
OP_DELETE [[deprecated]] = 2006,
|
|
||||||
OP_KILL_CURSORS [[deprecated]] = 2007,
|
|
||||||
#else
|
|
||||||
OP_REPLY = 1,
|
|
||||||
OP_UPDATE = 2001,
|
|
||||||
OP_INSERT = 2002,
|
|
||||||
OP_QUERY = 2004,
|
|
||||||
OP_GET_MORE = 2005,
|
|
||||||
OP_DELETE = 2006,
|
|
||||||
OP_KILL_CURSORS = 2007,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Opcodes supported in MongoDB 5.1 and later
|
/// Opcodes supported in MongoDB 5.1 and later
|
||||||
OP_COMPRESSED = 2012,
|
OP_COMPRESSED = 2012,
|
||||||
OP_MSG = 2013
|
OP_MSG = 2013
|
||||||
@@ -74,19 +55,19 @@ public:
|
|||||||
void write(BinaryWriter& writer);
|
void write(BinaryWriter& writer);
|
||||||
/// Writes the header using the given BinaryWriter.
|
/// Writes the header using the given BinaryWriter.
|
||||||
|
|
||||||
Int32 getMessageLength() const;
|
[[nodiscard]] Int32 getMessageLength() const;
|
||||||
/// Returns the message length.
|
/// Returns the message length.
|
||||||
|
|
||||||
OpCode opCode() const;
|
[[nodiscard]] OpCode opCode() const;
|
||||||
/// Returns the OpCode.
|
/// Returns the OpCode.
|
||||||
|
|
||||||
Int32 getRequestID() const;
|
[[nodiscard]] Int32 getRequestID() const;
|
||||||
/// Returns the request ID of the current message.
|
/// Returns the request ID of the current message.
|
||||||
|
|
||||||
void setRequestID(Int32 id);
|
void setRequestID(Int32 id);
|
||||||
/// Sets the request ID of the current message.
|
/// Sets the request ID of the current message.
|
||||||
|
|
||||||
Int32 responseTo() const;
|
[[nodiscard]] Int32 responseTo() const;
|
||||||
/// Returns the request id from the original request.
|
/// Returns the request id from the original request.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -50,16 +50,25 @@ public:
|
|||||||
/// The string must contain a hexadecimal representation
|
/// The string must contain a hexadecimal representation
|
||||||
/// of an object ID. This means a string of 24 characters.
|
/// of an object ID. This means a string of 24 characters.
|
||||||
|
|
||||||
ObjectId(const ObjectId& copy);
|
ObjectId(const ObjectId& copy) noexcept;
|
||||||
/// Creates an ObjectId by copying another one.
|
/// Creates an ObjectId by copying another one.
|
||||||
|
|
||||||
|
ObjectId(ObjectId&& other) noexcept;
|
||||||
|
/// Creates an ObjectId by moving another one.
|
||||||
|
|
||||||
|
ObjectId& operator=(const ObjectId& copy) noexcept;
|
||||||
|
/// Assigns another ObjectId.
|
||||||
|
|
||||||
|
ObjectId& operator=(ObjectId&& other) noexcept;
|
||||||
|
/// Move-assigns another ObjectId.
|
||||||
|
|
||||||
virtual ~ObjectId();
|
virtual ~ObjectId();
|
||||||
/// Destroys the ObjectId.
|
/// Destroys the ObjectId.
|
||||||
|
|
||||||
Timestamp timestamp() const;
|
[[nodiscard]] Timestamp timestamp() const noexcept;
|
||||||
/// Returns the timestamp which is stored in the first four bytes of the id
|
/// Returns the timestamp which is stored in the first four bytes of the id
|
||||||
|
|
||||||
std::string toString(const std::string& fmt = "%02x") const;
|
[[nodiscard]] std::string toString(const std::string& fmt = "%02x") const;
|
||||||
/// Returns the id in string format. The fmt parameter
|
/// Returns the id in string format. The fmt parameter
|
||||||
/// specifies the formatting used for individual members
|
/// specifies the formatting used for individual members
|
||||||
/// of the ID char array.
|
/// of the ID char array.
|
||||||
@@ -67,8 +76,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
ObjectId();
|
ObjectId();
|
||||||
|
|
||||||
static int fromHex(char c);
|
static constexpr int fromHex(char c) noexcept;
|
||||||
static char fromHex(const char* c);
|
static constexpr char fromHex(const char* c) noexcept;
|
||||||
|
|
||||||
unsigned char _id[12];
|
unsigned char _id[12];
|
||||||
|
|
||||||
@@ -81,19 +90,19 @@ private:
|
|||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
inline Timestamp ObjectId::timestamp() const
|
inline Timestamp ObjectId::timestamp() const noexcept
|
||||||
{
|
{
|
||||||
int time;
|
int time;
|
||||||
char* T = (char *) &time;
|
char* T = reinterpret_cast<char*>(&time);
|
||||||
T[0] = _id[3];
|
T[0] = _id[3];
|
||||||
T[1] = _id[2];
|
T[1] = _id[2];
|
||||||
T[2] = _id[1];
|
T[2] = _id[1];
|
||||||
T[3] = _id[0];
|
T[3] = _id[0];
|
||||||
return Timestamp::fromEpochTime((time_t) time);
|
return Timestamp::fromEpochTime(static_cast<time_t>(time));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline int ObjectId::fromHex(char c)
|
constexpr inline int ObjectId::fromHex(char c) noexcept
|
||||||
{
|
{
|
||||||
if ( '0' <= c && c <= '9' )
|
if ( '0' <= c && c <= '9' )
|
||||||
return c - '0';
|
return c - '0';
|
||||||
@@ -105,9 +114,9 @@ inline int ObjectId::fromHex(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline char ObjectId::fromHex(const char* c)
|
constexpr inline char ObjectId::fromHex(const char* c) noexcept
|
||||||
{
|
{
|
||||||
return (char)((fromHex(c[0]) << 4 ) | fromHex(c[1]));
|
return static_cast<char>((fromHex(c[0]) << 4) | fromHex(c[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,14 +139,14 @@ struct ElementTraits<ObjectId::Ptr>
|
|||||||
template<>
|
template<>
|
||||||
inline void BSONReader::read<ObjectId::Ptr>(ObjectId::Ptr& to)
|
inline void BSONReader::read<ObjectId::Ptr>(ObjectId::Ptr& to)
|
||||||
{
|
{
|
||||||
_reader.readRaw((char*) to->_id, 12);
|
_reader.readRaw(reinterpret_cast<char*>(to->_id), 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void BSONWriter::write<ObjectId::Ptr>(ObjectId::Ptr& from)
|
inline void BSONWriter::write<ObjectId::Ptr>(ObjectId::Ptr& from)
|
||||||
{
|
{
|
||||||
_writer.writeRaw((char*) from->_id, 12);
|
_writer.writeRaw(reinterpret_cast<char*>(from->_id), 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,16 @@ namespace MongoDB {
|
|||||||
class MongoDB_API OpMsgCursor: public Document
|
class MongoDB_API OpMsgCursor: public Document
|
||||||
/// OpMsgCursor is an helper class for querying multiple documents using OpMsgMessage.
|
/// OpMsgCursor is an helper class for querying multiple documents using OpMsgMessage.
|
||||||
/// Once all of the data is read with the cursor (see isActive()) it can't be reused.
|
/// Once all of the data is read with the cursor (see isActive()) it can't be reused.
|
||||||
|
///
|
||||||
|
/// RESOURCE MANAGEMENT:
|
||||||
|
/// When a cursor is no longer needed, you should call kill() to release server-side
|
||||||
|
/// resources. If kill() is not called explicitly, the server will keep the cursor
|
||||||
|
/// open until it times out.
|
||||||
|
///
|
||||||
|
/// THREAD SAFETY:
|
||||||
|
/// This class is NOT thread-safe. A cursor must not be used concurrently from
|
||||||
|
/// multiple threads. Each thread should have its own cursor instances.
|
||||||
|
/// The next() method modifies internal state and is not safe for concurrent access.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpMsgCursor(const std::string& dbname, const std::string& collectionName);
|
OpMsgCursor(const std::string& dbname, const std::string& collectionName);
|
||||||
@@ -37,20 +47,20 @@ public:
|
|||||||
virtual ~OpMsgCursor();
|
virtual ~OpMsgCursor();
|
||||||
/// Destroys the OpMsgCursor.
|
/// Destroys the OpMsgCursor.
|
||||||
|
|
||||||
void setEmptyFirstBatch(bool empty);
|
void setEmptyFirstBatch(bool empty) noexcept;
|
||||||
/// Empty first batch is used to get error response faster with little server processing
|
/// Empty first batch is used to get error response faster with little server processing
|
||||||
|
|
||||||
bool emptyFirstBatch() const;
|
[[nodiscard]] bool emptyFirstBatch() const noexcept;
|
||||||
|
|
||||||
void setBatchSize(Int32 batchSize);
|
void setBatchSize(Int32 batchSize) noexcept;
|
||||||
/// Set non-default batch size
|
/// Set non-default batch size
|
||||||
|
|
||||||
Int32 batchSize() const;
|
[[nodiscard]] Int32 batchSize() const noexcept;
|
||||||
/// Current batch size (zero or negative number indicates default batch size)
|
/// Current batch size (zero or negative number indicates default batch size)
|
||||||
|
|
||||||
Int64 cursorID() const;
|
[[nodiscard]] Int64 cursorID() const noexcept;
|
||||||
|
|
||||||
bool isActive() const;
|
[[nodiscard]] bool isActive() const noexcept;
|
||||||
/// Is there more data to acquire with this cursor?
|
/// Is there more data to acquire with this cursor?
|
||||||
|
|
||||||
OpMsgMessage& next(Connection& connection);
|
OpMsgMessage& next(Connection& connection);
|
||||||
@@ -85,7 +95,7 @@ inline OpMsgMessage& OpMsgCursor::query()
|
|||||||
return _query;
|
return _query;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Int64 OpMsgCursor::cursorID() const
|
inline Int64 OpMsgCursor::cursorID() const noexcept
|
||||||
{
|
{
|
||||||
return _cursorID;
|
return _cursorID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ namespace MongoDB {
|
|||||||
|
|
||||||
class MongoDB_API OpMsgMessage: public Message
|
class MongoDB_API OpMsgMessage: public Message
|
||||||
/// This class represents a request/response (OP_MSG) to send requests and receive responses to/from MongoDB.
|
/// This class represents a request/response (OP_MSG) to send requests and receive responses to/from MongoDB.
|
||||||
|
///
|
||||||
|
/// THREAD SAFETY:
|
||||||
|
/// This class is NOT thread-safe. OpMsgMessage instances must not be accessed
|
||||||
|
/// concurrently from multiple threads without external synchronization.
|
||||||
|
/// Each thread should use its own message instances.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -90,14 +95,14 @@ public:
|
|||||||
|
|
||||||
virtual ~OpMsgMessage();
|
virtual ~OpMsgMessage();
|
||||||
|
|
||||||
const std::string& databaseName() const;
|
[[nodiscard]] const std::string& databaseName() const;
|
||||||
|
|
||||||
const std::string& collectionName() const;
|
[[nodiscard]] const std::string& collectionName() const;
|
||||||
|
|
||||||
void setCommandName(const std::string& command);
|
void setCommandName(const std::string& command);
|
||||||
/// Sets the command name and clears the command document
|
/// Sets the command name and clears the command document
|
||||||
|
|
||||||
const std::string& commandName() const;
|
[[nodiscard]] const std::string& commandName() const;
|
||||||
/// Current command name.
|
/// Current command name.
|
||||||
|
|
||||||
void setAcknowledgedRequest(bool ack);
|
void setAcknowledgedRequest(bool ack);
|
||||||
@@ -105,23 +110,23 @@ public:
|
|||||||
/// It has effect only for commands that write or delete documents.
|
/// It has effect only for commands that write or delete documents.
|
||||||
/// Default is true (request returns acknowledge response).
|
/// Default is true (request returns acknowledge response).
|
||||||
|
|
||||||
bool acknowledgedRequest() const;
|
[[nodiscard]] bool acknowledgedRequest() const;
|
||||||
|
|
||||||
UInt32 flags() const;
|
[[nodiscard]] UInt32 flags() const;
|
||||||
|
|
||||||
Document& body();
|
Document& body();
|
||||||
/// Access to body document.
|
/// Access to body document.
|
||||||
/// Additional query arguments shall be added after setting the command name.
|
/// Additional query arguments shall be added after setting the command name.
|
||||||
|
|
||||||
const Document& body() const;
|
[[nodiscard]] const Document& body() const;
|
||||||
|
|
||||||
Document::Vector& documents();
|
Document::Vector& documents();
|
||||||
/// Documents prepared for request or retrieved in response.
|
/// Documents prepared for request or retrieved in response.
|
||||||
|
|
||||||
const Document::Vector& documents() const;
|
[[nodiscard]] const Document::Vector& documents() const;
|
||||||
/// Documents prepared for request or retrieved in response.
|
/// Documents prepared for request or retrieved in response.
|
||||||
|
|
||||||
bool responseOk() const;
|
[[nodiscard]] bool responseOk() const;
|
||||||
/// Reads "ok" status from the response message.
|
/// Reads "ok" status from the response message.
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
//
|
|
||||||
// QueryRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: QueryRequest
|
|
||||||
//
|
|
||||||
// Definition of the QueryRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_QueryRequest_INCLUDED
|
|
||||||
#define MongoDB_QueryRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/MongoDB/Document.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class [[deprecated]] QueryRequest;
|
|
||||||
class QueryRequest;
|
|
||||||
|
|
||||||
class MongoDB_API QueryRequest: public RequestMessage
|
|
||||||
/// A request to query documents in a MongoDB database
|
|
||||||
/// using an OP_QUERY request.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
QUERY_DEFAULT = 0,
|
|
||||||
/// Do not set any flags.
|
|
||||||
|
|
||||||
QUERY_TAILABLE_CURSOR = 2,
|
|
||||||
/// Tailable means cursor is not closed when the last data is retrieved.
|
|
||||||
/// Rather, the cursor marks the final object’s position.
|
|
||||||
/// You can resume using the cursor later, from where it was located,
|
|
||||||
/// if more data were received. Like any "latent cursor", the cursor may
|
|
||||||
/// become invalid at some point (CursorNotFound) – for example if the final
|
|
||||||
/// object it references were deleted.
|
|
||||||
|
|
||||||
QUERY_SLAVE_OK = 4,
|
|
||||||
/// Allow query of replica slave. Normally these return an error except
|
|
||||||
/// for namespace "local".
|
|
||||||
|
|
||||||
// QUERY_OPLOG_REPLAY = 8 (internal replication use only - drivers should not implement)
|
|
||||||
|
|
||||||
QUERY_NO_CURSOR_TIMEOUT = 16,
|
|
||||||
/// The server normally times out idle cursors after an inactivity period
|
|
||||||
/// (10 minutes) to prevent excess memory use. Set this option to prevent that.
|
|
||||||
|
|
||||||
QUERY_AWAIT_DATA = 32,
|
|
||||||
/// Use with QUERY_TAILABLECURSOR. If we are at the end of the data, block for
|
|
||||||
/// a while rather than returning no data. After a timeout period, we do
|
|
||||||
/// return as normal.
|
|
||||||
|
|
||||||
QUERY_EXHAUST = 64,
|
|
||||||
/// Stream the data down full blast in multiple "more" packages, on the
|
|
||||||
/// assumption that the client will fully read all data queried.
|
|
||||||
/// Faster when you are pulling a lot of data and know you want to pull
|
|
||||||
/// it all down.
|
|
||||||
/// Note: the client is not allowed to not read all the data unless it
|
|
||||||
/// closes the connection.
|
|
||||||
|
|
||||||
QUERY_PARTIAL = 128
|
|
||||||
/// Get partial results from a mongos if some shards are down
|
|
||||||
/// (instead of throwing an error).
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryRequest(const std::string& collectionName, Flags flags = QUERY_DEFAULT);
|
|
||||||
/// Creates a QueryRequest.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar".
|
|
||||||
|
|
||||||
virtual ~QueryRequest();
|
|
||||||
/// Destroys the QueryRequest.
|
|
||||||
|
|
||||||
Flags getFlags() const;
|
|
||||||
/// Returns the flags.
|
|
||||||
|
|
||||||
void setFlags(Flags flag);
|
|
||||||
/// Set the flags.
|
|
||||||
|
|
||||||
std::string fullCollectionName() const;
|
|
||||||
/// Returns the <db>.<collection> used for this query.
|
|
||||||
|
|
||||||
Int32 getNumberToSkip() const;
|
|
||||||
/// Returns the number of documents to skip.
|
|
||||||
|
|
||||||
void setNumberToSkip(Int32 n);
|
|
||||||
/// Sets the number of documents to skip.
|
|
||||||
|
|
||||||
Int32 getNumberToReturn() const;
|
|
||||||
/// Returns the number of documents to return.
|
|
||||||
|
|
||||||
void setNumberToReturn(Int32 n);
|
|
||||||
/// Sets the number of documents to return (limit).
|
|
||||||
|
|
||||||
Document& selector();
|
|
||||||
/// Returns the selector document.
|
|
||||||
|
|
||||||
Document& returnFieldSelector();
|
|
||||||
/// Returns the field selector document.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Flags _flags;
|
|
||||||
std::string _fullCollectionName;
|
|
||||||
Int32 _numberToSkip;
|
|
||||||
Int32 _numberToReturn;
|
|
||||||
Document _selector;
|
|
||||||
Document _returnFieldSelector;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline QueryRequest::Flags QueryRequest::getFlags() const
|
|
||||||
{
|
|
||||||
return _flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void QueryRequest::setFlags(QueryRequest::Flags flags)
|
|
||||||
{
|
|
||||||
_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::string QueryRequest::fullCollectionName() const
|
|
||||||
{
|
|
||||||
return _fullCollectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document& QueryRequest::selector()
|
|
||||||
{
|
|
||||||
return _selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document& QueryRequest::returnFieldSelector()
|
|
||||||
{
|
|
||||||
return _returnFieldSelector;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Int32 QueryRequest::getNumberToSkip() const
|
|
||||||
{
|
|
||||||
return _numberToSkip;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void QueryRequest::setNumberToSkip(Int32 n)
|
|
||||||
{
|
|
||||||
_numberToSkip = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Int32 QueryRequest::getNumberToReturn() const
|
|
||||||
{
|
|
||||||
return _numberToReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void QueryRequest::setNumberToReturn(Int32 n)
|
|
||||||
{
|
|
||||||
_numberToReturn = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_QueryRequest_INCLUDED
|
|
||||||
@@ -39,24 +39,45 @@ public:
|
|||||||
RegularExpression(const std::string& pattern, const std::string& options);
|
RegularExpression(const std::string& pattern, const std::string& options);
|
||||||
/// Creates a RegularExpression using the given pattern and options.
|
/// Creates a RegularExpression using the given pattern and options.
|
||||||
|
|
||||||
|
RegularExpression(std::string&& pattern, std::string&& options);
|
||||||
|
/// Creates a RegularExpression using the given pattern and options (move semantics).
|
||||||
|
|
||||||
|
RegularExpression(const RegularExpression& copy) = default;
|
||||||
|
/// Creates a RegularExpression by copying another one.
|
||||||
|
|
||||||
|
RegularExpression(RegularExpression&& other) noexcept = default;
|
||||||
|
/// Creates a RegularExpression by moving another one.
|
||||||
|
|
||||||
|
RegularExpression& operator=(const RegularExpression& copy) = default;
|
||||||
|
/// Assigns another RegularExpression.
|
||||||
|
|
||||||
|
RegularExpression& operator=(RegularExpression&& other) noexcept = default;
|
||||||
|
/// Move-assigns another RegularExpression.
|
||||||
|
|
||||||
virtual ~RegularExpression();
|
virtual ~RegularExpression();
|
||||||
/// Destroys the RegularExpression.
|
/// Destroys the RegularExpression.
|
||||||
|
|
||||||
SharedPtr<Poco::RegularExpression> createRE() const;
|
[[nodiscard]] SharedPtr<Poco::RegularExpression> createRE() const;
|
||||||
/// Tries to create a Poco::RegularExpression from the MongoDB regular expression.
|
/// Tries to create a Poco::RegularExpression from the MongoDB regular expression.
|
||||||
|
|
||||||
std::string getOptions() const;
|
[[nodiscard]] const std::string& getOptions() const noexcept;
|
||||||
/// Returns the options string.
|
/// Returns the options string.
|
||||||
|
|
||||||
void setOptions(const std::string& options);
|
void setOptions(const std::string& options);
|
||||||
/// Sets the options string.
|
/// Sets the options string.
|
||||||
|
|
||||||
std::string getPattern() const;
|
void setOptions(std::string&& options) noexcept;
|
||||||
|
/// Sets the options string (move semantics).
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& getPattern() const noexcept;
|
||||||
/// Returns the pattern.
|
/// Returns the pattern.
|
||||||
|
|
||||||
void setPattern(const std::string& pattern);
|
void setPattern(const std::string& pattern);
|
||||||
/// Sets the pattern.
|
/// Sets the pattern.
|
||||||
|
|
||||||
|
void setPattern(std::string&& pattern) noexcept;
|
||||||
|
/// Sets the pattern (move semantics).
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _pattern;
|
std::string _pattern;
|
||||||
std::string _options;
|
std::string _options;
|
||||||
@@ -66,7 +87,7 @@ private:
|
|||||||
///
|
///
|
||||||
/// inlines
|
/// inlines
|
||||||
///
|
///
|
||||||
inline std::string RegularExpression::getPattern() const
|
inline const std::string& RegularExpression::getPattern() const noexcept
|
||||||
{
|
{
|
||||||
return _pattern;
|
return _pattern;
|
||||||
}
|
}
|
||||||
@@ -78,7 +99,13 @@ inline void RegularExpression::setPattern(const std::string& pattern)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::string RegularExpression::getOptions() const
|
inline void RegularExpression::setPattern(std::string&& pattern) noexcept
|
||||||
|
{
|
||||||
|
_pattern = std::move(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string& RegularExpression::getOptions() const noexcept
|
||||||
{
|
{
|
||||||
return _options;
|
return _options;
|
||||||
}
|
}
|
||||||
@@ -90,6 +117,12 @@ inline void RegularExpression::setOptions(const std::string& options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void RegularExpression::setOptions(std::string&& options) noexcept
|
||||||
|
{
|
||||||
|
_options = std::move(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// BSON Regex
|
// BSON Regex
|
||||||
// spec: cstring cstring
|
// spec: cstring cstring
|
||||||
template<>
|
template<>
|
||||||
@@ -99,8 +132,19 @@ struct ElementTraits<RegularExpression::Ptr>
|
|||||||
|
|
||||||
static std::string toString(const RegularExpression::Ptr& value, int indent = 0)
|
static std::string toString(const RegularExpression::Ptr& value, int indent = 0)
|
||||||
{
|
{
|
||||||
//TODO
|
if (value.isNull())
|
||||||
return "RE: not implemented yet";
|
{
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format as /pattern/options similar to MongoDB shell
|
||||||
|
std::string result;
|
||||||
|
result.reserve(value->getPattern().size() + value->getOptions().size() + 3);
|
||||||
|
result += '/';
|
||||||
|
result += value->getPattern();
|
||||||
|
result += '/';
|
||||||
|
result += value->getOptions();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
virtual ~ReplicaSet();
|
virtual ~ReplicaSet();
|
||||||
/// Destroys the ReplicaSet.
|
/// Destroys the ReplicaSet.
|
||||||
|
|
||||||
Connection::Ptr findMaster();
|
[[nodiscard]] Connection::Ptr findMaster();
|
||||||
/// Tries to find the master MongoDB instance from the addresses
|
/// Tries to find the master MongoDB instance from the addresses
|
||||||
/// passed to the constructor.
|
/// passed to the constructor.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
//
|
|
||||||
// RequestMessage.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: RequestMessage
|
|
||||||
//
|
|
||||||
// Definition of the RequestMessage class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_RequestMessage_INCLUDED
|
|
||||||
#define MongoDB_RequestMessage_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/Message.h"
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class [[deprecated]] RequestMessage;
|
|
||||||
class RequestMessage;
|
|
||||||
|
|
||||||
class MongoDB_API RequestMessage: public Message
|
|
||||||
/// Base class for a request sent to the MongoDB server.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit RequestMessage(MessageHeader::OpCode opcode);
|
|
||||||
/// Creates a RequestMessage using the given opcode.
|
|
||||||
|
|
||||||
virtual ~RequestMessage();
|
|
||||||
/// Destroys the RequestMessage.
|
|
||||||
|
|
||||||
void send(std::ostream& ostr);
|
|
||||||
/// Writes the request to stream.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void buildRequest(BinaryWriter& ss) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_RequestMessage_INCLUDED
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
//
|
|
||||||
// ResponseMessage.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: ResponseMessage
|
|
||||||
//
|
|
||||||
// Definition of the ResponseMessage class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_ResponseMessage_INCLUDED
|
|
||||||
#define MongoDB_ResponseMessage_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/Message.h"
|
|
||||||
#include "Poco/MongoDB/Document.h"
|
|
||||||
#include <istream>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class [[deprecated]] ResponseMessage;
|
|
||||||
class ResponseMessage;
|
|
||||||
|
|
||||||
class MongoDB_API ResponseMessage: public Message
|
|
||||||
/// This class represents a response (OP_REPLY) from MongoDB.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ResponseMessage();
|
|
||||||
/// Creates an empty ResponseMessage.
|
|
||||||
|
|
||||||
ResponseMessage(const Int64& cursorID);
|
|
||||||
/// Creates an ResponseMessage for existing cursor ID.
|
|
||||||
|
|
||||||
virtual ~ResponseMessage();
|
|
||||||
/// Destroys the ResponseMessage.
|
|
||||||
|
|
||||||
Int64 cursorID() const;
|
|
||||||
/// Returns the cursor ID.
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
/// Clears the response.
|
|
||||||
|
|
||||||
std::size_t count() const;
|
|
||||||
/// Returns the number of documents in the response.
|
|
||||||
|
|
||||||
Document::Vector& documents();
|
|
||||||
/// Returns a vector containing the received documents.
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
/// Returns true if the response does not contain any documents.
|
|
||||||
|
|
||||||
bool hasDocuments() const;
|
|
||||||
/// Returns true if there is at least one document in the response.
|
|
||||||
|
|
||||||
void read(std::istream& istr);
|
|
||||||
/// Reads the response from the stream.
|
|
||||||
|
|
||||||
private:
|
|
||||||
Int32 _responseFlags;
|
|
||||||
Int64 _cursorID;
|
|
||||||
Int32 _startingFrom;
|
|
||||||
Int32 _numberReturned;
|
|
||||||
Document::Vector _documents;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline std::size_t ResponseMessage::count() const
|
|
||||||
{
|
|
||||||
return _documents.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ResponseMessage::empty() const
|
|
||||||
{
|
|
||||||
return _documents.size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Int64 ResponseMessage::cursorID() const
|
|
||||||
{
|
|
||||||
return _cursorID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document::Vector& ResponseMessage::documents()
|
|
||||||
{
|
|
||||||
return _documents;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ResponseMessage::hasDocuments() const
|
|
||||||
{
|
|
||||||
return _documents.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_ResponseMessage_INCLUDED
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
//
|
|
||||||
// UpdateRequest.h
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: UpdateRequest
|
|
||||||
//
|
|
||||||
// Definition of the UpdateRequest class.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MongoDB_UpdateRequest_INCLUDED
|
|
||||||
#define MongoDB_UpdateRequest_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/MongoDB.h"
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/MongoDB/Document.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
//class POCO_DEPRECATED("Use new wire protocol") UpdateRequest;
|
|
||||||
|
|
||||||
class MongoDB_API UpdateRequest: public RequestMessage
|
|
||||||
/// This request is used to update a document in a database
|
|
||||||
/// using the OP_UPDATE client request.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
UPDATE_DEFAULT = 0,
|
|
||||||
/// If set, the database will insert the supplied object into the
|
|
||||||
/// collection if no matching document is found.
|
|
||||||
|
|
||||||
UPDATE_UPSERT = 1,
|
|
||||||
/// If set, the database will update all matching objects in the collection.
|
|
||||||
/// Otherwise only updates first matching doc.
|
|
||||||
|
|
||||||
UPDATE_MULTIUPDATE = 2
|
|
||||||
/// If set to, updates multiple documents that meet the query criteria.
|
|
||||||
/// Otherwise only updates one document.
|
|
||||||
};
|
|
||||||
|
|
||||||
UpdateRequest(const std::string& collectionName, Flags flags = UPDATE_DEFAULT);
|
|
||||||
/// Creates the UpdateRequest.
|
|
||||||
///
|
|
||||||
/// The full collection name is the concatenation of the database
|
|
||||||
/// name with the collection name, using a "." for the concatenation. For example,
|
|
||||||
/// for the database "foo" and the collection "bar", the full collection name is
|
|
||||||
/// "foo.bar".
|
|
||||||
|
|
||||||
virtual ~UpdateRequest();
|
|
||||||
/// Destroys the UpdateRequest.
|
|
||||||
|
|
||||||
Document& selector();
|
|
||||||
/// Returns the selector document.
|
|
||||||
|
|
||||||
Document& update();
|
|
||||||
/// Returns the document to update.
|
|
||||||
|
|
||||||
Flags flags() const;
|
|
||||||
/// Returns the flags
|
|
||||||
|
|
||||||
void flags(Flags flags);
|
|
||||||
/// Sets the flags
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildRequest(BinaryWriter& writer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Flags _flags;
|
|
||||||
std::string _fullCollectionName;
|
|
||||||
Document _selector;
|
|
||||||
Document _update;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline UpdateRequest::Flags UpdateRequest::flags() const
|
|
||||||
{
|
|
||||||
return _flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void UpdateRequest::flags(UpdateRequest::Flags flags)
|
|
||||||
{
|
|
||||||
_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document& UpdateRequest::selector()
|
|
||||||
{
|
|
||||||
return _selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Document& UpdateRequest::update()
|
|
||||||
{
|
|
||||||
return _update;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MongoDB_UpdateRequest_INCLUDED
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// main.cpp
|
// main.cpp
|
||||||
//
|
//
|
||||||
// This sample shows SQL to mongo Shell to C++ examples.
|
// This sample shows SQL to MongoDB Shell to C++ examples using OP_MSG wire protocol.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2013, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2013, Applied Informatics Software Engineering GmbH.
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
#include "Poco/MongoDB/MongoDB.h"
|
#include "Poco/MongoDB/MongoDB.h"
|
||||||
#include "Poco/MongoDB/Connection.h"
|
#include "Poco/MongoDB/Connection.h"
|
||||||
#include "Poco/MongoDB/Database.h"
|
#include "Poco/MongoDB/Database.h"
|
||||||
#include "Poco/MongoDB/Cursor.h"
|
#include "Poco/MongoDB/OpMsgMessage.h"
|
||||||
|
#include "Poco/MongoDB/OpMsgCursor.h"
|
||||||
#include "Poco/MongoDB/Array.h"
|
#include "Poco/MongoDB/Array.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -24,117 +25,119 @@ void sample1(Poco::MongoDB::Connection& connection)
|
|||||||
std::cout << "*** SAMPLE 1 ***" << std::endl;
|
std::cout << "*** SAMPLE 1 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::InsertRequest> insertPlayerRequest = db.createInsertRequest("players");
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_INSERT);
|
||||||
|
|
||||||
// With one insert request, we can add multiple documents
|
// Add multiple documents
|
||||||
insertPlayerRequest->addNewDocument()
|
auto& docs = request->documents();
|
||||||
.add("lastname", "Valdes")
|
|
||||||
.add("firstname", "Victor")
|
|
||||||
.add("birthyear", 1982);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Alves")
|
|
||||||
.add("firstname", "Daniel")
|
|
||||||
.add("birthyear", 1983);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Bartra")
|
|
||||||
.add("firstname", "Marc")
|
|
||||||
.add("birthyear", 1991);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Alba")
|
|
||||||
.add("firstname", "Jordi")
|
|
||||||
.add("birthyear", 1989);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Montoya")
|
|
||||||
.add("firstname", "Martin")
|
|
||||||
.add("birthyear", 1991);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Abidal")
|
|
||||||
.add("firstname", "Eric")
|
|
||||||
.add("birthyear", 1979);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Fontas")
|
|
||||||
.add("firstname", "Andreu")
|
|
||||||
.add("birthyear", 1989);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Messi")
|
|
||||||
.add("firstname", "Lionel")
|
|
||||||
.add("birthyear", 1987);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Puyol")
|
|
||||||
.add("firstname", "Carles")
|
|
||||||
.add("birthyear", 1978);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Piqué")
|
|
||||||
.add("firstname", "Gerard")
|
|
||||||
.add("birthyear", 1987);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Muniesa")
|
|
||||||
.add("firstname", "Marc")
|
|
||||||
.add("birthyear", 1992);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Fabrégas")
|
|
||||||
.add("firstname", "Cesc")
|
|
||||||
.add("birthyear", 1987);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Hernandez")
|
|
||||||
.add("firstname", "Xavi")
|
|
||||||
.add("birthyear", 1980);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Iniesta")
|
|
||||||
.add("firstname", "Andres")
|
|
||||||
.add("birthyear", 1984);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Alcantara")
|
|
||||||
.add("firstname", "Thiago")
|
|
||||||
.add("birthyear", 1991);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Dos Santos")
|
|
||||||
.add("firstname", "Jonathan")
|
|
||||||
.add("birthyear", 1990);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Mascherano")
|
|
||||||
.add("firstname", "Javier")
|
|
||||||
.add("birthyear", 1984);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Busquets")
|
|
||||||
.add("firstname", "Sergio")
|
|
||||||
.add("birthyear", 1988);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Adriano")
|
|
||||||
.add("firstname", "")
|
|
||||||
.add("birthyear", 1984);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Song")
|
|
||||||
.add("firstname", "Alex")
|
|
||||||
.add("birthyear", 1987);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Villa")
|
|
||||||
.add("firstname", "David")
|
|
||||||
.add("birthyear", 1981);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Sanchez")
|
|
||||||
.add("firstname", "Alexis")
|
|
||||||
.add("birthyear", 1988);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Pedro")
|
|
||||||
.add("firstname", "")
|
|
||||||
.add("birthyear", 1987);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Cuenca")
|
|
||||||
.add("firstname", "Isaac")
|
|
||||||
.add("birthyear", 1991);
|
|
||||||
insertPlayerRequest->addNewDocument()
|
|
||||||
.add("lastname", "Tello")
|
|
||||||
.add("firstname", "Cristian")
|
|
||||||
.add("birthyear", 1991);
|
|
||||||
|
|
||||||
std::cout << insertPlayerRequest->documents().size() << std::endl;
|
Poco::MongoDB::Document::Ptr doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Valdes").add("firstname", "Victor").add("birthyear", 1982);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
connection.sendRequest(*insertPlayerRequest);
|
doc = new Poco::MongoDB::Document();
|
||||||
std::string lastError = db.getLastError(connection);
|
doc->add("lastname", "Alves").add("firstname", "Daniel").add("birthyear", 1983);
|
||||||
if (!lastError.empty())
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Bartra").add("firstname", "Marc").add("birthyear", 1991);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Alba").add("firstname", "Jordi").add("birthyear", 1989);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Montoya").add("firstname", "Martin").add("birthyear", 1991);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Abidal").add("firstname", "Eric").add("birthyear", 1979);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Fontas").add("firstname", "Andreu").add("birthyear", 1989);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Messi").add("firstname", "Lionel").add("birthyear", 1987);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Puyol").add("firstname", "Carles").add("birthyear", 1978);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Piqué").add("firstname", "Gerard").add("birthyear", 1987);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Muniesa").add("firstname", "Marc").add("birthyear", 1992);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Fabrégas").add("firstname", "Cesc").add("birthyear", 1987);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Hernandez").add("firstname", "Xavi").add("birthyear", 1980);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Iniesta").add("firstname", "Andres").add("birthyear", 1984);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Alcantara").add("firstname", "Thiago").add("birthyear", 1991);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Dos Santos").add("firstname", "Jonathan").add("birthyear", 1990);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Mascherano").add("firstname", "Javier").add("birthyear", 1984);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Busquets").add("firstname", "Sergio").add("birthyear", 1988);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Adriano").add("firstname", "").add("birthyear", 1984);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Song").add("firstname", "Alex").add("birthyear", 1987);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Villa").add("firstname", "David").add("birthyear", 1981);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Sanchez").add("firstname", "Alexis").add("birthyear", 1988);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Pedro").add("firstname", "").add("birthyear", 1987);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Cuenca").add("firstname", "Isaac").add("birthyear", 1991);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
doc = new Poco::MongoDB::Document();
|
||||||
|
doc->add("lastname", "Tello").add("firstname", "Cristian").add("birthyear", 1991);
|
||||||
|
docs.push_back(doc);
|
||||||
|
|
||||||
|
std::cout << request->documents().size() << std::endl;
|
||||||
|
|
||||||
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
|
connection.sendRequest(*request, response);
|
||||||
|
if (!response.responseOk())
|
||||||
{
|
{
|
||||||
std::cout << "Last Error: " << db.getLastError(connection) << std::endl;
|
std::cout << "Error: " << response.body().toString(2) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,26 +147,20 @@ void sample2(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 2 ***" << std::endl;
|
std::cout << "*** SAMPLE 2 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
// Selecting fields is done by adding them to the returnFieldSelector
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
// Use 1 as value of the element.
|
// Selecting fields is done by adding a projection document
|
||||||
cursor.query().returnFieldSelector().add("lastname", 1);
|
cursor.query().body().addNewDocument("projection")
|
||||||
cursor.query().returnFieldSelector().add("birthyear", 1);
|
.add("lastname", 1)
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
.add("birthyear", 1);
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
|
||||||
{
|
|
||||||
std::cout << (*it)->get<std::string>("lastname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
if (response.cursorID() == 0)
|
while (cursor.isActive())
|
||||||
{
|
{
|
||||||
break;
|
for (const auto& doc : response.documents())
|
||||||
|
{
|
||||||
|
std::cout << doc->get<std::string>("lastname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,24 +171,18 @@ void sample3(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 3 ***" << std::endl;
|
std::cout << "*** SAMPLE 3 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
|
||||||
{
|
|
||||||
std::cout << (*it)->get<std::string>("lastname") << ' ' << (*it)->get<std::string>("firstname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
if (response.cursorID() == 0)
|
while (cursor.isActive())
|
||||||
{
|
{
|
||||||
break;
|
for (const auto& doc : response.documents())
|
||||||
|
{
|
||||||
|
std::cout << doc->get<std::string>("lastname") << ' ' << doc->get<std::string>("firstname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -200,26 +191,19 @@ void sample4(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 4 ***" << std::endl;
|
std::cout << "*** SAMPLE 4 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
cursor.query().selector().add("birthyear", 1978);
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
|
cursor.query().body().addNewDocument("filter").add("birthyear", 1978);
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
for (;;)
|
while (cursor.isActive())
|
||||||
{
|
{
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
for (const auto& doc : response.documents())
|
||||||
{
|
{
|
||||||
std::cout << (*it)->get<std::string>("lastname") << ' ' << (*it)->get<std::string>("firstname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
std::cout << doc->get<std::string>("lastname") << ' ' << doc->get<std::string>("firstname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
|
||||||
if (response.cursorID() == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -228,29 +212,20 @@ void sample5(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 5 ***" << std::endl;
|
std::cout << "*** SAMPLE 5 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
|
cursor.query().body().addNewDocument("filter").add("birthyear", 1987);
|
||||||
|
cursor.query().body().addNewDocument("sort").add("lastname", 1);
|
||||||
|
|
||||||
// When orderby is needed, use 2 separate documents in the query selector
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
cursor.query().selector().addNewDocument("$query").add("birthyear", 1987);
|
while (cursor.isActive())
|
||||||
cursor.query().selector().addNewDocument("$orderby").add("lastname", 1);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
for (const auto& doc : response.documents())
|
||||||
{
|
{
|
||||||
std::cout << (*it)->get<std::string>("lastname") << ' ' << (*it)->get<std::string>("firstname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
std::cout << doc->get<std::string>("lastname") << ' ' << doc->get<std::string>("firstname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
|
||||||
if (response.cursorID() == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -259,29 +234,22 @@ void sample6(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 6 ***" << std::endl;
|
std::cout << "*** SAMPLE 6 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
cursor.query().selector().addNewDocument("birthyear")
|
cursor.query().body().addNewDocument("filter")
|
||||||
|
.addNewDocument("birthyear")
|
||||||
.add("$gt", 1969)
|
.add("$gt", 1969)
|
||||||
.add("$lte", 1980);
|
.add("$lte", 1980);
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
for (;;)
|
while (cursor.isActive())
|
||||||
{
|
{
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
for (const auto& doc : response.documents())
|
||||||
{
|
{
|
||||||
std::cout << (*it)->get<std::string>("lastname") << ' ' << (*it)->get<std::string>("firstname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
std::cout << doc->get<std::string>("lastname") << ' ' << doc->get<std::string>("firstname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
|
||||||
if (response.cursorID() == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -294,20 +262,9 @@ void sample7(Poco::MongoDB::Connection& connection)
|
|||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::MongoDB::Document::Ptr keys = new Poco::MongoDB::Document();
|
Poco::MongoDB::Document::Ptr keys = new Poco::MongoDB::Document();
|
||||||
keys->add("lastname", 1);
|
keys->add("lastname", 1);
|
||||||
Poco::MongoDB::Document::Ptr errorDoc = db.ensureIndex(connection, "players", "lastname", keys);
|
Poco::MongoDB::Document::Ptr resultDoc = db.ensureIndex(connection, "players", "lastname", keys);
|
||||||
|
|
||||||
/* Sample above is the same as the following code:
|
std::cout << resultDoc->toString(2);
|
||||||
Poco::MongoDB::Document::Ptr index = new Poco::MongoDB::Document();
|
|
||||||
index->add("ns", "sample.players");
|
|
||||||
index->add("name", "lastname");
|
|
||||||
index->addNewDocument("key").add("lastname", 1);
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::InsertRequest> insertRequest = db.createInsertRequest("system.indexes");
|
|
||||||
insertRequest->documents().push_back(index);
|
|
||||||
connection.sendRequest(*insertRequest);
|
|
||||||
Poco::MongoDB::Document::Ptr errorDoc = db.getLastErrorDoc(connection);
|
|
||||||
*/
|
|
||||||
std::cout << errorDoc->toString(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,134 +273,132 @@ void sample8(Poco::MongoDB::Connection& connection)
|
|||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 8 ***" << std::endl;
|
std::cout << "*** SAMPLE 8 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("sample", "players");
|
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
|
||||||
cursor.query().setNumberToReturn(10);
|
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
cursor.query().setNumberToSkip(20);
|
cursor.query().body()
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(connection);
|
.add("limit", 10)
|
||||||
for (;;)
|
.add("skip", 20);
|
||||||
{
|
|
||||||
for (Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it)
|
|
||||||
{
|
|
||||||
std::cout << (*it)->get<std::string>("lastname") << ' ' << (*it)->get<std::string>("firstname") << " (" << (*it)->get<int>("birthyear") << ')' << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the cursorID is 0, there are no documents left, so break out ...
|
Poco::MongoDB::OpMsgMessage& response = cursor.next(connection);
|
||||||
if (response.cursorID() == 0)
|
while (cursor.isActive())
|
||||||
{
|
{
|
||||||
break;
|
for (const auto& doc : response.documents())
|
||||||
|
{
|
||||||
|
std::cout << doc->get<std::string>("lastname") << ' ' << doc->get<std::string>("firstname") << " (" << doc->get<int>("birthyear") << ')' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next bunch of documents
|
|
||||||
response = cursor.next(connection);
|
response = cursor.next(connection);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SELECT * FROM players LIMIT 1
|
// SELECT * FROM players LIMIT 1
|
||||||
void sample9(Poco::MongoDB::Connection& connection)
|
void sample9(Poco::MongoDB::Connection& connection)
|
||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 9 ***" << std::endl;
|
std::cout << "*** SAMPLE 9 ***" << std::endl;
|
||||||
|
|
||||||
// QueryRequest can be used directly
|
|
||||||
Poco::MongoDB::QueryRequest query("sample.players");
|
|
||||||
query.setNumberToReturn(1);
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
connection.sendRequest(query, response);
|
|
||||||
if (response.hasDocuments())
|
|
||||||
{
|
|
||||||
std::cout << response.documents()[0]->toString(2) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryRequest can be created using the Database class
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> queryPtr = db.createQueryRequest("players");
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
queryPtr->setNumberToReturn(1);
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
|
||||||
connection.sendRequest(*queryPtr, response);
|
request->body().add("limit", 1);
|
||||||
if (response.hasDocuments())
|
|
||||||
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
|
connection.sendRequest(*request, response);
|
||||||
|
if (!response.documents().empty())
|
||||||
{
|
{
|
||||||
std::cout << response.documents()[0]->toString(2) << std::endl;
|
std::cout << response.documents()[0]->toString(2) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SELECT DISTINCT birthyear FROM players WHERE birthyear > 1980
|
// SELECT DISTINCT birthyear FROM players WHERE birthyear > 1980
|
||||||
void sample10(Poco::MongoDB::Connection& connection)
|
void sample10(Poco::MongoDB::Connection& connection)
|
||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 10 ***" << std::endl;
|
std::cout << "*** SAMPLE 10 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> command = db.createCommand();
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_DISTINCT);
|
||||||
command->selector()
|
request->body()
|
||||||
.add("distinct", "players")
|
|
||||||
.add("key", "birthyear")
|
.add("key", "birthyear")
|
||||||
.addNewDocument("query")
|
.addNewDocument("query")
|
||||||
.addNewDocument("birthyear")
|
.addNewDocument("birthyear")
|
||||||
.add("$gt", 1980);
|
.add("$gt", 1980);
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
connection.sendRequest(*command, response);
|
connection.sendRequest(*request, response);
|
||||||
if (response.hasDocuments())
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
Poco::MongoDB::Array::Ptr values = response.documents()[0]->get<Poco::MongoDB::Array::Ptr>("values");
|
Poco::MongoDB::Array::Ptr values = response.body().get<Poco::MongoDB::Array::Ptr>("values");
|
||||||
for (int i = 0; i < values->size(); ++i )
|
for (std::size_t i = 0; i < values->size(); ++i)
|
||||||
{
|
{
|
||||||
std::cout << values->get<int>(i) << std::endl;
|
std::cout << values->get<int>(i) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SELECT COUNT(*) FROM players WHERE birthyear > 1980
|
// SELECT COUNT(*) FROM players WHERE birthyear > 1980
|
||||||
void sample11(Poco::MongoDB::Connection& connection)
|
void sample11(Poco::MongoDB::Connection& connection)
|
||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 11 ***" << std::endl;
|
std::cout << "*** SAMPLE 11 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> count = db.createCountRequest("players");
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
count->selector().addNewDocument("query")
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_COUNT);
|
||||||
|
request->body()
|
||||||
|
.addNewDocument("query")
|
||||||
.addNewDocument("birthyear")
|
.addNewDocument("birthyear")
|
||||||
.add("$gt", 1980);
|
.add("$gt", 1980);
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
connection.sendRequest(*count, response);
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
if (response.hasDocuments())
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
std::cout << "Count: " << response.documents()[0]->getInteger("n") << std::endl;
|
std::cout << "Count: " << response.body().getInteger("n") << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//UPDATE players SET birthyear = birthyear + 1 WHERE firstname = 'Victor'
|
// UPDATE players SET birthyear = birthyear + 1 WHERE firstname = 'Victor'
|
||||||
void sample12(Poco::MongoDB::Connection& connection)
|
void sample12(Poco::MongoDB::Connection& connection)
|
||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 12 ***" << std::endl;
|
std::cout << "*** SAMPLE 12 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::UpdateRequest> request = db.createUpdateRequest("players");
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
request->selector().add("firstname", "Victor");
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_UPDATE);
|
||||||
|
|
||||||
request->update().addNewDocument("$inc").add("birthyear", 1);
|
Poco::MongoDB::Document::Ptr update = new Poco::MongoDB::Document();
|
||||||
|
update->addNewDocument("q").add("firstname", "Victor");
|
||||||
|
update->addNewDocument("u").addNewDocument("$inc").add("birthyear", 1);
|
||||||
|
request->documents().push_back(update);
|
||||||
|
|
||||||
connection.sendRequest(*request);
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
Poco::MongoDB::Document::Ptr lastError = db.getLastErrorDoc(connection);
|
std::cout << "Response: " << response.body().toString(2) << std::endl;
|
||||||
std::cout << "LastError: " << lastError->toString(2) << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//DELETE players WHERE firstname = 'Victor'
|
// DELETE players WHERE firstname = 'Victor'
|
||||||
void sample13(Poco::MongoDB::Connection& connection)
|
void sample13(Poco::MongoDB::Connection& connection)
|
||||||
{
|
{
|
||||||
std::cout << "*** SAMPLE 13 ***" << std::endl;
|
std::cout << "*** SAMPLE 13 ***" << std::endl;
|
||||||
|
|
||||||
Poco::MongoDB::Database db("sample");
|
Poco::MongoDB::Database db("sample");
|
||||||
Poco::SharedPtr<Poco::MongoDB::DeleteRequest> request = db.createDeleteRequest("players");
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
request->selector().add("firstname", "Victor");
|
request->setCommandName(Poco::MongoDB::OpMsgMessage::CMD_DELETE);
|
||||||
|
|
||||||
connection.sendRequest(*request);
|
Poco::MongoDB::Document::Ptr del = new Poco::MongoDB::Document();
|
||||||
|
del->addNewDocument("q").add("firstname", "Victor");
|
||||||
|
del->add("limit", 0); // 0 = delete all matching
|
||||||
|
request->documents().push_back(del);
|
||||||
|
|
||||||
Poco::MongoDB::Document::Ptr lastError = db.getLastErrorDoc(connection);
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
std::cout << "LastError: " << lastError->toString(2) << std::endl;
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
|
std::cout << "Response: " << response.body().toString(2) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,11 @@ std::string Array::toString(int indent) const
|
|||||||
|
|
||||||
if (indent > 0) oss << std::endl;
|
if (indent > 0) oss << std::endl;
|
||||||
|
|
||||||
for (auto it = _elements.begin(), total = _elements.end(); it != total; ++it)
|
// Use protected accessor instead of direct _elements access to maintain encapsulation
|
||||||
|
const ElementSet& elems = elements();
|
||||||
|
for (auto it = elems.begin(), total = elems.end(); it != total; ++it)
|
||||||
{
|
{
|
||||||
if (it != _elements.begin())
|
if (it != elems.begin())
|
||||||
{
|
{
|
||||||
oss << ",";
|
oss << ",";
|
||||||
if (indent > 0) oss << std::endl;
|
if (indent > 0) oss << std::endl;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Binary::Binary(Poco::Int32 size, unsigned char subtype):
|
|||||||
|
|
||||||
Binary::Binary(const UUID& uuid):
|
Binary::Binary(const UUID& uuid):
|
||||||
_buffer(128 / 8),
|
_buffer(128 / 8),
|
||||||
_subtype(0x04)
|
_subtype(SUBTYPE_UUID)
|
||||||
{
|
{
|
||||||
unsigned char szUUID[16];
|
unsigned char szUUID[16];
|
||||||
uuid.copyTo((char*) szUUID);
|
uuid.copyTo((char*) szUUID);
|
||||||
@@ -69,6 +69,20 @@ Binary::~Binary()
|
|||||||
|
|
||||||
std::string Binary::toString(int indent) const
|
std::string Binary::toString(int indent) const
|
||||||
{
|
{
|
||||||
|
// Special handling for UUID subtype - format like MongoDB tools: UUID("...")
|
||||||
|
if (_subtype == SUBTYPE_UUID && _buffer.size() == 16)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return "UUID(\"" + uuid().toString() + "\")";
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Fall through to Base64 encoding if UUID extraction fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: Base64 encode the binary data
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
Base64Encoder encoder(oss);
|
Base64Encoder encoder(oss);
|
||||||
MemoryInputStream mis((const char*) _buffer.begin(), _buffer.size());
|
MemoryInputStream mis((const char*) _buffer.begin(), _buffer.size());
|
||||||
@@ -80,7 +94,7 @@ std::string Binary::toString(int indent) const
|
|||||||
|
|
||||||
UUID Binary::uuid() const
|
UUID Binary::uuid() const
|
||||||
{
|
{
|
||||||
if (_subtype == 0x04 && _buffer.size() == 16)
|
if (_subtype == SUBTYPE_UUID && _buffer.size() == 16)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
uuid.copyFrom((const char*) _buffer.begin());
|
uuid.copyFrom((const char*) _buffer.begin());
|
||||||
|
|||||||
@@ -216,22 +216,6 @@ void Connection::disconnect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Connection::sendRequest(RequestMessage& request)
|
|
||||||
{
|
|
||||||
Poco::Net::SocketOutputStream sos(_socket);
|
|
||||||
request.send(sos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Connection::sendRequest(RequestMessage& request, ResponseMessage& response)
|
|
||||||
{
|
|
||||||
sendRequest(request);
|
|
||||||
|
|
||||||
Poco::Net::SocketInputStream sis(_socket);
|
|
||||||
response.read(sis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Connection::sendRequest(OpMsgMessage& request, OpMsgMessage& response)
|
void Connection::sendRequest(OpMsgMessage& request, OpMsgMessage& response)
|
||||||
{
|
{
|
||||||
Poco::Net::SocketOutputStream sos(_socket);
|
Poco::Net::SocketOutputStream sos(_socket);
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
//
|
|
||||||
// Cursor.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: Cursor
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/Cursor.h"
|
|
||||||
#include "Poco/MongoDB/GetMoreRequest.h"
|
|
||||||
#include "Poco/MongoDB/KillCursorsRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
Cursor::Cursor(const std::string& db, const std::string& collection, QueryRequest::Flags flags):
|
|
||||||
_query(db + '.' + collection, flags)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Cursor::Cursor(const std::string& fullCollectionName, QueryRequest::Flags flags):
|
|
||||||
_query(fullCollectionName, flags)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Cursor::Cursor(const Document& aggregationResponse) :
|
|
||||||
_query(aggregationResponse.get<Poco::MongoDB::Document::Ptr>("cursor")->get<std::string>("ns")),
|
|
||||||
_response(aggregationResponse.get<Poco::MongoDB::Document::Ptr>("cursor")->get<Int64>("id"))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor::~Cursor()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
poco_assert_dbg(!_response.cursorID());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ResponseMessage& Cursor::next(Connection& connection)
|
|
||||||
{
|
|
||||||
if (_response.cursorID() == 0)
|
|
||||||
{
|
|
||||||
connection.sendRequest(_query, _response);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Poco::MongoDB::GetMoreRequest getMore(_query.fullCollectionName(), _response.cursorID());
|
|
||||||
getMore.setNumberToReturn(_query.getNumberToReturn());
|
|
||||||
_response.clear();
|
|
||||||
connection.sendRequest(getMore, _response);
|
|
||||||
}
|
|
||||||
return _response;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Cursor::kill(Connection& connection)
|
|
||||||
{
|
|
||||||
if (_response.cursorID() != 0)
|
|
||||||
{
|
|
||||||
KillCursorsRequest killRequest;
|
|
||||||
killRequest.cursors().push_back(_response.cursorID());
|
|
||||||
connection.sendRequest(killRequest);
|
|
||||||
}
|
|
||||||
_response.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // Namespace Poco::MongoDB
|
|
||||||
@@ -13,8 +13,9 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/Database.h"
|
#include "Poco/MongoDB/Database.h"
|
||||||
#include "Poco/Base64Encoder.h"
|
#include "Poco/MongoDB/Array.h"
|
||||||
#include "Poco/MongoDB/Binary.h"
|
#include "Poco/MongoDB/Binary.h"
|
||||||
|
#include "Poco/Base64Encoder.h"
|
||||||
#include "Poco/MD5Engine.h"
|
#include "Poco/MD5Engine.h"
|
||||||
#include "Poco/SHA1Engine.h"
|
#include "Poco/SHA1Engine.h"
|
||||||
#include "Poco/PBKDF2Engine.h"
|
#include "Poco/PBKDF2Engine.h"
|
||||||
@@ -35,7 +36,6 @@ namespace Poco {
|
|||||||
namespace MongoDB {
|
namespace MongoDB {
|
||||||
|
|
||||||
|
|
||||||
const std::string Database::AUTH_MONGODB_CR("MONGODB-CR");
|
|
||||||
const std::string Database::AUTH_SCRAM_SHA1("SCRAM-SHA-1");
|
const std::string Database::AUTH_SCRAM_SHA1("SCRAM-SHA-1");
|
||||||
|
|
||||||
|
|
||||||
@@ -44,17 +44,24 @@ namespace
|
|||||||
std::map<std::string, std::string> parseKeyValueList(const std::string& str)
|
std::map<std::string, std::string> parseKeyValueList(const std::string& str)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> kvm;
|
std::map<std::string, std::string> kvm;
|
||||||
std::string::const_iterator it = str.begin();
|
std::string::size_type pos = 0;
|
||||||
std::string::const_iterator end = str.end();
|
while (pos < str.size())
|
||||||
while (it != end)
|
|
||||||
{
|
{
|
||||||
std::string k;
|
// Find key-value separators using find() instead of character-by-character iteration
|
||||||
std::string v;
|
std::string::size_type eqPos = str.find('=', pos);
|
||||||
while (it != end && *it != '=') k += *it++;
|
if (eqPos == std::string::npos)
|
||||||
if (it != end) ++it;
|
break;
|
||||||
while (it != end && *it != ',') v += *it++;
|
|
||||||
if (it != end) ++it;
|
std::string::size_type commaPos = str.find(',', eqPos);
|
||||||
kvm[k] = v;
|
if (commaPos == std::string::npos)
|
||||||
|
commaPos = str.length();
|
||||||
|
|
||||||
|
// Extract key and value using substr (single allocation each)
|
||||||
|
std::string key = str.substr(pos, eqPos - pos);
|
||||||
|
std::string value = str.substr(eqPos + 1, commaPos - eqPos - 1);
|
||||||
|
|
||||||
|
kvm[std::move(key)] = std::move(value);
|
||||||
|
pos = commaPos + 1;
|
||||||
}
|
}
|
||||||
return kvm;
|
return kvm;
|
||||||
}
|
}
|
||||||
@@ -135,93 +142,40 @@ bool Database::authenticate(Connection& connection, const std::string& username,
|
|||||||
if (username.empty()) throw Poco::InvalidArgumentException("empty username");
|
if (username.empty()) throw Poco::InvalidArgumentException("empty username");
|
||||||
if (password.empty()) throw Poco::InvalidArgumentException("empty password");
|
if (password.empty()) throw Poco::InvalidArgumentException("empty password");
|
||||||
|
|
||||||
if (method == AUTH_MONGODB_CR)
|
if (method == AUTH_SCRAM_SHA1)
|
||||||
return authCR(connection, username, password);
|
|
||||||
else if (method == AUTH_SCRAM_SHA1)
|
|
||||||
return authSCRAM(connection, username, password);
|
return authSCRAM(connection, username, password);
|
||||||
else
|
else
|
||||||
throw Poco::InvalidArgumentException("authentication method", method);
|
throw Poco::InvalidArgumentException("authentication method", method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Database::authCR(Connection& connection, const std::string& username, const std::string& password)
|
|
||||||
{
|
|
||||||
std::string nonce;
|
|
||||||
Poco::SharedPtr<QueryRequest> pCommand = createCommand();
|
|
||||||
pCommand->selector().add<Poco::Int32>("getnonce", 1);
|
|
||||||
|
|
||||||
ResponseMessage response;
|
|
||||||
connection.sendRequest(*pCommand, response);
|
|
||||||
if (response.documents().empty())
|
|
||||||
{
|
|
||||||
throw Poco::ProtocolException("empty response for getnonce");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Document::Ptr pDoc = response.documents()[0];
|
|
||||||
if (pDoc->getInteger("ok") != 1) return false;
|
|
||||||
nonce = pDoc->get<std::string>("nonce", "");
|
|
||||||
if (nonce.empty()) throw Poco::ProtocolException("no nonce received");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string credsDigest = hashCredentials(username, password);
|
|
||||||
|
|
||||||
Poco::MD5Engine md5;
|
|
||||||
md5.update(nonce);
|
|
||||||
md5.update(username);
|
|
||||||
md5.update(credsDigest);
|
|
||||||
std::string key = digestToHexString(md5);
|
|
||||||
|
|
||||||
pCommand = createCommand();
|
|
||||||
pCommand->selector()
|
|
||||||
.add<Poco::Int32>("authenticate", 1)
|
|
||||||
.add<std::string>("user", username)
|
|
||||||
.add<std::string>("nonce", nonce)
|
|
||||||
.add<std::string>("key", key);
|
|
||||||
|
|
||||||
connection.sendRequest(*pCommand, response);
|
|
||||||
if (!response.documents().empty())
|
|
||||||
{
|
|
||||||
Document::Ptr pDoc = response.documents()[0];
|
|
||||||
return pDoc->getInteger("ok") == 1;
|
|
||||||
}
|
|
||||||
throw Poco::ProtocolException("empty response for authenticate");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Database::authSCRAM(Connection& connection, const std::string& username, const std::string& password)
|
bool Database::authSCRAM(Connection& connection, const std::string& username, const std::string& password)
|
||||||
{
|
{
|
||||||
std::string clientNonce(createNonce());
|
std::string clientNonce(createNonce());
|
||||||
std::string clientFirstMsg = Poco::format("n=%s,r=%s", username, clientNonce);
|
std::string clientFirstMsg = Poco::format("n=%s,r=%s", username, clientNonce);
|
||||||
|
|
||||||
Poco::SharedPtr<QueryRequest> pCommand = createCommand();
|
Poco::SharedPtr<OpMsgMessage> pCommand = createOpMsgMessage("$cmd");
|
||||||
pCommand->selector()
|
pCommand->setCommandName("saslStart");
|
||||||
.add<Poco::Int32>("saslStart", 1)
|
pCommand->body()
|
||||||
.add<std::string>("mechanism", AUTH_SCRAM_SHA1)
|
.add<std::string>("mechanism", AUTH_SCRAM_SHA1)
|
||||||
.add<Binary::Ptr>("payload", new Binary(Poco::format("n,,%s", clientFirstMsg)))
|
.add<Binary::Ptr>("payload", new Binary(Poco::format("n,,%s", clientFirstMsg)))
|
||||||
.add<bool>("autoAuthorize", true);
|
.add<bool>("autoAuthorize", true);
|
||||||
|
|
||||||
ResponseMessage response;
|
OpMsgMessage response;
|
||||||
connection.sendRequest(*pCommand, response);
|
connection.sendRequest(*pCommand, response);
|
||||||
|
|
||||||
Int32 conversationId = 0;
|
Int32 conversationId = 0;
|
||||||
std::string serverFirstMsg;
|
std::string serverFirstMsg;
|
||||||
|
|
||||||
if (response.documents().empty())
|
if (!response.responseOk())
|
||||||
{
|
|
||||||
throw Poco::ProtocolException("empty response for saslStart");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Document::Ptr pDoc = response.documents()[0];
|
|
||||||
if (pDoc->getInteger("ok") == 1)
|
|
||||||
{
|
|
||||||
Binary::Ptr pPayload = pDoc->get<Binary::Ptr>("payload");
|
|
||||||
serverFirstMsg = pPayload->toRawString();
|
|
||||||
conversationId = pDoc->get<Int32>("conversationId");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Document::Ptr pDoc = new Document(response.body());
|
||||||
|
Binary::Ptr pPayload = pDoc->get<Binary::Ptr>("payload");
|
||||||
|
serverFirstMsg = pPayload->toRawString();
|
||||||
|
conversationId = pDoc->get<Int32>("conversationId");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> kvm = parseKeyValueList(serverFirstMsg);
|
std::map<std::string, std::string> kvm = parseKeyValueList(serverFirstMsg);
|
||||||
@@ -259,29 +213,23 @@ bool Database::authSCRAM(Connection& connection, const std::string& username, co
|
|||||||
|
|
||||||
std::string clientFinal = Poco::format("%s,p=%s", clientFinalNoProof, encodeBase64(clientProof));
|
std::string clientFinal = Poco::format("%s,p=%s", clientFinalNoProof, encodeBase64(clientProof));
|
||||||
|
|
||||||
pCommand = createCommand();
|
pCommand = createOpMsgMessage("$cmd");
|
||||||
pCommand->selector()
|
pCommand->setCommandName("saslContinue");
|
||||||
.add<Poco::Int32>("saslContinue", 1)
|
pCommand->body()
|
||||||
.add<Poco::Int32>("conversationId", conversationId)
|
.add<Poco::Int32>("conversationId", conversationId)
|
||||||
.add<Binary::Ptr>("payload", new Binary(clientFinal));
|
.add<Binary::Ptr>("payload", new Binary(clientFinal));
|
||||||
|
|
||||||
std::string serverSecondMsg;
|
std::string serverSecondMsg;
|
||||||
connection.sendRequest(*pCommand, response);
|
connection.sendRequest(*pCommand, response);
|
||||||
if (response.documents().empty())
|
|
||||||
{
|
if (!response.responseOk())
|
||||||
throw Poco::ProtocolException("empty response for saslContinue");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Document::Ptr pDoc = response.documents()[0];
|
|
||||||
if (pDoc->getInteger("ok") == 1)
|
|
||||||
{
|
|
||||||
Binary::Ptr pPayload = pDoc->get<Binary::Ptr>("payload");
|
|
||||||
serverSecondMsg = pPayload->toRawString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Document::Ptr pDoc = new Document(response.body());
|
||||||
|
Binary::Ptr pPayload = pDoc->get<Binary::Ptr>("payload");
|
||||||
|
serverSecondMsg = pPayload->toRawString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::HMACEngine<Poco::SHA1Engine> hmacSKey(saltedPassword);
|
Poco::HMACEngine<Poco::SHA1Engine> hmacSKey(saltedPassword);
|
||||||
@@ -298,39 +246,33 @@ bool Database::authSCRAM(Connection& connection, const std::string& username, co
|
|||||||
if (serverSignature != serverSignatureReceived)
|
if (serverSignature != serverSignatureReceived)
|
||||||
throw Poco::ProtocolException("server signature verification failed");
|
throw Poco::ProtocolException("server signature verification failed");
|
||||||
|
|
||||||
pCommand = createCommand();
|
pCommand = createOpMsgMessage("$cmd");
|
||||||
pCommand->selector()
|
pCommand->setCommandName("saslContinue");
|
||||||
.add<Poco::Int32>("saslContinue", 1)
|
pCommand->body()
|
||||||
.add<Poco::Int32>("conversationId", conversationId)
|
.add<Poco::Int32>("conversationId", conversationId)
|
||||||
.add<Binary::Ptr>("payload", new Binary);
|
.add<Binary::Ptr>("payload", new Binary);
|
||||||
|
|
||||||
connection.sendRequest(*pCommand, response);
|
connection.sendRequest(*pCommand, response);
|
||||||
if (!response.documents().empty())
|
return response.responseOk();
|
||||||
{
|
|
||||||
Document::Ptr pDoc = response.documents()[0];
|
|
||||||
return pDoc->getInteger("ok") == 1;
|
|
||||||
}
|
|
||||||
throw Poco::ProtocolException("empty response for saslContinue");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Document::Ptr Database::queryBuildInfo(Connection& connection) const
|
Document::Ptr Database::queryBuildInfo(Connection& connection) const
|
||||||
{
|
{
|
||||||
// build info can be issued on "config" system database
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = createOpMsgMessage();
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = createCommand();
|
request->setCommandName(OpMsgMessage::CMD_BUILD_INFO);
|
||||||
request->selector().add("buildInfo", 1);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
connection.sendRequest(*request, response);
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
Document::Ptr buildInfo;
|
Document::Ptr buildInfo;
|
||||||
if ( !response.documents().empty() )
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
buildInfo = response.documents()[0];
|
buildInfo = new Document(response.body());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw Poco::ProtocolException("Didn't get a response from the buildinfo command");
|
throw Poco::ProtocolException("Didn't get a response from the buildInfo command");
|
||||||
}
|
}
|
||||||
return buildInfo;
|
return buildInfo;
|
||||||
}
|
}
|
||||||
@@ -338,17 +280,16 @@ Document::Ptr Database::queryBuildInfo(Connection& connection) const
|
|||||||
|
|
||||||
Document::Ptr Database::queryServerHello(Connection& connection) const
|
Document::Ptr Database::queryServerHello(Connection& connection) const
|
||||||
{
|
{
|
||||||
// hello can be issued on "config" system database
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = createOpMsgMessage();
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = createCommand();
|
request->setCommandName(OpMsgMessage::CMD_HELLO);
|
||||||
request->selector().add("hello", 1);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
connection.sendRequest(*request, response);
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
Document::Ptr hello;
|
Document::Ptr hello;
|
||||||
if ( response.documents().size() > 0 )
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
hello = response.documents()[0];
|
hello = new Document(response.body());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -360,94 +301,77 @@ Document::Ptr Database::queryServerHello(Connection& connection) const
|
|||||||
|
|
||||||
Int64 Database::count(Connection& connection, const std::string& collectionName) const
|
Int64 Database::count(Connection& connection, const std::string& collectionName) const
|
||||||
{
|
{
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> countRequest = createCountRequest(collectionName);
|
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = createOpMsgMessage(collectionName);
|
||||||
|
request->setCommandName(OpMsgMessage::CMD_COUNT);
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
Poco::MongoDB::OpMsgMessage response;
|
||||||
connection.sendRequest(*countRequest, response);
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
if (!response.documents().empty())
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
const auto& body = response.body();
|
||||||
return doc->getInteger("n");
|
return body.getInteger("n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Poco::MongoDB::Document::Ptr Database::ensureIndex(Connection& connection, const std::string& collection, const std::string& indexName, Poco::MongoDB::Document::Ptr keys, bool unique, bool background, int version, int ttl)
|
Poco::MongoDB::Document::Ptr Database::createIndex(
|
||||||
|
Connection& connection,
|
||||||
|
const std::string& collection,
|
||||||
|
const IndexedFields& indexedFields,
|
||||||
|
const std::string &indexName,
|
||||||
|
unsigned long options,
|
||||||
|
int expirationSeconds,
|
||||||
|
int version)
|
||||||
{
|
{
|
||||||
Poco::MongoDB::Document::Ptr index = new Poco::MongoDB::Document();
|
// https://www.mongodb.com/docs/manual/reference/command/createIndexes/
|
||||||
|
|
||||||
|
MongoDB::Document::Ptr keys = new MongoDB::Document();
|
||||||
|
|
||||||
|
for (const auto& [name, ascending]: indexedFields) {
|
||||||
|
keys->add(name, ascending ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoDB::Document::Ptr index = new MongoDB::Document();
|
||||||
|
if (!indexName.empty())
|
||||||
|
{
|
||||||
|
index->add("name", indexName);
|
||||||
|
}
|
||||||
|
index->add("key", keys);
|
||||||
index->add("ns", _dbname + "." + collection);
|
index->add("ns", _dbname + "." + collection);
|
||||||
index->add("name", indexName);
|
index->add("name", indexName);
|
||||||
index->add("key", keys);
|
|
||||||
|
|
||||||
if (version > 0)
|
if (options & INDEX_UNIQUE) {
|
||||||
{
|
|
||||||
index->add("version", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unique)
|
|
||||||
{
|
|
||||||
index->add("unique", true);
|
index->add("unique", true);
|
||||||
}
|
}
|
||||||
|
if (options & INDEX_BACKGROUND) {
|
||||||
if (background)
|
|
||||||
{
|
|
||||||
index->add("background", true);
|
index->add("background", true);
|
||||||
}
|
}
|
||||||
|
if (options & INDEX_SPARSE) {
|
||||||
if (ttl > 0)
|
index->add("sparse", true);
|
||||||
{
|
}
|
||||||
index->add("expireAfterSeconds", ttl);
|
if (expirationSeconds > 0) {
|
||||||
|
index->add("expireAfterSeconds", static_cast<Poco::Int32>(expirationSeconds));
|
||||||
|
}
|
||||||
|
if (version > 0) {
|
||||||
|
index->add("version", static_cast<Poco::Int32>(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::InsertRequest> insertRequest = createInsertRequest("system.indexes");
|
MongoDB::Array::Ptr indexes = new MongoDB::Array();
|
||||||
insertRequest->documents().push_back(index);
|
indexes->add(index);
|
||||||
connection.sendRequest(*insertRequest);
|
|
||||||
|
|
||||||
return getLastErrorDoc(connection);
|
auto request = createOpMsgMessage(collection);
|
||||||
}
|
request->setCommandName(OpMsgMessage::CMD_CREATE_INDEXES);
|
||||||
|
request->body().add("indexes", indexes);
|
||||||
|
|
||||||
|
OpMsgMessage response;
|
||||||
Document::Ptr Database::getLastErrorDoc(Connection& connection) const
|
|
||||||
{
|
|
||||||
Document::Ptr errorDoc;
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = createCommand();
|
|
||||||
request->setNumberToReturn(1);
|
|
||||||
request->selector().add("getLastError", 1);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
connection.sendRequest(*request, response);
|
connection.sendRequest(*request, response);
|
||||||
|
|
||||||
if (!response.documents().empty())
|
MongoDB::Document::Ptr result = new MongoDB::Document(response.body());
|
||||||
{
|
|
||||||
errorDoc = response.documents()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorDoc;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string Database::getLastError(Connection& connection) const
|
|
||||||
{
|
|
||||||
Document::Ptr errorDoc = getLastErrorDoc(connection);
|
|
||||||
if (!errorDoc.isNull() && errorDoc->isType<std::string>("err"))
|
|
||||||
{
|
|
||||||
return errorDoc->get<std::string>("err");
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> Database::createCountRequest(const std::string& collectionName) const
|
|
||||||
{
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = createCommand();
|
|
||||||
request->setNumberToReturn(1);
|
|
||||||
request->selector().add("count", collectionName);
|
|
||||||
return request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
//
|
|
||||||
// DeleteRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: DeleteRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/DeleteRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
DeleteRequest::DeleteRequest(const std::string& collectionName, DeleteRequest::Flags flags):
|
|
||||||
RequestMessage(MessageHeader::OP_DELETE),
|
|
||||||
_flags(flags),
|
|
||||||
_fullCollectionName(collectionName),
|
|
||||||
_selector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DeleteRequest::DeleteRequest(const std::string& collectionName, bool justOne):
|
|
||||||
RequestMessage(MessageHeader::OP_DELETE),
|
|
||||||
_flags(justOne ? DELETE_SINGLE_REMOVE : DELETE_DEFAULT),
|
|
||||||
_fullCollectionName(collectionName),
|
|
||||||
_selector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DeleteRequest::~DeleteRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DeleteRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
writer << 0; // 0 - reserved for future use
|
|
||||||
BSONWriter(writer).writeCString(_fullCollectionName);
|
|
||||||
writer << _flags;
|
|
||||||
_selector.write(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -45,15 +45,14 @@ Array& Document::addNewArray(const std::string& name)
|
|||||||
|
|
||||||
Element::Ptr Document::get(const std::string& name) const
|
Element::Ptr Document::get(const std::string& name) const
|
||||||
{
|
{
|
||||||
Element::Ptr element;
|
// O(1) hash map lookup instead of O(n) linear search
|
||||||
|
auto it = _elementMap.find(name);
|
||||||
auto it = std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name));
|
if (it != _elementMap.end())
|
||||||
if (it != _elements.end())
|
|
||||||
{
|
{
|
||||||
return *it;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return element;
|
return Element::Ptr(); // Return empty pointer if not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -64,18 +63,19 @@ Int64 Document::getInteger(const std::string& name) const
|
|||||||
|
|
||||||
if (ElementTraits<double>::TypeId == element->type())
|
if (ElementTraits<double>::TypeId == element->type())
|
||||||
{
|
{
|
||||||
ConcreteElement<double>* concrete = dynamic_cast<ConcreteElement<double>*>(element.get());
|
// Type is already verified, static_cast is safe and ~10x faster than dynamic_cast
|
||||||
if (concrete) return static_cast<Int64>(concrete->value());
|
auto* concrete = static_cast<ConcreteElement<double>*>(element.get());
|
||||||
|
return static_cast<Int64>(concrete->value());
|
||||||
}
|
}
|
||||||
else if (ElementTraits<Int32>::TypeId == element->type())
|
else if (ElementTraits<Int32>::TypeId == element->type())
|
||||||
{
|
{
|
||||||
ConcreteElement<Int32>* concrete = dynamic_cast<ConcreteElement<Int32>*>(element.get());
|
auto* concrete = static_cast<ConcreteElement<Int32>*>(element.get());
|
||||||
if (concrete) return concrete->value();
|
return concrete->value();
|
||||||
}
|
}
|
||||||
else if (ElementTraits<Int64>::TypeId == element->type())
|
else if (ElementTraits<Int64>::TypeId == element->type())
|
||||||
{
|
{
|
||||||
ConcreteElement<Int64>* concrete = dynamic_cast<ConcreteElement<Int64>*>(element.get());
|
auto* concrete = static_cast<ConcreteElement<Int64>*>(element.get());
|
||||||
if (concrete) return concrete->value();
|
return concrete->value();
|
||||||
}
|
}
|
||||||
throw Poco::BadCastException("Invalid type mismatch!");
|
throw Poco::BadCastException("Invalid type mismatch!");
|
||||||
}
|
}
|
||||||
@@ -152,6 +152,7 @@ void Document::read(BinaryReader& reader)
|
|||||||
|
|
||||||
element->read(reader);
|
element->read(reader);
|
||||||
_elements.push_back(element);
|
_elements.push_back(element);
|
||||||
|
_elementMap[element->name()] = element; // Populate hash map for O(1) lookups
|
||||||
|
|
||||||
reader >> type;
|
reader >> type;
|
||||||
}
|
}
|
||||||
@@ -161,12 +162,13 @@ void Document::read(BinaryReader& reader)
|
|||||||
std::string Document::toString(int indent) const
|
std::string Document::toString(int indent) const
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
// Pre-reserve reasonable capacity for small-medium documents to reduce reallocations
|
||||||
|
oss.str().reserve(256);
|
||||||
|
|
||||||
oss << '{';
|
oss << '{';
|
||||||
|
|
||||||
if (indent > 0) oss << std::endl;
|
if (indent > 0) oss << std::endl;
|
||||||
|
|
||||||
|
|
||||||
for (auto it = _elements.begin(), total = _elements.end(); it != total; ++it)
|
for (auto it = _elements.begin(), total = _elements.end(); it != total; ++it)
|
||||||
{
|
{
|
||||||
if (it != _elements.begin())
|
if (it != _elements.begin())
|
||||||
@@ -175,7 +177,11 @@ std::string Document::toString(int indent) const
|
|||||||
if (indent > 0) oss << std::endl;
|
if (indent > 0) oss << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < indent; ++i) oss << ' ';
|
if (indent > 0)
|
||||||
|
{
|
||||||
|
const std::string indentStr(indent, ' ');
|
||||||
|
oss << indentStr;
|
||||||
|
}
|
||||||
|
|
||||||
oss << '"' << (*it)->name() << '"';
|
oss << '"' << (*it)->name() << '"';
|
||||||
oss << (indent > 0 ? " : " : ":");
|
oss << (indent > 0 ? " : " : ":");
|
||||||
@@ -188,7 +194,8 @@ std::string Document::toString(int indent) const
|
|||||||
oss << std::endl;
|
oss << std::endl;
|
||||||
if (indent >= 2) indent -= 2;
|
if (indent >= 2) indent -= 2;
|
||||||
|
|
||||||
for (int i = 0; i < indent; ++i) oss << ' ';
|
const std::string indentStr(indent, ' ');
|
||||||
|
oss << indentStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
oss << '}';
|
oss << '}';
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ Element::Element(const std::string& name) : _name(name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Element::Element(std::string&& name) : _name(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Element::~Element()
|
Element::~Element()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
//
|
|
||||||
// GetMoreRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: GetMoreRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/GetMoreRequest.h"
|
|
||||||
#include "Poco/MongoDB/Element.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
GetMoreRequest::GetMoreRequest(const std::string& collectionName, Int64 cursorID):
|
|
||||||
RequestMessage(MessageHeader::OP_GET_MORE),
|
|
||||||
_fullCollectionName(collectionName),
|
|
||||||
_numberToReturn(100),
|
|
||||||
_cursorID(cursorID)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GetMoreRequest::~GetMoreRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GetMoreRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
writer << 0; // 0 - reserved for future use
|
|
||||||
BSONWriter(writer).writeCString(_fullCollectionName);
|
|
||||||
writer << _numberToReturn;
|
|
||||||
writer << _cursorID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
//
|
|
||||||
// InsertRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: InsertRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/InsertRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
InsertRequest::InsertRequest(const std::string& collectionName, Flags flags):
|
|
||||||
RequestMessage(MessageHeader::OP_INSERT),
|
|
||||||
_flags(flags),
|
|
||||||
_fullCollectionName(collectionName)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
InsertRequest::~InsertRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InsertRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
poco_assert (!_documents.empty());
|
|
||||||
|
|
||||||
writer << _flags;
|
|
||||||
BSONWriter bsonWriter(writer);
|
|
||||||
bsonWriter.writeCString(_fullCollectionName);
|
|
||||||
for (Document::Vector::iterator it = _documents.begin(); it != _documents.end(); ++it)
|
|
||||||
{
|
|
||||||
bsonWriter.write(*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
//
|
|
||||||
// KillCursorsRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: KillCursorsRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/KillCursorsRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
KillCursorsRequest::KillCursorsRequest():
|
|
||||||
RequestMessage(MessageHeader::OP_KILL_CURSORS)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
KillCursorsRequest::~KillCursorsRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void KillCursorsRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
writer << 0; // 0 - reserved for future use
|
|
||||||
writer << static_cast<Poco::UInt64>(_cursors.size());
|
|
||||||
for (std::vector<Int64>::iterator it = _cursors.begin(); it != _cursors.end(); ++it)
|
|
||||||
{
|
|
||||||
writer << *it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -40,12 +40,38 @@ ObjectId::ObjectId(const std::string& id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ObjectId::ObjectId(const ObjectId& copy)
|
ObjectId::ObjectId(const ObjectId& copy) noexcept
|
||||||
{
|
{
|
||||||
std::memcpy(_id, copy._id, sizeof(_id));
|
std::memcpy(_id, copy._id, sizeof(_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ObjectId::ObjectId(ObjectId&& other) noexcept
|
||||||
|
{
|
||||||
|
std::memcpy(_id, other._id, sizeof(_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ObjectId& ObjectId::operator=(const ObjectId& copy) noexcept
|
||||||
|
{
|
||||||
|
if (this != ©)
|
||||||
|
{
|
||||||
|
std::memcpy(_id, copy._id, sizeof(_id));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ObjectId& ObjectId::operator=(ObjectId&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
std::memcpy(_id, other._id, sizeof(_id));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ObjectId::~ObjectId()
|
ObjectId::~ObjectId()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -54,10 +80,11 @@ ObjectId::~ObjectId()
|
|||||||
std::string ObjectId::toString(const std::string& fmt) const
|
std::string ObjectId::toString(const std::string& fmt) const
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
s.reserve(24); // Pre-allocate for 12 bytes * 2 hex chars
|
||||||
|
|
||||||
for (int i = 0; i < 12; ++i)
|
for (std::size_t i = 0; i < 12; ++i)
|
||||||
{
|
{
|
||||||
s += format(fmt, (unsigned int) _id[i]);
|
s += format(fmt, static_cast<unsigned int>(_id[i]));
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ OpMsgCursor::~OpMsgCursor()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
poco_assert_dbg(_cursorID == 0);
|
poco_assert_msg_dbg(_cursorID == 0, "OpMsgCursor destroyed with active cursor - call kill() before destruction");
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -73,31 +73,31 @@ OpMsgCursor::~OpMsgCursor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OpMsgCursor::setEmptyFirstBatch(bool empty)
|
void OpMsgCursor::setEmptyFirstBatch(bool empty) noexcept
|
||||||
{
|
{
|
||||||
_emptyFirstBatch = empty;
|
_emptyFirstBatch = empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OpMsgCursor::emptyFirstBatch() const
|
bool OpMsgCursor::emptyFirstBatch() const noexcept
|
||||||
{
|
{
|
||||||
return _emptyFirstBatch;
|
return _emptyFirstBatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OpMsgCursor::setBatchSize(Int32 batchSize)
|
void OpMsgCursor::setBatchSize(Int32 batchSize) noexcept
|
||||||
{
|
{
|
||||||
_batchSize = batchSize;
|
_batchSize = batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Int32 OpMsgCursor::batchSize() const
|
Int32 OpMsgCursor::batchSize() const noexcept
|
||||||
{
|
{
|
||||||
return _batchSize;
|
return _batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OpMsgCursor::isActive() const
|
bool OpMsgCursor::isActive() const noexcept
|
||||||
{
|
{
|
||||||
const auto& cmd {_query.commandName()};
|
const auto& cmd {_query.commandName()};
|
||||||
return ( _cursorID > 0 || (!cmd.empty() && cmd != OpMsgMessage::CMD_GET_MORE) );
|
return ( _cursorID > 0 || (!cmd.empty() && cmd != OpMsgMessage::CMD_GET_MORE) );
|
||||||
|
|||||||
@@ -242,8 +242,10 @@ void OpMsgMessage::send(std::ostream& ostr)
|
|||||||
|
|
||||||
if (!_documents.empty())
|
if (!_documents.empty())
|
||||||
{
|
{
|
||||||
// Serialise attached documents
|
// Serialise attached documents directly to main stream to avoid extra buffer copy
|
||||||
|
const std::string& identifier = commandIdentifier(_commandName);
|
||||||
|
|
||||||
|
// Write documents to temporary buffer (still needed to calculate size)
|
||||||
std::stringstream ssdoc;
|
std::stringstream ssdoc;
|
||||||
BinaryWriter wdoc(ssdoc, BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
BinaryWriter wdoc(ssdoc, BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
for (auto& doc: _documents)
|
for (auto& doc: _documents)
|
||||||
@@ -252,12 +254,14 @@ void OpMsgMessage::send(std::ostream& ostr)
|
|||||||
}
|
}
|
||||||
wdoc.flush();
|
wdoc.flush();
|
||||||
|
|
||||||
const std::string& identifier = commandIdentifier(_commandName);
|
|
||||||
const Poco::Int32 size = static_cast<Poco::Int32>(sizeof(size) + identifier.size() + 1 + ssdoc.tellp());
|
const Poco::Int32 size = static_cast<Poco::Int32>(sizeof(size) + identifier.size() + 1 + ssdoc.tellp());
|
||||||
writer << PAYLOAD_TYPE_1;
|
writer << PAYLOAD_TYPE_1;
|
||||||
writer << size;
|
writer << size;
|
||||||
writer.writeCString(identifier.c_str());
|
writer.writeCString(identifier.c_str());
|
||||||
StreamCopier::copyStream(ssdoc, ss);
|
|
||||||
|
// Use writeRaw instead of copyStream for better performance
|
||||||
|
const std::string& docData = ssdoc.str();
|
||||||
|
ss.write(docData.data(), docData.size());
|
||||||
}
|
}
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
|
||||||
@@ -271,8 +275,10 @@ void OpMsgMessage::send(std::ostream& ostr)
|
|||||||
messageLength(static_cast<Poco::Int32>(ss.tellp()));
|
messageLength(static_cast<Poco::Int32>(ss.tellp()));
|
||||||
|
|
||||||
_header.write(socketWriter);
|
_header.write(socketWriter);
|
||||||
StreamCopier::copyStream(ss, ostr);
|
|
||||||
|
|
||||||
|
// Write directly instead of using StreamCopier for better performance
|
||||||
|
const std::string& msgData = ss.str();
|
||||||
|
ostr.write(msgData.data(), msgData.size());
|
||||||
ostr.flush();
|
ostr.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +383,9 @@ void OpMsgMessage::read(std::istream& istr)
|
|||||||
}
|
}
|
||||||
if (batch)
|
if (batch)
|
||||||
{
|
{
|
||||||
|
// Reserve space to avoid reallocations
|
||||||
|
_documents.reserve(_documents.size() + batch->size());
|
||||||
|
|
||||||
for(std::size_t i = 0; i < batch->size(); i++)
|
for(std::size_t i = 0; i < batch->size(); i++)
|
||||||
{
|
{
|
||||||
const auto& d = batch->get<MongoDB::Document::Ptr>(i, nullptr);
|
const auto& d = batch->get<MongoDB::Document::Ptr>(i, nullptr);
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
//
|
|
||||||
// QueryRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: QueryRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/QueryRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
QueryRequest::QueryRequest(const std::string& collectionName, QueryRequest::Flags flags):
|
|
||||||
RequestMessage(MessageHeader::OP_QUERY),
|
|
||||||
_flags(flags),
|
|
||||||
_fullCollectionName(collectionName),
|
|
||||||
_numberToSkip(0),
|
|
||||||
_numberToReturn(100),
|
|
||||||
_selector(),
|
|
||||||
_returnFieldSelector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QueryRequest::~QueryRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void QueryRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
writer << _flags;
|
|
||||||
BSONWriter(writer).writeCString(_fullCollectionName);
|
|
||||||
writer << _numberToSkip;
|
|
||||||
writer << _numberToReturn;
|
|
||||||
_selector.write(writer);
|
|
||||||
|
|
||||||
if (!_returnFieldSelector.empty())
|
|
||||||
{
|
|
||||||
_returnFieldSelector.write(writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -32,6 +32,13 @@ RegularExpression::RegularExpression(const std::string& pattern, const std::stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegularExpression::RegularExpression(std::string&& pattern, std::string&& options):
|
||||||
|
_pattern(std::move(pattern)),
|
||||||
|
_options(std::move(options))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RegularExpression::~RegularExpression()
|
RegularExpression::~RegularExpression()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -40,9 +47,9 @@ RegularExpression::~RegularExpression()
|
|||||||
SharedPtr<Poco::RegularExpression> RegularExpression::createRE() const
|
SharedPtr<Poco::RegularExpression> RegularExpression::createRE() const
|
||||||
{
|
{
|
||||||
int options = 0;
|
int options = 0;
|
||||||
for (std::string::const_iterator optIt = _options.begin(); optIt != _options.end(); ++optIt)
|
for (char opt : _options)
|
||||||
{
|
{
|
||||||
switch (*optIt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
case 'i': // Case Insensitive
|
case 'i': // Case Insensitive
|
||||||
options |= Poco::RegularExpression::RE_CASELESS;
|
options |= Poco::RegularExpression::RE_CASELESS;
|
||||||
|
|||||||
@@ -13,8 +13,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/ReplicaSet.h"
|
#include "Poco/MongoDB/ReplicaSet.h"
|
||||||
#include "Poco/MongoDB/QueryRequest.h"
|
#include "Poco/MongoDB/OpMsgMessage.h"
|
||||||
#include "Poco/MongoDB/ResponseMessage.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@@ -57,23 +56,22 @@ Connection::Ptr ReplicaSet::isMaster(const Net::SocketAddress& address)
|
|||||||
{
|
{
|
||||||
conn->connect(address);
|
conn->connect(address);
|
||||||
|
|
||||||
QueryRequest request("admin.$cmd");
|
OpMsgMessage request("admin", "");
|
||||||
request.setNumberToReturn(1);
|
request.setCommandName(OpMsgMessage::CMD_HELLO);
|
||||||
request.selector().add("isMaster", 1);
|
|
||||||
|
|
||||||
ResponseMessage response;
|
OpMsgMessage response;
|
||||||
conn->sendRequest(request, response);
|
conn->sendRequest(request, response);
|
||||||
|
|
||||||
if (response.documents().size() > 0)
|
if (response.responseOk())
|
||||||
{
|
{
|
||||||
Document::Ptr doc = response.documents()[0];
|
const Document& doc = response.body();
|
||||||
if (doc->get<bool>("ismaster"))
|
if (doc.get<bool>("isWritablePrimary", false) || doc.get<bool>("ismaster", false))
|
||||||
{
|
{
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
else if (doc->exists("primary"))
|
else if (doc.exists("primary"))
|
||||||
{
|
{
|
||||||
return isMaster(Net::SocketAddress(doc->get<std::string>("primary")));
|
return isMaster(Net::SocketAddress(doc.get<std::string>("primary")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
//
|
|
||||||
// RequestMessage.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: RequestMessage
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/RequestMessage.h"
|
|
||||||
#include "Poco/Net/SocketStream.h"
|
|
||||||
#include "Poco/StreamCopier.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
RequestMessage::RequestMessage(MessageHeader::OpCode opcode):
|
|
||||||
Message(opcode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RequestMessage::~RequestMessage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RequestMessage::send(std::ostream& ostr)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
BinaryWriter requestWriter(ss, BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
|
||||||
buildRequest(requestWriter);
|
|
||||||
requestWriter.flush();
|
|
||||||
|
|
||||||
messageLength(static_cast<Poco::Int32>(ss.tellp()));
|
|
||||||
|
|
||||||
BinaryWriter socketWriter(ostr, BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
|
||||||
_header.write(socketWriter);
|
|
||||||
StreamCopier::copyStream(ss, ostr);
|
|
||||||
ostr.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// ResponseMessage.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: ResponseMessage
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/ResponseMessage.h"
|
|
||||||
#include "Poco/Net/SocketStream.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
ResponseMessage::ResponseMessage():
|
|
||||||
Message(MessageHeader::OP_REPLY),
|
|
||||||
_responseFlags(0),
|
|
||||||
_cursorID(0),
|
|
||||||
_startingFrom(0),
|
|
||||||
_numberReturned(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ResponseMessage::ResponseMessage(const Int64& cursorID):
|
|
||||||
Message(MessageHeader::OP_REPLY),
|
|
||||||
_responseFlags(0),
|
|
||||||
_cursorID(cursorID),
|
|
||||||
_startingFrom(0),
|
|
||||||
_numberReturned(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ResponseMessage::~ResponseMessage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ResponseMessage::clear()
|
|
||||||
{
|
|
||||||
_responseFlags = 0;
|
|
||||||
_startingFrom = 0;
|
|
||||||
_cursorID = 0;
|
|
||||||
_numberReturned = 0;
|
|
||||||
_documents.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ResponseMessage::read(std::istream& istr)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
BinaryReader reader(istr, BinaryReader::LITTLE_ENDIAN_BYTE_ORDER);
|
|
||||||
|
|
||||||
_header.read(reader);
|
|
||||||
|
|
||||||
reader >> _responseFlags;
|
|
||||||
reader >> _cursorID;
|
|
||||||
reader >> _startingFrom;
|
|
||||||
reader >> _numberReturned;
|
|
||||||
|
|
||||||
for (int i = 0; i < _numberReturned; ++i)
|
|
||||||
{
|
|
||||||
Document::Ptr doc = new Document();
|
|
||||||
doc->read(reader);
|
|
||||||
_documents.push_back(doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
//
|
|
||||||
// UpdateRequest.cpp
|
|
||||||
//
|
|
||||||
// Library: MongoDB
|
|
||||||
// Package: MongoDB
|
|
||||||
// Module: UpdateRequest
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
||||||
// and Contributors.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/MongoDB/UpdateRequest.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace MongoDB {
|
|
||||||
|
|
||||||
|
|
||||||
UpdateRequest::UpdateRequest(const std::string& collectionName, UpdateRequest::Flags flags):
|
|
||||||
RequestMessage(MessageHeader::OP_UPDATE),
|
|
||||||
_flags(flags),
|
|
||||||
_fullCollectionName(collectionName),
|
|
||||||
_selector(),
|
|
||||||
_update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UpdateRequest::~UpdateRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UpdateRequest::buildRequest(BinaryWriter& writer)
|
|
||||||
{
|
|
||||||
writer << 0; // 0 - reserved for future use
|
|
||||||
BSONWriter(writer).writeCString(_fullCollectionName);
|
|
||||||
writer << _flags;
|
|
||||||
_selector.write(writer);
|
|
||||||
_update.write(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::MongoDB
|
|
||||||
@@ -11,14 +11,11 @@
|
|||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
#include "Poco/ObjectPool.h"
|
#include "Poco/ObjectPool.h"
|
||||||
#include "Poco/MongoDB/Array.h"
|
#include "Poco/MongoDB/Array.h"
|
||||||
#include "Poco/MongoDB/InsertRequest.h"
|
|
||||||
#include "Poco/MongoDB/QueryRequest.h"
|
|
||||||
#include "Poco/MongoDB/DeleteRequest.h"
|
|
||||||
#include "Poco/MongoDB/GetMoreRequest.h"
|
|
||||||
#include "Poco/MongoDB/PoolableConnectionFactory.h"
|
#include "Poco/MongoDB/PoolableConnectionFactory.h"
|
||||||
#include "Poco/MongoDB/Database.h"
|
#include "Poco/MongoDB/Database.h"
|
||||||
#include "Poco/MongoDB/Connection.h"
|
#include "Poco/MongoDB/Connection.h"
|
||||||
#include "Poco/MongoDB/Cursor.h"
|
#include "Poco/MongoDB/OpMsgMessage.h"
|
||||||
|
#include "Poco/MongoDB/OpMsgCursor.h"
|
||||||
#include "Poco/MongoDB/ObjectId.h"
|
#include "Poco/MongoDB/ObjectId.h"
|
||||||
#include "Poco/MongoDB/Binary.h"
|
#include "Poco/MongoDB/Binary.h"
|
||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
@@ -57,29 +54,6 @@ void MongoDBTest::tearDown()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testInsertRequest()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr player = new Poco::MongoDB::Document();
|
|
||||||
player->add("lastname", std::string("Braem"));
|
|
||||||
player->add("firstname", std::string("Franky"));
|
|
||||||
|
|
||||||
Poco::DateTime birthdate;
|
|
||||||
birthdate.assign(1969, 3, 9);
|
|
||||||
player->add("birthdate", birthdate.timestamp());
|
|
||||||
|
|
||||||
player->add("start", 1993);
|
|
||||||
player->add("active", false);
|
|
||||||
|
|
||||||
Poco::DateTime now;
|
|
||||||
player->add("lastupdated", now.timestamp());
|
|
||||||
|
|
||||||
player->add("unknown", NullValue());
|
|
||||||
|
|
||||||
Poco::MongoDB::InsertRequest request("team.players");
|
|
||||||
request.documents().push_back(player);
|
|
||||||
_mongo->sendRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MongoDBTest::testArray()
|
void MongoDBTest::testArray()
|
||||||
{
|
{
|
||||||
Poco::MongoDB::Array::Ptr arr = new Poco::MongoDB::Array();
|
Poco::MongoDB::Array::Ptr arr = new Poco::MongoDB::Array();
|
||||||
@@ -117,190 +91,8 @@ void MongoDBTest::testArray()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testQueryRequest()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::QueryRequest request("team.players");
|
|
||||||
request.selector().add("lastname" , std::string("Braem"));
|
|
||||||
request.setNumberToReturn(1);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
|
|
||||||
_mongo->sendRequest(request, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string lastname = doc->get<std::string>("lastname");
|
|
||||||
assertTrue (lastname.compare("Braem") == 0);
|
|
||||||
std::string firstname = doc->get<std::string>("firstname");
|
|
||||||
assertTrue (firstname.compare("Franky") == 0);
|
|
||||||
Poco::Timestamp birthDateTimestamp = doc->get<Poco::Timestamp>("birthdate");
|
|
||||||
Poco::DateTime birthDate(birthDateTimestamp);
|
|
||||||
assertTrue (birthDate.year() == 1969 && birthDate.month() == 3 && birthDate.day() == 9);
|
|
||||||
Poco::Timestamp lastupdatedTimestamp = doc->get<Poco::Timestamp>("lastupdated");
|
|
||||||
assertTrue (doc->isType<NullValue>("unknown"));
|
|
||||||
bool active = doc->get<bool>("active");
|
|
||||||
assertTrue (!active);
|
|
||||||
|
|
||||||
std::string id = doc->get("_id")->toString();
|
|
||||||
}
|
|
||||||
catch(Poco::NotFoundException& nfe)
|
|
||||||
{
|
|
||||||
fail(nfe.message() + " not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("No document returned");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testDBQueryRequest()
|
|
||||||
{
|
|
||||||
Database db("team");
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = db.createQueryRequest("players");
|
|
||||||
request->selector().add("lastname" , std::string("Braem"));
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
_mongo->sendRequest(*request, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string lastname = doc->get<std::string>("lastname");
|
|
||||||
assertTrue (lastname.compare("Braem") == 0);
|
|
||||||
std::string firstname = doc->get<std::string>("firstname");
|
|
||||||
assertTrue (firstname.compare("Franky") == 0);
|
|
||||||
Poco::Timestamp birthDateTimestamp = doc->get<Poco::Timestamp>("birthdate");
|
|
||||||
Poco::DateTime birthDate(birthDateTimestamp);
|
|
||||||
assertTrue (birthDate.year() == 1969 && birthDate.month() == 3 && birthDate.day() == 9);
|
|
||||||
Poco::Timestamp lastupdatedTimestamp = doc->get<Poco::Timestamp>("lastupdated");
|
|
||||||
assertTrue (doc->isType<NullValue>("unknown"));
|
|
||||||
|
|
||||||
std::string id = doc->get("_id")->toString();
|
|
||||||
}
|
|
||||||
catch(Poco::NotFoundException& nfe)
|
|
||||||
{
|
|
||||||
fail(nfe.message() + " not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("No document returned");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testCountCommand()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::QueryRequest request("team.$cmd");
|
|
||||||
request.setNumberToReturn(1);
|
|
||||||
request.selector().add("count", std::string("players"));
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
|
|
||||||
_mongo->sendRequest(request, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
assertTrue (doc->getInteger("n") == 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("Didn't get a response from the count command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testDBCountCommand()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Database db("team");
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> request = db.createCountRequest("players");
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
_mongo->sendRequest(*request, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
assertTrue (doc->getInteger("n") == 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("Didn't get a response from the count command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testDBCount2Command()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Database db("team");
|
|
||||||
Poco::Int64 count = db.count(*_mongo, "players");
|
|
||||||
assertTrue (count == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testDeleteRequest()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::DeleteRequest request("team.players");
|
|
||||||
request.selector().add("lastname", std::string("Braem"));
|
|
||||||
|
|
||||||
_mongo->sendRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testCursorRequest()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Database db("team");
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::DeleteRequest> deleteRequest = db.createDeleteRequest("numbers");
|
|
||||||
_mongo->sendRequest(*deleteRequest);
|
|
||||||
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::InsertRequest> insertRequest = db.createInsertRequest("numbers");
|
|
||||||
for(int i = 0; i < 10000; ++i)
|
|
||||||
{
|
|
||||||
Document::Ptr doc = new Document();
|
|
||||||
doc->add("number", i);
|
|
||||||
insertRequest->documents().push_back(doc);
|
|
||||||
}
|
|
||||||
_mongo->sendRequest(*insertRequest);
|
|
||||||
|
|
||||||
Poco::Int64 count = db.count(*_mongo, "numbers");
|
|
||||||
assertTrue (count == 10000);
|
|
||||||
|
|
||||||
Poco::MongoDB::Cursor cursor("team", "numbers");
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
Poco::MongoDB::ResponseMessage& response = cursor.next(*_mongo);
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
n += static_cast<int>(response.documents().size());
|
|
||||||
if ( response.cursorID() == 0 )
|
|
||||||
break;
|
|
||||||
response = cursor.next(*_mongo);
|
|
||||||
}
|
|
||||||
assertTrue (n == 10000);
|
|
||||||
|
|
||||||
Poco::MongoDB::QueryRequest drop("team.$cmd");
|
|
||||||
drop.setNumberToReturn(1);
|
|
||||||
drop.selector().add("drop", std::string("numbers"));
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage responseDrop;
|
|
||||||
_mongo->sendRequest(drop, responseDrop);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MongoDBTest::testBuildInfo()
|
void MongoDBTest::testBuildInfo()
|
||||||
{
|
{
|
||||||
// build info can be issued on "config" system database
|
|
||||||
|
|
||||||
Poco::MongoDB::Database db("config");
|
Poco::MongoDB::Database db("config");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -328,39 +120,6 @@ void MongoDBTest::testHello()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testConnectionPool()
|
|
||||||
{
|
|
||||||
#if POCO_OS == POCO_OS_ANDROID
|
|
||||||
std::string host = "10.0.2.2";
|
|
||||||
#else
|
|
||||||
std::string host = "127.0.0.1";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Poco::Net::SocketAddress sa(host, 27017);
|
|
||||||
Poco::PoolableObjectFactory<Poco::MongoDB::Connection, Poco::MongoDB::Connection::Ptr> factory(sa);
|
|
||||||
Poco::ObjectPool<Poco::MongoDB::Connection, Poco::MongoDB::Connection::Ptr> pool(factory, 10, 15);
|
|
||||||
|
|
||||||
Poco::MongoDB::PooledConnection pooledConnection(pool);
|
|
||||||
|
|
||||||
Poco::MongoDB::QueryRequest request("team.$cmd");
|
|
||||||
request.setNumberToReturn(1);
|
|
||||||
request.selector().add("count", std::string("players"));
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
((Connection::Ptr) pooledConnection)->sendRequest(request, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
assertTrue (doc->getInteger("n") == 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("Didn't get a response from the count command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testObjectID()
|
void MongoDBTest::testObjectID()
|
||||||
{
|
{
|
||||||
ObjectId oid("536aeebba081de6815000002");
|
ObjectId oid("536aeebba081de6815000002");
|
||||||
@@ -369,77 +128,6 @@ void MongoDBTest::testObjectID()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testCommand() {
|
|
||||||
Poco::MongoDB::Database db("team");
|
|
||||||
Poco::SharedPtr<Poco::MongoDB::QueryRequest> command = db.createCommand();
|
|
||||||
command->selector().add("create", "fixCol")
|
|
||||||
.add("capped", true)
|
|
||||||
.add("max", 1024*1024)
|
|
||||||
.add("size", 1024);
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
_mongo->sendRequest(*command, response);
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr lastError = db.getLastErrorDoc(*_mongo);
|
|
||||||
fail(lastError->toString(2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testUUID()
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr club = new Poco::MongoDB::Document();
|
|
||||||
club->add("name", std::string("Barcelona"));
|
|
||||||
|
|
||||||
Poco::UUIDGenerator generator;
|
|
||||||
Poco::UUID uuid = generator.create();
|
|
||||||
Poco::MongoDB::Binary::Ptr uuidBinary = new Poco::MongoDB::Binary(uuid);
|
|
||||||
club->add("uuid", uuidBinary);
|
|
||||||
|
|
||||||
Poco::MongoDB::InsertRequest request("team.club");
|
|
||||||
request.documents().push_back(club);
|
|
||||||
|
|
||||||
_mongo->sendRequest(request);
|
|
||||||
|
|
||||||
Poco::MongoDB::QueryRequest queryReq("team.club");
|
|
||||||
queryReq.selector().add("name" , std::string("Barcelona"));
|
|
||||||
|
|
||||||
Poco::MongoDB::ResponseMessage response;
|
|
||||||
_mongo->sendRequest(queryReq, response);
|
|
||||||
|
|
||||||
if ( response.documents().size() > 0 )
|
|
||||||
{
|
|
||||||
Poco::MongoDB::Document::Ptr doc = response.documents()[0];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string name = doc->get<std::string>("name");
|
|
||||||
assertTrue (name.compare("Barcelona") == 0);
|
|
||||||
|
|
||||||
Poco::MongoDB::Binary::Ptr uuidBinary = doc->get<Binary::Ptr>("uuid");
|
|
||||||
assertTrue (uuid == uuidBinary->uuid());
|
|
||||||
}
|
|
||||||
catch(Poco::NotFoundException& nfe)
|
|
||||||
{
|
|
||||||
fail(nfe.message() + " not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail("No document returned");
|
|
||||||
}
|
|
||||||
|
|
||||||
Poco::MongoDB::DeleteRequest delRequest("team.club");
|
|
||||||
delRequest.selector().add("name", std::string("Barcelona"));
|
|
||||||
_mongo->sendRequest(delRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MongoDBTest::testConnectURI()
|
void MongoDBTest::testConnectURI()
|
||||||
{
|
{
|
||||||
Poco::MongoDB::Connection conn;
|
Poco::MongoDB::Connection conn;
|
||||||
@@ -491,6 +179,36 @@ void MongoDBTest::testConnectURI()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MongoDBTest::testDBCount()
|
||||||
|
{
|
||||||
|
// First insert some documents
|
||||||
|
Database db("team");
|
||||||
|
Poco::SharedPtr<OpMsgMessage> request = db.createOpMsgMessage("players");
|
||||||
|
request->setCommandName(OpMsgMessage::CMD_INSERT);
|
||||||
|
|
||||||
|
Document::Ptr player = new Document();
|
||||||
|
player->add("lastname", std::string("TestPlayer"));
|
||||||
|
player->add("firstname", std::string("Test"));
|
||||||
|
request->documents().push_back(player);
|
||||||
|
|
||||||
|
OpMsgMessage response;
|
||||||
|
_mongo->sendRequest(*request, response);
|
||||||
|
assertTrue(response.responseOk());
|
||||||
|
|
||||||
|
// Now test the count method
|
||||||
|
Poco::Int64 count = db.count(*_mongo, "players");
|
||||||
|
assertTrue (count >= 1);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
request = db.createOpMsgMessage("players");
|
||||||
|
request->setCommandName(OpMsgMessage::CMD_DELETE);
|
||||||
|
Document::Ptr del = new Document();
|
||||||
|
del->add("limit", 0).addNewDocument("q").add("lastname" , std::string("TestPlayer"));
|
||||||
|
request->documents().push_back(del);
|
||||||
|
_mongo->sendRequest(*request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CppUnit::Test* MongoDBTest::suite()
|
CppUnit::Test* MongoDBTest::suite()
|
||||||
{
|
{
|
||||||
#if POCO_OS == POCO_OS_ANDROID
|
#if POCO_OS == POCO_OS_ANDROID
|
||||||
@@ -522,23 +240,6 @@ CppUnit::Test* MongoDBTest::suite()
|
|||||||
CppUnit_addTest(pSuite, MongoDBTest, testHello);
|
CppUnit_addTest(pSuite, MongoDBTest, testHello);
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testBuildInfo);
|
CppUnit_addTest(pSuite, MongoDBTest, testBuildInfo);
|
||||||
|
|
||||||
if (_wireVersion < Poco::MongoDB::Database::VER_51)
|
|
||||||
{
|
|
||||||
// Database supports old wire protocol
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testInsertRequest);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testQueryRequest);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testDBQueryRequest);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testCountCommand);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testDBCountCommand);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testDBCount2Command);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testConnectionPool);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testDeleteRequest);
|
|
||||||
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testCursorRequest);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testCommand);
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testUUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_wireVersion >= Poco::MongoDB::Database::VER_36)
|
if (_wireVersion >= Poco::MongoDB::Database::VER_36)
|
||||||
{
|
{
|
||||||
// Database supports OP_MSG wire protocol
|
// Database supports OP_MSG wire protocol
|
||||||
@@ -560,6 +261,8 @@ CppUnit::Test* MongoDBTest::suite()
|
|||||||
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testOpCmdUUID);
|
CppUnit_addTest(pSuite, MongoDBTest, testOpCmdUUID);
|
||||||
|
|
||||||
|
CppUnit_addTest(pSuite, MongoDBTest, testDBCount);
|
||||||
|
|
||||||
CppUnit_addTest(pSuite, MongoDBTest, testOpCmdDropDatabase);
|
CppUnit_addTest(pSuite, MongoDBTest, testOpCmdDropDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,21 +35,7 @@ public:
|
|||||||
void testHello();
|
void testHello();
|
||||||
void testConnectURI();
|
void testConnectURI();
|
||||||
|
|
||||||
// Old wire protocol
|
// OP_MSG wire protocol
|
||||||
void testInsertRequest();
|
|
||||||
void testQueryRequest();
|
|
||||||
void testDBQueryRequest();
|
|
||||||
void testCountCommand();
|
|
||||||
void testDBCountCommand();
|
|
||||||
void testDBCount2Command();
|
|
||||||
void testDeleteRequest();
|
|
||||||
|
|
||||||
void testConnectionPool();
|
|
||||||
void testCursorRequest();
|
|
||||||
void testCommand();
|
|
||||||
void testUUID();
|
|
||||||
|
|
||||||
// New wire protocol using OP_CMD
|
|
||||||
void testOpCmdUUID();
|
void testOpCmdUUID();
|
||||||
void testOpCmdHello();
|
void testOpCmdHello();
|
||||||
void testOpCmdWriteRead();
|
void testOpCmdWriteRead();
|
||||||
@@ -64,6 +50,7 @@ public:
|
|||||||
void testOpCmdUnaknowledgedInsert();
|
void testOpCmdUnaknowledgedInsert();
|
||||||
void testOpCmdConnectionPool();
|
void testOpCmdConnectionPool();
|
||||||
void testOpCmdDropDatabase();
|
void testOpCmdDropDatabase();
|
||||||
|
void testDBCount();
|
||||||
|
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user