Skip to content

Commit

Permalink
Added support for getting optional value #33 (#34)
Browse files Browse the repository at this point in the history
* getOptional function added

* getOptional unit test added

* added optional function instances

* code refractor

* review comments

* minor comment
  • Loading branch information
srivastava-yash authored Feb 25, 2024
1 parent 565a052 commit c237c6a
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
18 changes: 18 additions & 0 deletions include/config-cxx/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ class Config
template <typename T>
T get(const std::string& keyPath);

/**
* @brief Get a config value by path if it exists.
*
* @tparam T The target type of config value.
*
* @param path The path to config key.
*
* @return The value of config key casted to provided type or std::nullopt.
*
* @code
* Config().getOptional<std::string>("db.host") // "localhost"
* Config().getOptional<int>("db.port") // 3306
* Config().getOptional<std::string>("redis.host") // std::nullopt
* @endcode
*/
template <typename T>
std::optional<T> getOptional(const std::string& keyPath);

/**
* @brief Get a config value by path.
*
Expand Down
48 changes: 48 additions & 0 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <filesystem>
#include <iostream>
#include <optional>
#include <stdexcept>
#include <variant>

Expand Down Expand Up @@ -56,6 +57,47 @@ T Config::get(const std::string& keyPath)
}
}

template <typename T>
std::optional<T> Config::getOptional(const std::string& keyPath)
{
std::lock_guard<std::mutex> lockGuard(lock);

if (!initialized)
{
initialize();
}

if constexpr (std::is_same_v<T, std::vector<std::string>>)
{
return getArray(keyPath);
}

auto it = values.find(keyPath);
if (it == values.end())
{
return std::nullopt;
}

const auto& value = it->second;

if (value.index() == 0)
{
return std::nullopt;
}

std::optional<T> castedValue = config::cast<T>(value);

if (castedValue)
{
return castedValue.value();
}

else
{
throw std::runtime_error("Config key " + keyPath + " has value of wrong type.");
}
}

ConfigValue Config::get(const std::string& keyPath)
{
std::lock_guard<std::mutex> lockGuard(lock);
Expand Down Expand Up @@ -226,4 +268,10 @@ template bool Config::get<bool>(const std::string&);
template std::string Config::get<std::string>(const std::string&);
template std::vector<std::string> Config::get<std::vector<std::string>>(const std::string&);
template float Config::get<float>(const std::string&);

template std::optional<int> Config::getOptional<int>(const std::string&);
template std::optional<bool> Config::getOptional<bool>(const std::string&);
template std::optional<std::string> Config::getOptional<std::string>(const std::string&);
template std::optional<std::vector<std::string>> Config::getOptional<std::vector<std::string>>(const std::string&);
template std::optional<float> Config::getOptional<float>(const std::string&);
}
35 changes: 34 additions & 1 deletion src/ConfigTest.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "config-cxx/Config.h"

#include <filesystem>
#include <optional>
#include <fstream>
#include <stdexcept>

Expand Down Expand Up @@ -421,4 +422,36 @@ TEST_F(ConfigTest, configWorksWithJsonAndXml)
ASSERT_EQ(authRolesValue, expectedAuthRoles);
ASSERT_EQ(userNameValue, "Koko");
ASSERT_EQ(userActiveValue, false);
}
}

TEST_F(ConfigTest, givenCxxEnvAndConfigDir_returnsOptionalKeyValues)
{
EnvironmentSetter::setEnvironmentVariable("CXX_ENV", "test");
EnvironmentSetter::setEnvironmentVariable("CXX_CONFIG_DIR", testConfigDirectory.string());

const auto awsAccountId = "9999999999";
const auto awsAccountKey = "806223445";

EnvironmentSetter::setEnvironmentVariable("AWS_ACCOUNT_ID", awsAccountId);
EnvironmentSetter::setEnvironmentVariable("AWS_ACCOUNT_KEY", awsAccountKey);

Config config;

const std::string dbHostKey = "db.host";
const std::string dbPortKey = "db.port";
const std::string awsAccountIdKey = "aws.accountId";
const std::string awsAccountKeyKey = "aws.accountKey";
const std::string nonExistantKey = "redis.host";

const auto dbHostValue = config.getOptional<std::string>(dbHostKey);
const auto dbPortValue = config.getOptional<int>(dbPortKey);
const auto awsAccountIdValue = config.getOptional<std::string>(awsAccountIdKey);
const auto awsAccountKeyValue = config.getOptional<std::string>(awsAccountKeyKey);
const auto nonExistantKeyValue = config.getOptional<std::string>(nonExistantKey);

ASSERT_EQ(*dbHostValue, "localhost");
ASSERT_EQ(*dbPortValue, 1996);
ASSERT_EQ(*awsAccountIdValue, awsAccountId);
ASSERT_EQ(*awsAccountKeyValue, awsAccountKey);
ASSERT_EQ(nonExistantKeyValue.has_value(), false);
}

0 comments on commit c237c6a

Please sign in to comment.