diff --git a/src/combinator.cpp b/src/combinator.cpp index 348a663..2fe9178 100644 --- a/src/combinator.cpp +++ b/src/combinator.cpp @@ -26,6 +26,7 @@ #include #include +#include #include using Log = metricq::logger::nitro::Log; @@ -50,45 +51,102 @@ Combinator::~Combinator() { } -std::string displayExpression(const nlohmann::json& expression) { +std::string handleBasicExpression(const nlohmann::json& expression) +{ + if (expression.is_number()) + { + auto value = expression.get(); + return (value == static_cast(value)) ? std::to_string(static_cast(value)) : + std::to_string(value); + } + + if (expression.is_string()) + { + return expression.get(); + } + + throw std::runtime_error("Expression is not a basic type (number or string)!"); +} + +std::string handleOperatorExpression(const std::string& operation, const std::string& leftStr, + const std::string& rightStr) +{ static const std::unordered_set validOperators = { "+", "-", "*", "/" }; - // Check if the expression is a number and return it as a string - if (expression.is_number()) { - double value = expression.get(); - return (value == static_cast(value)) ? std::to_string(static_cast(value)) : std::to_string(value); + if (validOperators.find(operation) == validOperators.end()) + { + throw std::runtime_error("Invalid operator: " + operation); } - if (expression.is_object() && expression.contains("operation")) { - std::string operation = expression.value("operation", ""); + return operation + (leftStr.empty() ? "" : " " + leftStr) + + (rightStr.empty() ? "" : " " + rightStr); +} - // Validate if the operation is supported - if (validOperators.find(operation) == validOperators.end()) { - return operation; - } +std::string handleAggregateExpression(const std::string& operation, + const std::vector& inputs) +{ + static const std::unordered_set validAggregates = { "sum", "min", "max" }; - // Helper lambda to process operands - auto processOperand = [&](const std::string& key) -> std::string { - if (expression.contains(key)) { - const auto& operand = expression[key]; - if (operand.is_string()) return operand.get(); - if (operand.is_number()) return std::to_string(operand.get()); - return displayExpression(operand); - } - return ""; - }; + if (validAggregates.find(operation) == validAggregates.end()) + { + throw std::runtime_error("Invalid aggregate operation: " + operation); + } - std::string leftStr = processOperand("left"); - std::string rightStr = processOperand("right"); - return operation + (leftStr.empty() ? "" : " " + leftStr) + (rightStr.empty() ? "" : " " + rightStr); + if (inputs.empty()) + { + throw std::logic_error("Aggregate operation missing inputs!"); } - // If the expression is a string, return it directly - if (expression.is_string()) { - return expression.get(); + auto input = std::accumulate(std::next(inputs.begin()), inputs.end(), inputs[0], + [](std::string a, const std::string& b) { return a + ", " + b; }); + + return operation + ": [" + input + "]"; +} + +std::string displayExpression(const nlohmann::json& expression) +{ + if (expression.is_number() || expression.is_string()) + { + return handleBasicExpression(expression); + } + + if (!expression.is_object() || !expression.contains("operation")) + { + throw std::runtime_error("Unknown expression format!"); + } + + std::string operation = expression.value("operation", ""); + + if (operation == "throttle") + { + return operation; + } + + if (expression.contains("left") || expression.contains("right")) + { + std::string leftStr = + expression.contains("left") ? displayExpression(expression["left"]) : ""; + std::string rightStr = + expression.contains("right") ? displayExpression(expression["right"]) : ""; + return handleOperatorExpression(operation, leftStr, rightStr); + } + + if (expression.contains("inputs")) + { + if (!expression["inputs"].is_array()) + { + throw std::logic_error("Inputs must be an array!"); + } + + std::vector inputStrings; + for (const auto& input : expression["inputs"]) + { + inputStrings.push_back(displayExpression(input)); + } + return handleAggregateExpression(operation, inputStrings); } - return "Unknown expression format"; + throw std::runtime_error("Unsupported operation type: " + operation); } void Combinator::on_transformer_config(const metricq::json& config)