| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- #pragma once
- // v1.11 Phase B — binary in-memory document storage.
- //
- // Wraps a yyjson_mut_doc as the canonical Document::data representation,
- // exposing encode/decode/get_field/to_json_text. The yyjson types are
- // forward-declared here so this header does NOT transitively pull in
- // <yyjson.h> — only doc_binary.cpp links against yyjson. Callsites that
- // only need the public surface stay yyjson-agnostic.
- //
- // See docs/superpowers/specs/2026-05-15-binary-doc-format-decision.md for
- // the format-choice rationale and lifecycle contract.
- #include <optional>
- #include <string>
- #include <string_view>
- #include <nlohmann/json.hpp>
- // Forward declarations — keep <yyjson.h> out of the public header.
- struct yyjson_mut_doc;
- struct yyjson_mut_val;
- namespace smartbotic::db::doc_binary {
- // Owning, move-only RAII wrapper around a yyjson_mut_doc*. The destructor
- // calls yyjson_mut_doc_free, so any Doc constructed from a raw pointer takes
- // ownership of that pointer.
- class Doc {
- public:
- Doc() = default;
- explicit Doc(yyjson_mut_doc* doc);
- Doc(Doc&& other) noexcept;
- Doc& operator=(Doc&& other) noexcept;
- // Deep-copy via yyjson_mut_val_mut_copy. Phase B T3 deviation: the
- // decision doc originally listed Doc as move-only, but the surrounding
- // codebase copies Document by value in too many places (vector<Document>
- // returns, query results, replication paths) to refactor safely. Copies
- // are O(size) and allocate a fresh yyjson_mut_doc.
- Doc(const Doc& other);
- Doc& operator=(const Doc& other);
- ~Doc();
- // True if this Doc holds no underlying yyjson document.
- bool empty() const noexcept;
- // Root value of the underlying doc, or nullptr if empty.
- yyjson_mut_val* root() const noexcept;
- // Raw underlying pointer (or nullptr). Caller must not free.
- yyjson_mut_doc* raw() const noexcept;
- private:
- yyjson_mut_doc* doc_ = nullptr;
- };
- // Encode an nlohmann::json tree into a freshly-allocated yyjson mut_doc.
- // Strings are COPIED into yyjson (yyjson_mut_strncpy) so the source can be
- // destroyed safely. Throws std::bad_alloc on yyjson allocator failure.
- Doc encode(const nlohmann::json& j);
- // Decode a Doc back to nlohmann::json (full-tree materialise). Used by the
- // lazy view and any caller that needs full-tree semantics. An empty Doc
- // returns nlohmann::json(nullptr).
- nlohmann::json decode(const Doc& doc);
- // Field-fast-path. Returns nullopt if the field is absent or if the root is
- // not an object. Walks only the immediate children of the root (NOT
- // recursive). For nested access, callers should decode() and walk the
- // resulting nlohmann tree.
- std::optional<nlohmann::json> get_field(const Doc& doc, std::string_view field_name);
- // Serialise the Doc back to compact JSON text. Used at WAL/snapshot write
- // sites and gRPC egress. An empty Doc returns "null".
- std::string to_json_text(const Doc& doc);
- } // namespace smartbotic::db::doc_binary
|