#pragma once #include "IDataNode.h" #include "JsonDataValue.h" #include #include #include #include #include #include namespace grove { using json = nlohmann::json; /** * @brief Concrete implementation of IDataNode backed by JSON * * Represents a node in the hierarchical data tree. Can have: * - Children nodes (map of name -> node) * - Own data (JSON value) * - Path in the tree for identification */ class JsonDataNode : public IDataNode { public: /** * @brief Create a node with name and optional data * @param name Node name * @param data Optional JSON data for this node * @param parent Optional parent node (for path tracking) * @param readOnly Whether this node is read-only (for config/) */ JsonDataNode(const std::string& name, const json& data = json::object(), JsonDataNode* parent = nullptr, bool readOnly = false); virtual ~JsonDataNode() = default; // Tree navigation std::unique_ptr getChild(const std::string& name) override; IDataNode* getChildReadOnly(const std::string& name) override; std::vector getChildNames() override; bool hasChildren() override; bool hasChild(const std::string& name) const override; // Exact search in children std::vector getChildrenByName(const std::string& name) override; bool hasChildrenByName(const std::string& name) const override; IDataNode* getFirstChildByName(const std::string& name) override; // Pattern matching search std::vector getChildrenByNameMatch(const std::string& pattern) override; bool hasChildrenByNameMatch(const std::string& pattern) const override; IDataNode* getFirstChildByNameMatch(const std::string& pattern) override; // Query by properties std::vector queryByProperty(const std::string& propName, const std::function& predicate) override; // Node's own data std::unique_ptr getData() const override; bool hasData() const override; void setData(std::unique_ptr data) override; // Typed data access std::string getString(const std::string& name, const std::string& defaultValue = "") const override; int getInt(const std::string& name, int defaultValue = 0) const override; double getDouble(const std::string& name, double defaultValue = 0.0) const override; bool getBool(const std::string& name, bool defaultValue = false) const override; bool hasProperty(const std::string& name) const override; // Typed data modification void setString(const std::string& name, const std::string& value) override; void setInt(const std::string& name, int value) override; void setDouble(const std::string& name, double value) override; void setBool(const std::string& name, bool value) override; // Hash system std::string getDataHash() override; std::string getTreeHash() override; std::string getSubtreeHash(const std::string& childPath) override; // Metadata std::string getPath() const override; std::string getName() const override; std::string getNodeType() const override; // Tree modification void setChild(const std::string& name, std::unique_ptr node) override; bool removeChild(const std::string& name) override; void clearChildren() override; // Direct JSON access (for internal use by JsonDataTree) const json& getJsonData() const { return m_data; } json& getJsonData() { return m_data; } const std::map>& getChildren() const { return m_children; } private: std::string m_name; json m_data; JsonDataNode* m_parent; bool m_readOnly; std::map> m_children; // Helper methods bool matchesPattern(const std::string& text, const std::string& pattern) const; void collectMatchingNodes(const std::string& pattern, std::vector& results); void collectNodesByProperty(const std::string& propName, const std::function& predicate, std::vector& results); std::string computeHash(const std::string& input) const; void checkReadOnly() const; }; } // namespace grove