// // Document.cpp // // Library: MongoDB // Package: MongoDB // Module: Document // // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #include "Poco/MongoDB/Document.h" #include "Poco/MongoDB/Binary.h" #include "Poco/MongoDB/ObjectId.h" #include "Poco/MongoDB/Array.h" #include "Poco/MongoDB/RegularExpression.h" #include "Poco/MongoDB/JavaScriptCode.h" #include namespace Poco { namespace MongoDB { Document::Document() { } Document::~Document() { } Array& Document::addNewArray(const std::string& name) { Array::Ptr newArray = new Array(); add(name, newArray); return *newArray; } Element::Ptr Document::get(const std::string& name) const { Element::Ptr element; ElementSet::const_iterator it = std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name)); if (it != _elements.end()) { return *it; } return element; } Int64 Document::getInteger(const std::string& name) const { Element::Ptr element = get(name); if (element.isNull()) throw Poco::NotFoundException(name); if (ElementTraits::TypeId == element->type()) { ConcreteElement* concrete = dynamic_cast*>(element.get()); if (concrete) return static_cast(concrete->value()); } else if (ElementTraits::TypeId == element->type()) { ConcreteElement* concrete = dynamic_cast*>(element.get()); if (concrete) return concrete->value(); } else if (ElementTraits::TypeId == element->type()) { ConcreteElement* concrete = dynamic_cast*>(element.get()); if (concrete) return concrete->value(); } throw Poco::BadCastException("Invalid type mismatch!"); } void Document::read(BinaryReader& reader) { int size; reader >> size; unsigned char type; reader >> type; while (type != '\0') { Element::Ptr element; std::string name = BSONReader(reader).readCString(); switch (type) { case ElementTraits::TypeId: element = new ConcreteElement(name, 0); break; case ElementTraits::TypeId: element = new ConcreteElement(name, 0); break; case ElementTraits::TypeId: element = new ConcreteElement(name, ""); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new Document); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new Array); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new Binary); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new ObjectId); break; case ElementTraits::TypeId: element = new ConcreteElement(name, false); break; case ElementTraits::TypeId: element = new ConcreteElement(name, Poco::Timestamp()); break; case ElementTraits::TypeId: element = new ConcreteElement(name, BSONTimestamp()); break; case ElementTraits::TypeId: element = new ConcreteElement(name, NullValue(0)); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new RegularExpression()); break; case ElementTraits::TypeId: element = new ConcreteElement(name, new JavaScriptCode()); break; case ElementTraits::TypeId: element = new ConcreteElement(name, 0); break; default: { std::stringstream ss; ss << "Element " << name << " contains an unsupported type 0x" << std::hex << (int) type; throw Poco::NotImplementedException(ss.str()); } //TODO: x0F -> JavaScript code with scope // xFF -> Min Key // x7F -> Max Key } element->read(reader); _elements.push_back(element); reader >> type; } } std::string Document::toString(int indent) const { std::ostringstream oss; oss << '{'; if (indent > 0) oss << std::endl; for (ElementSet::const_iterator it = _elements.begin(); it != _elements.end(); ++it) { if (it != _elements.begin()) { oss << ','; if (indent > 0) oss << std::endl; } for (int i = 0; i < indent; ++i) oss << ' '; oss << '"' << (*it)->name() << '"'; oss << (indent > 0 ? " : " : ":"); oss << (*it)->toString(indent > 0 ? indent + 2 : 0); } if (indent > 0) { oss << std::endl; if (indent >= 2) indent -= 2; for (int i = 0; i < indent; ++i) oss << ' '; } oss << '}'; return oss.str(); } void Document::write(BinaryWriter& writer) { if (_elements.empty()) { writer << 5; } else { std::stringstream sstream; Poco::BinaryWriter tempWriter(sstream, BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER); for (ElementSet::iterator it = _elements.begin(); it != _elements.end(); ++it) { tempWriter << static_cast((*it)->type()); BSONWriter(tempWriter).writeCString((*it)->name()); Element::Ptr element = *it; element->write(tempWriter); } tempWriter.flush(); Poco::Int32 len = static_cast(5 + sstream.tellp()); /* 5 = sizeof(len) + 0-byte */ writer << len; writer.writeRaw(sstream.str()); } writer << '\0'; } } } // namespace Poco::MongoDB