config_loader.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #pragma once
  2. #include <string>
  3. #include <optional>
  4. #include <filesystem>
  5. #include <nlohmann/json.hpp>
  6. #include "common/error.hpp"
  7. namespace smartbotic::config {
  8. class ConfigLoader {
  9. public:
  10. // Load configuration from file
  11. static common::Result<nlohmann::json> loadFromFile(const std::filesystem::path& path);
  12. // Load configuration from string
  13. static common::Result<nlohmann::json> loadFromString(const std::string& content);
  14. // Expand environment variables in JSON values (${VAR:default})
  15. static nlohmann::json expandEnvVars(const nlohmann::json& config);
  16. // Get nested value with dot notation (e.g., "database.host")
  17. static std::optional<nlohmann::json> get(const nlohmann::json& config,
  18. const std::string& path);
  19. // Get value with default
  20. template<typename T>
  21. static T getOr(const nlohmann::json& config, const std::string& path, T defaultValue) {
  22. auto value = get(config, path);
  23. if (value.has_value()) {
  24. try {
  25. return value->get<T>();
  26. } catch (...) {
  27. return defaultValue;
  28. }
  29. }
  30. return defaultValue;
  31. }
  32. // Merge two configurations (second overrides first)
  33. static nlohmann::json merge(const nlohmann::json& base, const nlohmann::json& override);
  34. // Validate config against schema
  35. static common::Result<void> validate(const nlohmann::json& config,
  36. const nlohmann::json& schema);
  37. };
  38. // Configuration holder with typed accessors
  39. class Config {
  40. public:
  41. Config() = default;
  42. explicit Config(nlohmann::json data);
  43. // Load from file
  44. static common::Result<Config> fromFile(const std::filesystem::path& path);
  45. // Raw access
  46. const nlohmann::json& data() const { return data_; }
  47. nlohmann::json& data() { return data_; }
  48. // Get value with path
  49. template<typename T>
  50. std::optional<T> get(const std::string& path) const {
  51. auto value = ConfigLoader::get(data_, path);
  52. if (value.has_value()) {
  53. try {
  54. return value->get<T>();
  55. } catch (...) {
  56. return std::nullopt;
  57. }
  58. }
  59. return std::nullopt;
  60. }
  61. // Get value with default
  62. template<typename T>
  63. T getOr(const std::string& path, T defaultValue) const {
  64. return ConfigLoader::getOr(data_, path, std::move(defaultValue));
  65. }
  66. // Get required value (throws if not found)
  67. template<typename T>
  68. T getRequired(const std::string& path) const {
  69. auto value = get<T>(path);
  70. if (!value.has_value()) {
  71. throw common::SmartBoticException(
  72. common::Error(common::ErrorCode::InvalidArgument,
  73. "Required config value not found: " + path));
  74. }
  75. return *value;
  76. }
  77. // Check if path exists
  78. bool has(const std::string& path) const;
  79. // Reload from file
  80. common::Result<void> reload(const std::filesystem::path& path);
  81. private:
  82. nlohmann::json data_;
  83. };
  84. } // namespace smartbotic::config