// // Element.h // // $Id$ // // Library: MongoDB // Package: MongoDB // Module: Element // // Definition of the Element class. // // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. // and Contributors. // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // #ifndef MongoDB_Element_INCLUDED #define MongoDB_Element_INCLUDED #include "Poco/BinaryReader.h" #include "Poco/BinaryWriter.h" #include "Poco/SharedPtr.h" #include "Poco/Timestamp.h" #include "Poco/Nullable.h" #include "Poco/NumberFormatter.h" #include "Poco/DateTimeFormatter.h" #include "Poco/MongoDB/MongoDB.h" #include "Poco/MongoDB/BSONReader.h" #include "Poco/MongoDB/BSONWriter.h" #include #include #include #include namespace Poco { namespace MongoDB { class MongoDB_API Element /// Represents an element of a Document or an Array { public: typedef Poco::SharedPtr Ptr; Element(const std::string& name); /// Constructor virtual ~Element(); /// Destructor std::string name() const; /// Returns the name of the element virtual std::string toString(int indent = 0) const = 0; /// Returns a string representation of the element. virtual int type() const = 0; /// Returns the MongoDB type of the element. private: virtual void read(BinaryReader& reader) = 0; virtual void write(BinaryWriter& writer) = 0; friend class Document; std::string _name; }; inline std::string Element::name() const { return _name; } class ElementComparator { public: bool operator()(const Element::Ptr& s1, const Element::Ptr& s2) { return s1->name() < s2->name(); } }; typedef std::set ElementSet; template struct ElementTraits { }; // BSON Floating point // spec: double template<> struct ElementTraits { enum { TypeId = 0x01 }; static std::string toString(const double& value, int indent = 0) { return Poco::NumberFormatter::format(value); } }; // BSON UTF-8 string // spec: int32 (byte*) "\x00" // int32 is the number bytes in byte* + 1 (for trailing "\x00") template<> struct ElementTraits { enum { TypeId = 0x02 }; static std::string toString(const std::string& value, int indent = 0) { std::ostringstream oss; oss << '"'; for(std::string::const_iterator it = value.begin(); it != value.end(); ++it) { switch (*it) { case '"': oss << "\\\""; break; case '\\': oss << "\\\\"; break; case '\b': oss << "\\b"; break; case '\f': oss << "\\f"; break; case '\n': oss << "\\n"; break; case '\r': oss << "\\r"; break; case '\t': oss << "\\t"; break; default: { if ( *it > 0 && *it <= 0x1F ) { oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*it); } else { oss << *it; } break; } } } oss << '"'; return oss.str(); } }; template<> inline void BSONReader::read(std::string& to) { Poco::Int32 size; _reader >> size; _reader.readRaw(size, to); to.erase(to.end() - 1); // remove terminating 0 } template<> inline void BSONWriter::write(std::string& from) { _writer << (Poco::Int32) (from.length() + 1); writeCString(from); } // BSON bool // spec: "\x00" "\x01" template<> struct ElementTraits { enum { TypeId = 0x08 }; static std::string toString(const bool& value, int indent = 0) { return value ? "true" : "false"; } }; template<> inline void BSONReader::read(bool& to) { unsigned char b; _reader >> b; to = b != 0; } template<> inline void BSONWriter::write(bool& from) { unsigned char b = from ? 0x01 : 0x00; _writer << b; } // BSON 32-bit integer // spec: int32 template<> struct ElementTraits { enum { TypeId = 0x10 }; static std::string toString(const Int32& value, int indent = 0) { return Poco::NumberFormatter::format(value); } }; // BSON UTC datetime // spec: int64 template<> struct ElementTraits { enum { TypeId = 0x09 }; static std::string toString(const Timestamp& value, int indent = 0) { return DateTimeFormatter::format(value, "%Y-%m-%dT%H:%M:%s%z"); } }; template<> inline void BSONReader::read(Timestamp& to) { Poco::Int64 value; _reader >> value; to = Timestamp::fromEpochTime(static_cast(value / 1000)); to += (value % 1000 * 1000); } template<> inline void BSONWriter::write(Timestamp& from) { _writer << (from.epochMicroseconds() / 1000); } typedef Nullable NullValue; // BSON Null Value // spec: template<> struct ElementTraits { enum { TypeId = 0x0A }; static std::string toString(const NullValue& value, int indent = 0) { return "null"; } }; template<> inline void BSONReader::read(NullValue& to) { } template<> inline void BSONWriter::write(NullValue& from) { } // BSON 64-bit integer // spec: int64 template<> struct ElementTraits { enum { TypeId = 0x12 }; static std::string toString(const Int64& value, int indent = 0) { return NumberFormatter::format(value); } }; template class ConcreteElement : public Element { public: ConcreteElement(const std::string& name, const T& init) : Element(name), _value(init) { } virtual ~ConcreteElement() { } T value() const { return _value; } std::string toString(int indent = 0) const { return ElementTraits::toString(_value, indent); } int type() const { return ElementTraits::TypeId; } void read(BinaryReader& reader) { BSONReader(reader).read(_value); } void write(BinaryWriter& writer) { BSONWriter(writer).write(_value); } private: T _value; }; } } // namespace Poco::MongoDB #endif // MongoDB_Element_INCLUDED