#pragma once /////////////////////////////////////////////////////////////////////// // Persist.h - persist DbCore

to and from XML file // // ver 1.0 // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2018 // /////////////////////////////////////////////////////////////////////// /* * Package Operations: * ------------------- * This package defines a single Persist class that: * - accepts a DbCore

instance when constructed * - persists its database to an XML string * - creates an instance of DbCore

from a persisted XML string * * Required Files: * --------------- * Persist.h, Persist.cpp * DbCore.h, DbCore.cpp * Query.h, Query.cpp * PayLoad.h * XmlDocument.h, XmlDocument.cpp * XmlElement.h, XmlElement.cpp * * Maintenance History: * -------------------- * ver 1.0 : 12 Feb 2018 * - first release */ #include "../DbCore/DbCore.h" #include "../Query/Query.h" #include "../DateTime/DateTime.h" #include "../XmlDocument/XmlDocument/XmlDocument.h" #include "../XmlDocument/XmlElement/XmlElement.h" #include #include namespace NoSqlDb { using namespace XmlProcessing; using Xml = std::string; using Sptr = std::shared_ptr; const bool augment = true; // do augment const bool rebuild = false; // don't augment ///////////////////////////////////////////////////////////////////// // Persist

class // - persist DbCore

to XML string template class Persist { public: Persist(DbCore

& db); virtual ~Persist() {} static void identify(std::ostream& out = std::cout); Persist

& shard(const Keys& keys); Persist

& addShardKey(const Key& key); Persist

& removeShard(); Xml toXml(); bool fromXml(const Xml& xml, bool augment = true); // will clear and reload db if augment is false !!! private: DbCore

& db_; Keys shardKeys_; bool containsKey(const Key& key); void toXmlRecord(Sptr pDb, const Key& key, DbElement

& dbElem); }; //----< constructor >------------------------------------------------ template Persist

::Persist(DbCore

& db) : db_(db) {} //----< show file name >--------------------------------------------- template void Persist

::identify(std::ostream& out) { out << "\n \"" << __FILE__ << "\""; } //----< add key to shard collection >-------------------------------- /* * - when sharding, a db record is persisted if, and only if, its key is contained in the shard collection */ template Persist

& Persist

::addShardKey(const Key& key) { shardKeys_.push_back(key); return *this; } //----< does the shard key collection contain key? >----------------- template bool Persist

::containsKey(const Key& key) { Keys::iterator start = shardKeys_.begin(); Keys::iterator end = shardKeys_.end(); return std::find(start, end, key) != end; } //----< set the shardKeys collection >------------------------------- template Persist

& Persist

::shard(const Keys& keys) { shardKeys_ = keys; return *this; } //----< empty the shardKeys collection >----------------------------- template Persist

& Persist

::removeShard() { shardKeys_.clear(); } //----< persist database record to XML string >---------------------- template void Persist

::toXmlRecord(Sptr pDb, const Key& key, DbElement

& dbElem) { Sptr pRecord = makeTaggedElement("dbRecord"); pDb->addChild(pRecord); Sptr pKey = makeTaggedElement("key", key); pRecord->addChild(pKey); Sptr pValue = makeTaggedElement("value"); pRecord->addChild(pValue); Sptr pName = makeTaggedElement("name", dbElem.name()); pValue->addChild(pName); Sptr pDescrip = makeTaggedElement("description", dbElem.descrip()); pValue->addChild(pDescrip); Sptr pChildren = makeTaggedElement("children"); pValue->addChild(pChildren); for (auto child : dbElem.children()) { Sptr pChild = makeTaggedElement("child", child); pChildren->addChild(pChild); } Sptr pPayLoad = dbElem.payLoad().toXmlElement(); pValue->addChild(pPayLoad); } //----< persist, possibly sharded, database to XML string >---------- /* * - database is sharded if the shardKeys collection is non-empty */ template Xml Persist

::toXml() { Sptr pDb = makeTaggedElement("db"); pDb->addAttrib("type", "fromQuery"); Sptr pDocElem = makeDocElement(pDb); XmlDocument xDoc(pDocElem); if (shardKeys_.size() > 0) { for (auto key : shardKeys_) { DbElement

elem = db_[key]; toXmlRecord(pDb, key, elem); } } else { for (auto item : db_) { toXmlRecord(pDb, item.first, item.second); } } std::string xml = xDoc.toString(); return xml; } //----< retrieve database from XML string >-------------------------- /* * - Will clear db and reload if augment is false */ template bool Persist

::fromXml(const Xml& xml, bool augment) { XmlProcessing::XmlDocument doc(xml); if(!augment) db_.dbStore().clear(); std::vector pRecords = doc.descendents("dbRecord").select(); for (auto pRecord : pRecords) { Key key; DbElement

elem; P pl; std::vector pChildren = pRecord->children(); for (auto pChild : pChildren) { if (pChild->tag() == "key") { key = pChild->children()[0]->value(); } else { std::vector pValueChildren = pChild->children(); std::string valueOfTextNode; for (auto pValueChild : pValueChildren) { std::string tag = pValueChild->tag(); if (pValueChild->children().size() > 0) valueOfTextNode = pValueChild->children()[0]->value(); else valueOfTextNode = ""; if (tag == "name") { elem.name(valueOfTextNode); } else if (tag == "description") { elem.descrip(valueOfTextNode); } else if (tag == "dateTime") { elem.dateTime(valueOfTextNode); } else if (tag == "children") { for (auto pChild : pValueChild->children()) { valueOfTextNode = pChild->children()[0]->value(); elem.children().push_back(valueOfTextNode); } } else if (tag == "payload") { pl = PayLoad::fromXmlElement(pValueChild); elem.payLoad(pl); } } } db_[key] = elem; } } return true; } }