{"action":"created","comment":{"url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/comments/67774405","id":67774405,"diff_hunk":"@@ -0,0 +1,1013 @@\n+#pragma once\n+\n+#include <memory>\n+#include <stack>\n+#include <string>\n+#include <vector>\n+\n+#include <cereal/cereal.hpp>\n+\n+#include <bsoncxx/builder/core.hpp>\n+#include <bsoncxx/types.hpp>\n+#include <bsoncxx/types/value.hpp>\n+\n+namespace cereal {\n+\n+/**\n+ * A base class that holds a shared_ptr to the binary data for a BSON document. If a class you are\n+ * serializing contains any of the bsoncxx view types (b_utf8, b_document, b_array, b_binary), you\n+ * must have that class inherit this base so that the views don't point to deallocated memory.\n+ *\n+ * When using the BSONInputArchive to deserialize a class that inherits from this base, the data\n+ * will be automatically loaded into this class using setUnderlyingBSONData().\n+ */\n+class UnderlyingBSONDataBase {\n+   public:\n+    void setUnderlyingBSONData(std::shared_ptr<uint8_t> ptr, size_t size) {\n+        _underlyingBSONData = ptr;\n+        _underlyingBSONDataSize = size;\n+    }\n+\n+    const bsoncxx::document::view getUnderlyingBSONData() {\n+        return bsoncxx::document::view{_underlyingBSONData.get(), _underlyingBSONDataSize};\n+    }\n+\n+   private:\n+    std::shared_ptr<uint8_t> _underlyingBSONData;\n+    size_t _underlyingBSONDataSize;\n+};\n+\n+/**\n+ * A templated struct containing a bool value that specifies whether the\n+ * provided template parameter is a BSON type.\n+ */\n+template <class BsonT>\n+struct is_bson {\n+    static constexpr auto value = std::is_same<BsonT, bsoncxx::types::b_double>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_utf8>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_document>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_array>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_binary>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_oid>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_bool>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_date>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_int32>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_int64>::value ||\n+                                  std::is_same<BsonT, bsoncxx::oid>::value;\n+};\n+\n+/**\n+ * A templated struct containing a bool value that specifies whether the\n+ * provided template parameter is a BSON type that contains a view.\n+ */\n+template <class BsonT>\n+struct is_bson_view {\n+    static constexpr auto value = std::is_same<BsonT, bsoncxx::types::b_utf8>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_document>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_array>::value ||\n+                                  std::is_same<BsonT, bsoncxx::types::b_binary>::value;\n+};\n+\n+class BSONOutputArchive : public OutputArchive<BSONOutputArchive> {\n+    /**\n+    * The possible states for the BSON nodes being output by the archive.\n+    */\n+    enum class OutputNodeType { StartObject, InObject, StartArray, InArray };\n+\n+    typedef bsoncxx::builder::core BSONBuilder;\n+\n+   public:\n+    /**\n+    * Construct a BSONOutputArchive that will output to the provided stream.\n+    *\n+    * @param stream\n+    *   The stream to which the archiver will output BSON data.\n+    */\n+    BSONOutputArchive(std::ostream& stream)\n+        : OutputArchive<BSONOutputArchive>{this},\n+          _bsonBuilder{false},\n+          _writeStream{stream},\n+          _nextName{nullptr},\n+          _objAsRootElement{false} {\n+    }\n+\n+   private:\n+    /**\n+     * Writes the current contents of the BSON document builder to the\n+     * output stream.\n+     */\n+    void writeDoc() {\n+        _writeStream.write(reinterpret_cast<const char*>(_bsonBuilder.view_document().data()),\n+                           _bsonBuilder.view_document().length());\n+        _bsonBuilder.clear();\n+    }\n+\n+   public:\n+    /**\n+     * Checks if the most recent object written was in the root of the document.\n+     * If so, that document is written to the archive.\n+     */\n+    void writeDocIfRoot() {\n+        if (_nodeTypeStack.empty()) {\n+            writeDoc();\n+        }\n+    }\n+\n+    /**\n+     * Starts a new node in the BSON output.\n+     *\n+     * The node can optionally be given a name by calling setNextName prior to\n+     * creating the node. Nodes only need to be started for types that are\n+     * objects or arrays.\n+     */\n+    void startNode(bool inheritsUnderlyingBSONDataBase) {\n+        writeName(true);\n+        _nodeTypeStack.push(OutputNodeType::StartObject);\n+        _curNodeInheritsUnderlyingBSONDataBase.push(inheritsUnderlyingBSONDataBase);\n+    }\n+\n+    /**\n+     * Designates the most recently added node as finished, which will end\n+     * any objects or arrays we happen to be in.\n+     */\n+    void finishNode() {\n+        // Iff we ended up serializing an empty object or array, writeName\n+        // will never have been called - therefore the node type at the top\n+        // of the stack will be StartArray or StartObject - so start and\n+        // then immediately end the documents/array.\n+\n+        // We'll also end any documents/arrays we happen to be in.\n+\n+        if (_nodeTypeStack.empty()) {\n+            throw cereal::Exception(\"Attempting to finish a nonexistent node.\\n\");\n+        }\n+\n+        switch (_nodeTypeStack.top()) {\n+            case OutputNodeType::StartArray:\n+                _bsonBuilder.open_array();\n+            // Don't break so that this array can also be closed.\n+            case OutputNodeType::InArray:\n+                _bsonBuilder.close_array();\n+                break;\n+            case OutputNodeType::StartObject:\n+                if (_nodeTypeStack.size() > 1 || _objAsRootElement) {\n+                    _bsonBuilder.open_document();\n+                }\n+            // Don't break so that this document can also be closed.\n+            case OutputNodeType::InObject:\n+                if (_nodeTypeStack.size() > 1) {\n+                    _bsonBuilder.close_document();\n+                } else if (_objAsRootElement) {\n+                    _bsonBuilder.close_document();\n+                }\n+                break;\n+        }\n+\n+        _nodeTypeStack.pop();\n+        _curNodeInheritsUnderlyingBSONDataBase.pop();\n+\n+        // Reset the _objAsRootElement tracker bool if the stack was emptied.\n+        if (_nodeTypeStack.empty()) {\n+            _objAsRootElement = false;\n+        }\n+        writeDocIfRoot();\n+    }\n+\n+    /**\n+     * Sets the name for the next node or element.\n+     *\n+     * @param name\n+     *    The name for the next node or element.\n+     */\n+    void setNextName(const char* name) {\n+        _nextName = name;\n+    }\n+\n+    /**\n+     * Saves a value of type T to the current node.\n+     *\n+     * @param t\n+     *    A value t where T is any type that is accepted by an overload\n+     *    of _bsonBuilder.append(), except for bsoncxx view types.\n+     */\n+    template <class T>\n+    typename std::enable_if<!is_bson_view<typename std::decay<T>::type>::value>::type saveValue(\n+        T&& t) {\n+        _bsonBuilder.append(std::forward<T>(t));\n+    }\n+\n+    /**\n+     * Saves a value of type T to the current node, and throws an exception if we're serializing a\n+     * bsoncxx view type without it being wrapped in a class that inherits UnderlyingBSONDataBase.\n+     *\n+     * @param t\n+     *    A value t where T is one of the bsoncxx view types.\n+     */\n+    template <class T>\n+    typename std::enable_if<is_bson_view<typename std::decay<T>::type>::value>::type saveValue(\n+        T&& t) {\n+        if (_curNodeInheritsUnderlyingBSONDataBase.empty() ||\n+            !_curNodeInheritsUnderlyingBSONDataBase.top()) {\n+            throw cereal::Exception(\n+                \"Cannot serialize bsoncxx view type (b_utf8, b_document, b_array, b_binary) unless \"\n+                \"that type is wrapped in a class that inherits UnderlyingBSONDataBase.\\n\");\n+        }\n+        _bsonBuilder.append(std::forward<T>(t));\n+    }\n+\n+    /**\n+     * Specialization of saveValue for std::chrono::system_clock::time_point,\n+     * which can't be directly passed to a BSON builder without it first\n+     * being constructed into a bsoncxx::types::b_date.\n+     */\n+    void saveValue(std::chrono::system_clock::time_point tp) {\n+        _bsonBuilder.append(bsoncxx::types::b_date{tp});\n+    }\n+\n+    /**\n+     * Write the name of the upcoming element and prepare object/array state.\n+     * Since writeName is called for every value that is output, regardless of\n+     * whether it has a name or not, it is the place where we will do a deferred\n+     * check of our node state and decide whether we are in an array or an object.\n+     *\n+     * The general workflow of saving to the BSON archive is:\n+     *   1. Set the name for the next node to be created, usually done by an NVP.\n+     *   2. Start the node.\n+     *   3. (if there is data to save) Write the name of the node (this function).\n+     *   4. (if there is data to save) Save each element of data (with saveValue).\n+     *   5. Finish the node.\n+     *\n+     * @param isNewNode\n+     *  Specifies whether this is writing the name of a new node. If this is set to true,\n+     *  and we happen to be in the root node no name will be enforced since root level documents\n+     *  have no name.\n+     */\n+    void writeName(bool isNewNode = false) {\n+        if (!_nodeTypeStack.empty()) {\n+            const auto& topType = _nodeTypeStack.top();\n+\n+            // Start up either an object or an array, depending on state.\n+            if (topType == OutputNodeType::StartArray) {\n+                _bsonBuilder.open_array();\n+                _nodeTypeStack.top() = OutputNodeType::InArray;\n+            } else if (topType == OutputNodeType::StartObject) {\n+                _nodeTypeStack.top() = OutputNodeType::InObject;\n+                // Only open a document if this document is not in the\n+                // root node or this is a root element.\n+                if (_nodeTypeStack.size() > 1 || _objAsRootElement) {\n+                    _bsonBuilder.open_document();\n+                }\n+            }\n+\n+            // Elements in arrays do not have names.\n+            if (topType == OutputNodeType::InArray) return;\n+        }\n+\n+        if (!_nextName && _nodeTypeStack.empty() && isNewNode) {\n+            // This is a document at the root node with no name.\n+            // Do nothing since no name is expected for non root-element documents in root.\n+            return;\n+        } else if (!_nextName) {\n+            // Enforce the existence of a name-value pair if this is not a node in root,\n+            // or this in an element in root.\n+            throw cereal::Exception(\"Missing a name for current node or element.\\n\");\n+        } else {\n+            // Set the key of this element to the name stored by the archiver.\n+            _bsonBuilder.key_view(_nextName);\n+            _nextName = nullptr;\n+\n+            // If this a named node in the root node, set up this node as a root element.\n+            if (_nodeTypeStack.empty() && isNewNode) {\n+                _objAsRootElement = true;\n+            }\n+        }\n+    }\n+\n+    /**\n+     * Designates that the current node should be output as an array, not an\n+     * object.\n+     */\n+    void makeArray() {\n+        _nodeTypeStack.top() = OutputNodeType::StartArray;\n+    }\n+\n+   private:\n+    // The BSONCXX builder for this archive.\n+    BSONBuilder _bsonBuilder;\n+\n+    // The stream to which to write the BSON archive.\n+    std::ostream& _writeStream;\n+\n+    // The name of the next element to be added to the archive.\n+    char const* _nextName;\n+\n+    // A stack maintaining the state of the nodes currently being written.\n+    std::stack<OutputNodeType> _nodeTypeStack;\n+\n+    // Stack maintaining whether or not the node we're serializing inherits from the underlying BSON\n+    // data base class required for classes that use bsoncxx view types.\n+    std::stack<bool> _curNodeInheritsUnderlyingBSONDataBase;\n+\n+    // Boolean value that tracks whether or not the current root BSON document or array is being\n+    // treated as a root element.\n+    bool _objAsRootElement;\n+\n+};  // BSONOutputArchive\n+\n+class BSONInputArchive : public InputArchive<BSONInputArchive> {\n+    enum class InputNodeType { InObject, InEmbeddedObject, InEmbeddedArray, InRootElement };\n+\n+   public:\n+    /**\n+    * Construct a BSONInputArchive from an input stream of BSON data.\n+    *\n+    * @param stream\n+    *    The stream from which to read BSON data.\n+    */\n+    BSONInputArchive(std::istream& stream)\n+        : InputArchive<BSONInputArchive>(this),\n+          _nextName(nullptr),\n+          _readStream(stream),\n+          _readFirstDoc(false) {\n+    }\n+\n+   private:\n+    /**\n+     * Reads the next BSON document from the istream. This should be called whenever\n+     * we are starting to load in a root element or root node.\n+     */\n+    void readNextDoc() {\n+        // Determine the size of the BSON document in bytes.\n+        // TODO: Only works on little endian.\n+        int32_t docsize;\n+        char docsize_buf[sizeof(docsize)];\n+        _readStream.read(docsize_buf, sizeof(docsize));\n+        std::memcpy(&docsize, docsize_buf, sizeof(docsize));\n+\n+        // Throw an exception if the end of the stream is prematurely reached.\n+        if (_readStream.eof() || !_readStream || docsize < 5) {\n+            throw cereal::Exception(\"No more data in BSONInputArchive stream.\\n\");\n+        }\n+\n+        // Create a shared buffer to store the BSON document.\n+        _curBsonData =\n+            std::shared_ptr<uint8_t>{new uint8_t[docsize], [](uint8_t* p) { delete[] p; }};\n+\n+        // Read the BSON data from the stream into the buffer.\n+        std::memcpy(_curBsonData.get(), docsize_buf, sizeof(docsize));\n+        _readStream.read(reinterpret_cast<char*>(_curBsonData.get() + sizeof(docsize)),\n+                         docsize - sizeof(docsize));\n+\n+        // Make sure there were no errors reading the BSON data.\n+        if (_readStream.eof() || !_readStream) {\n+            throw cereal::Exception(\"No more data in BSONInputArchive stream.\\n\");\n+        }\n+\n+        // Store the BSON data of the document in a view that we can access.\n+        _curBsonDoc = bsoncxx::document::view{_curBsonData.get(), static_cast<size_t>(docsize)};\n+        _curBsonDataSize = docsize;\n+\n+        // Specify that we've read a document.\n+        _readFirstDoc = true;\n+    }\n+\n+    /**\n+     * Searches for the next BSON element to be retrieved and loaded.\n+     *\n+     * @return the element with _nextName as a key, or if the current node is an\n+     *         array, the next element in that array.\n+     */\n+    inline bsoncxx::types::value search() {","path":"src/bson_mapper/bson_archiver.hpp","position":398,"original_position":380,"commit_id":"affe1d2a78560ea233ea4a82a223498878e94e05","original_commit_id":"32c5e752a76f8102263af7fcaea0cd8742ce82b9","user":{"login":"adamchel","id":1976694,"avatar_url":"https://avatars.githubusercontent.com/u/1976694?v=3","gravatar_id":"","url":"https://api.github.com/users/adamchel","html_url":"https://github.com/adamchel","followers_url":"https://api.github.com/users/adamchel/followers","following_url":"https://api.github.com/users/adamchel/following{/other_user}","gists_url":"https://api.github.com/users/adamchel/gists{/gist_id}","starred_url":"https://api.github.com/users/adamchel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/adamchel/subscriptions","organizations_url":"https://api.github.com/users/adamchel/orgs","repos_url":"https://api.github.com/users/adamchel/repos","events_url":"https://api.github.com/users/adamchel/events{/privacy}","received_events_url":"https://api.github.com/users/adamchel/received_events","type":"User","site_admin":false},"body":"Cereal works by linearly iterating through the fields we have to populate (and recursively iterating through fields in subdocuments), so this would be pretty tricky.\r\n\r\nWe could theoretically create a `std::map` hash table when we read in the document in `readNextDoc()` and use that in `search()` instead of the `bsoncxx::document::view`'s `[ ]` overload.\r\n\r\nI think it would be the most feasible way to do this, because trying to fill in the fields if they exist as we read through the BSON just isn't possible with the way cereal works. What do you think?","created_at":"2016-06-20T21:57:05Z","updated_at":"2016-06-20T21:57:05Z","html_url":"https://github.com/mongodb/mongo-cxx-odm/pull/3#discussion_r67774405","pull_request_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3","_links":{"self":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/comments/67774405"},"html":{"href":"https://github.com/mongodb/mongo-cxx-odm/pull/3#discussion_r67774405"},"pull_request":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3"}}},"pull_request":{"url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3","id":73429021,"html_url":"https://github.com/mongodb/mongo-cxx-odm/pull/3","diff_url":"https://github.com/mongodb/mongo-cxx-odm/pull/3.diff","patch_url":"https://github.com/mongodb/mongo-cxx-odm/pull/3.patch","issue_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/3","number":3,"state":"open","locked":false,"title":"Preliminary BSON archiver","user":{"login":"adamchel","id":1976694,"avatar_url":"https://avatars.githubusercontent.com/u/1976694?v=3","gravatar_id":"","url":"https://api.github.com/users/adamchel","html_url":"https://github.com/adamchel","followers_url":"https://api.github.com/users/adamchel/followers","following_url":"https://api.github.com/users/adamchel/following{/other_user}","gists_url":"https://api.github.com/users/adamchel/gists{/gist_id}","starred_url":"https://api.github.com/users/adamchel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/adamchel/subscriptions","organizations_url":"https://api.github.com/users/adamchel/orgs","repos_url":"https://api.github.com/users/adamchel/repos","events_url":"https://api.github.com/users/adamchel/events{/privacy}","received_events_url":"https://api.github.com/users/adamchel/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-06-10T20:10:41Z","updated_at":"2016-06-20T21:57:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"137f9331db9fc1071eee5f89ce366a894682f697","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3/commits","review_comments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3/comments","review_comment_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/3/comments","statuses_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/statuses/affe1d2a78560ea233ea4a82a223498878e94e05","head":{"label":"mongodb:bson_archiver","ref":"bson_archiver","sha":"affe1d2a78560ea233ea4a82a223498878e94e05","user":{"login":"mongodb","id":45120,"avatar_url":"https://avatars.githubusercontent.com/u/45120?v=3","gravatar_id":"","url":"https://api.github.com/users/mongodb","html_url":"https://github.com/mongodb","followers_url":"https://api.github.com/users/mongodb/followers","following_url":"https://api.github.com/users/mongodb/following{/other_user}","gists_url":"https://api.github.com/users/mongodb/gists{/gist_id}","starred_url":"https://api.github.com/users/mongodb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mongodb/subscriptions","organizations_url":"https://api.github.com/users/mongodb/orgs","repos_url":"https://api.github.com/users/mongodb/repos","events_url":"https://api.github.com/users/mongodb/events{/privacy}","received_events_url":"https://api.github.com/users/mongodb/received_events","type":"Organization","site_admin":false},"repo":{"id":60376659,"name":"mongo-cxx-odm","full_name":"mongodb/mongo-cxx-odm","owner":{"login":"mongodb","id":45120,"avatar_url":"https://avatars.githubusercontent.com/u/45120?v=3","gravatar_id":"","url":"https://api.github.com/users/mongodb","html_url":"https://github.com/mongodb","followers_url":"https://api.github.com/users/mongodb/followers","following_url":"https://api.github.com/users/mongodb/following{/other_user}","gists_url":"https://api.github.com/users/mongodb/gists{/gist_id}","starred_url":"https://api.github.com/users/mongodb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mongodb/subscriptions","organizations_url":"https://api.github.com/users/mongodb/orgs","repos_url":"https://api.github.com/users/mongodb/repos","events_url":"https://api.github.com/users/mongodb/events{/privacy}","received_events_url":"https://api.github.com/users/mongodb/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mongodb/mongo-cxx-odm","description":"","fork":false,"url":"https://api.github.com/repos/mongodb/mongo-cxx-odm","forks_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/forks","keys_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/teams","hooks_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/hooks","issue_events_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/events{/number}","events_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/events","assignees_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/assignees{/user}","branches_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/branches{/branch}","tags_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/tags","blobs_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/refs{/sha}","trees_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/statuses/{sha}","languages_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/languages","stargazers_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/stargazers","contributors_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/contributors","subscribers_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/subscribers","subscription_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/subscription","commits_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/commits{/sha}","git_commits_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/commits{/sha}","comments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/comments{/number}","issue_comment_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/comments{/number}","contents_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/contents/{+path}","compare_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/merges","archive_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/downloads","issues_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues{/number}","pulls_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls{/number}","milestones_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/milestones{/number}","notifications_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/labels{/name}","releases_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/releases{/id}","deployments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/deployments","created_at":"2016-06-03T20:45:42Z","updated_at":"2016-06-09T15:35:42Z","pushed_at":"2016-06-20T21:48:21Z","git_url":"git://github.com/mongodb/mongo-cxx-odm.git","ssh_url":"git@github.com:mongodb/mongo-cxx-odm.git","clone_url":"https://github.com/mongodb/mongo-cxx-odm.git","svn_url":"https://github.com/mongodb/mongo-cxx-odm","homepage":null,"size":418,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":1,"default_branch":"master"}},"base":{"label":"mongodb:master","ref":"master","sha":"a3e47b7d13c86d667410e2500f0d5bebdc8c05eb","user":{"login":"mongodb","id":45120,"avatar_url":"https://avatars.githubusercontent.com/u/45120?v=3","gravatar_id":"","url":"https://api.github.com/users/mongodb","html_url":"https://github.com/mongodb","followers_url":"https://api.github.com/users/mongodb/followers","following_url":"https://api.github.com/users/mongodb/following{/other_user}","gists_url":"https://api.github.com/users/mongodb/gists{/gist_id}","starred_url":"https://api.github.com/users/mongodb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mongodb/subscriptions","organizations_url":"https://api.github.com/users/mongodb/orgs","repos_url":"https://api.github.com/users/mongodb/repos","events_url":"https://api.github.com/users/mongodb/events{/privacy}","received_events_url":"https://api.github.com/users/mongodb/received_events","type":"Organization","site_admin":false},"repo":{"id":60376659,"name":"mongo-cxx-odm","full_name":"mongodb/mongo-cxx-odm","owner":{"login":"mongodb","id":45120,"avatar_url":"https://avatars.githubusercontent.com/u/45120?v=3","gravatar_id":"","url":"https://api.github.com/users/mongodb","html_url":"https://github.com/mongodb","followers_url":"https://api.github.com/users/mongodb/followers","following_url":"https://api.github.com/users/mongodb/following{/other_user}","gists_url":"https://api.github.com/users/mongodb/gists{/gist_id}","starred_url":"https://api.github.com/users/mongodb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mongodb/subscriptions","organizations_url":"https://api.github.com/users/mongodb/orgs","repos_url":"https://api.github.com/users/mongodb/repos","events_url":"https://api.github.com/users/mongodb/events{/privacy}","received_events_url":"https://api.github.com/users/mongodb/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mongodb/mongo-cxx-odm","description":"","fork":false,"url":"https://api.github.com/repos/mongodb/mongo-cxx-odm","forks_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/forks","keys_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/teams","hooks_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/hooks","issue_events_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/events{/number}","events_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/events","assignees_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/assignees{/user}","branches_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/branches{/branch}","tags_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/tags","blobs_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/refs{/sha}","trees_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/statuses/{sha}","languages_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/languages","stargazers_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/stargazers","contributors_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/contributors","subscribers_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/subscribers","subscription_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/subscription","commits_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/commits{/sha}","git_commits_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/git/commits{/sha}","comments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/comments{/number}","issue_comment_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/comments{/number}","contents_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/contents/{+path}","compare_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/merges","archive_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/downloads","issues_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues{/number}","pulls_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls{/number}","milestones_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/milestones{/number}","notifications_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/labels{/name}","releases_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/releases{/id}","deployments_url":"https://api.github.com/repos/mongodb/mongo-cxx-odm/deployments","created_at":"2016-06-03T20:45:42Z","updated_at":"2016-06-09T15:35:42Z","pushed_at":"2016-06-20T21:48:21Z","git_url":"git://github.com/mongodb/mongo-cxx-odm.git","ssh_url":"git@github.com:mongodb/mongo-cxx-odm.git","clone_url":"https://github.com/mongodb/mongo-cxx-odm.git","svn_url":"https://github.com/mongodb/mongo-cxx-odm","homepage":null,"size":418,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3"},"html":{"href":"https://github.com/mongodb/mongo-cxx-odm/pull/3"},"issue":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/3"},"comments":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/issues/3/comments"},"review_comments":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3/comments"},"review_comment":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/pulls/3/commits"},"statuses":{"href":"https://api.github.com/repos/mongodb/mongo-cxx-odm/statuses/affe1d2a78560ea233ea4a82a223498878e94e05"}}}}
{"actor":{"display_login":"adamchel"}}