From 7d3f05e57602139c957beed34019b58efe29da92 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Tue, 7 Jan 2025 19:10:27 +0000 Subject: [PATCH 01/18] fix: use namespace sqlite_manager to simplify code --- src/agent/command_store/src/command_store.cpp | 74 +++-- .../sqlite_manager/src/sqlite_manager.cpp | 6 +- .../tests/sqlite_manager_test.cpp | 254 +++++++++--------- 3 files changed, 161 insertions(+), 173 deletions(-) diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index e90286f1f3..5b4871a1a5 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -7,6 +7,8 @@ #include +using namespace sqlite_manager; + namespace command_store { constexpr double MILLISECS_IN_A_SEC = 1000.0; @@ -24,15 +26,15 @@ namespace command_store } CommandStore::CommandStore(const std::string& dbFolderPath) - : m_dataBase(std::make_unique(dbFolderPath + "/" + COMMANDSTORE_DB_NAME)) + : m_dataBase(std::make_unique(dbFolderPath + "/" + COMMANDSTORE_DB_NAME)) { - sqlite_manager::Column colId {"id", sqlite_manager::ColumnType::TEXT, true, false, true}; - sqlite_manager::Column colModule {"module", sqlite_manager::ColumnType::TEXT, true, false, false}; - sqlite_manager::Column colCommand {"command", sqlite_manager::ColumnType::TEXT, true, false, false}; - sqlite_manager::Column colParameter {"parameters", sqlite_manager::ColumnType::TEXT, true, false, false}; - sqlite_manager::Column colResult {"result", sqlite_manager::ColumnType::TEXT, true, false, false}; - sqlite_manager::Column colStatus {"status", sqlite_manager::ColumnType::INTEGER, true, false, false}; - sqlite_manager::Column colTime {"time", sqlite_manager::ColumnType::REAL, true, false, false}; + Column colId {"id", ColumnType::TEXT, true, false, true}; + Column colModule {"module", ColumnType::TEXT, true, false, false}; + Column colCommand {"command", ColumnType::TEXT, true, false, false}; + Column colParameter {"parameters", ColumnType::TEXT, true, false, false}; + Column colResult {"result", ColumnType::TEXT, true, false, false}; + Column colStatus {"status", ColumnType::INTEGER, true, false, false}; + Column colTime {"time", ColumnType::REAL, true, false, false}; try { @@ -86,16 +88,15 @@ namespace command_store bool CommandStore::StoreCommand(const module_command::CommandEntry& cmd) { - std::vector fields; - fields.emplace_back("id", sqlite_manager::ColumnType::TEXT, cmd.Id); - fields.emplace_back("module", sqlite_manager::ColumnType::TEXT, cmd.Module); - fields.emplace_back("command", sqlite_manager::ColumnType::TEXT, cmd.Command); - fields.emplace_back("time", sqlite_manager::ColumnType::REAL, std::to_string(GetCurrentTimestampAsReal())); - fields.emplace_back("parameters", sqlite_manager::ColumnType::TEXT, cmd.Parameters.dump()); - fields.emplace_back("result", sqlite_manager::ColumnType::TEXT, cmd.ExecutionResult.Message); - fields.emplace_back("status", - sqlite_manager::ColumnType::INTEGER, - std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + std::vector fields; + fields.emplace_back("id", ColumnType::TEXT, cmd.Id); + fields.emplace_back("module", ColumnType::TEXT, cmd.Module); + fields.emplace_back("command", ColumnType::TEXT, cmd.Command); + fields.emplace_back("time", ColumnType::REAL, std::to_string(GetCurrentTimestampAsReal())); + fields.emplace_back("parameters", ColumnType::TEXT, cmd.Parameters.dump()); + fields.emplace_back("result", ColumnType::TEXT, cmd.ExecutionResult.Message); + fields.emplace_back( + "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); try { m_dataBase->Insert(COMMANDSTORE_TABLE_NAME, fields); @@ -110,8 +111,8 @@ namespace command_store bool CommandStore::DeleteCommand(const std::string& id) { - std::vector fields; - fields.emplace_back("id", sqlite_manager::ColumnType::TEXT, id); + std::vector fields; + fields.emplace_back("id", ColumnType::TEXT, id); try { m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, fields); @@ -128,8 +129,7 @@ namespace command_store { try { - auto cmdData = m_dataBase->Select( - COMMANDSTORE_TABLE_NAME, {}, {sqlite_manager::Column("id", sqlite_manager::ColumnType::TEXT, id)}); + auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, {Column("id", ColumnType::TEXT, id)}); if (cmdData.empty()) { @@ -137,7 +137,7 @@ namespace command_store } module_command::CommandEntry cmd; - for (const sqlite_manager::Column& col : cmdData[0]) + for (const Column& col : cmdData[0]) { if (col.Name == "id") { @@ -182,11 +182,10 @@ namespace command_store { try { - auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, - {}, - {sqlite_manager::Column("status", - sqlite_manager::ColumnType::INTEGER, - std::to_string(static_cast(status)))}); + auto cmdData = + m_dataBase->Select(COMMANDSTORE_TABLE_NAME, + {}, + {Column("status", ColumnType::INTEGER, std::to_string(static_cast(status)))}); if (cmdData.empty()) { @@ -199,7 +198,7 @@ namespace command_store { module_command::CommandEntry cmd; - for (const sqlite_manager::Column& col : row) + for (const Column& col : row) { if (col.Name == "id") { @@ -244,21 +243,20 @@ namespace command_store bool CommandStore::UpdateCommand(const module_command::CommandEntry& cmd) { - std::vector fields; + std::vector fields; if (!cmd.Module.empty()) - fields.emplace_back("module", sqlite_manager::ColumnType::TEXT, cmd.Module); + fields.emplace_back("module", ColumnType::TEXT, cmd.Module); if (!cmd.Command.empty()) - fields.emplace_back("command", sqlite_manager::ColumnType::TEXT, cmd.Command); + fields.emplace_back("command", ColumnType::TEXT, cmd.Command); if (!cmd.Parameters.empty()) - fields.emplace_back("parameters", sqlite_manager::ColumnType::TEXT, cmd.Parameters.dump()); + fields.emplace_back("parameters", ColumnType::TEXT, cmd.Parameters.dump()); if (!cmd.ExecutionResult.Message.empty()) - fields.emplace_back("result", sqlite_manager::ColumnType::TEXT, cmd.ExecutionResult.Message); + fields.emplace_back("result", ColumnType::TEXT, cmd.ExecutionResult.Message); if (cmd.ExecutionResult.ErrorCode != module_command::Status::UNKNOWN) - fields.emplace_back("status", - sqlite_manager::ColumnType::INTEGER, - std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + fields.emplace_back( + "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); - sqlite_manager::Column condition("id", sqlite_manager::ColumnType::TEXT, cmd.Id); + Column condition("id", ColumnType::TEXT, cmd.Id); try { m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, {condition}); diff --git a/src/agent/sqlite_manager/src/sqlite_manager.cpp b/src/agent/sqlite_manager/src/sqlite_manager.cpp index f2b592350e..2aaf0bd52b 100644 --- a/src/agent/sqlite_manager/src/sqlite_manager.cpp +++ b/src/agent/sqlite_manager/src/sqlite_manager.cpp @@ -167,9 +167,9 @@ namespace sqlite_manager queryFields.reserve(static_cast(nColumns)); for (int i = 0; i < nColumns; i++) { - sqlite_manager::Column field(query.getColumn(i).getName(), - ColumnTypeFromSQLiteType(query.getColumn(i).getType()), - query.getColumn(i).getString()); + Column field(query.getColumn(i).getName(), + ColumnTypeFromSQLiteType(query.getColumn(i).getType()), + query.getColumn(i).getString()); queryFields.push_back(field); } results.push_back(queryFields); diff --git a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp index ddb1a303e8..222a144962 100644 --- a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp +++ b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp @@ -6,102 +6,101 @@ #include #include +using namespace sqlite_manager; + class SQLiteManagerTest : public ::testing::Test { protected: const std::string m_dbName = "testdb.db"; const std::string m_tableName = "TestTable"; - std::unique_ptr m_db; + std::unique_ptr m_db; void SetUp() override { - m_db = std::make_unique(m_dbName); + m_db = std::make_unique(m_dbName); } void TearDown() override {} void AddTestData() { - - using namespace sqlite_manager; EXPECT_NO_THROW(m_db->Remove(m_tableName)); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus")}); - m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "MyTestValue")}); - m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus2")}); + {Column("Name", ColumnType::TEXT, "ItemName"), Column("Status", ColumnType::TEXT, "ItemStatus")}); + m_db->Insert( + m_tableName, + {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); + m_db->Insert( + m_tableName, + {Column("Name", ColumnType::TEXT, "ItemName2"), Column("Status", ColumnType::TEXT, "ItemStatus2")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName3"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus3"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule3")}); + {Column("Name", ColumnType::TEXT, "ItemName3"), + Column("Status", ColumnType::TEXT, "ItemStatus3"), + Column("Module", ColumnType::TEXT, "ItemModule3")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName4"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus4"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule4"), - sqlite_manager::Column("Orden", sqlite_manager::ColumnType::INTEGER, "19"), - sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "2.8")}); + {Column("Name", ColumnType::TEXT, "ItemName4"), + Column("Status", ColumnType::TEXT, "ItemStatus4"), + Column("Module", ColumnType::TEXT, "ItemModule4"), + Column("Orden", ColumnType::INTEGER, "19"), + Column("Amount", ColumnType::REAL, "2.8")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName5"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus5"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule5"), - sqlite_manager::Column("Orden", sqlite_manager::ColumnType::INTEGER, "21"), - sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "3.5")}); + {Column("Name", ColumnType::TEXT, "ItemName5"), + Column("Status", ColumnType::TEXT, "ItemStatus5"), + Column("Module", ColumnType::TEXT, "ItemModule5"), + Column("Orden", ColumnType::INTEGER, "21"), + Column("Amount", ColumnType::REAL, "3.5")}); } }; TEST_F(SQLiteManagerTest, CreateTableTest) { - sqlite_manager::Column col1 {"Id", sqlite_manager::ColumnType::INTEGER, true, true, true}; - sqlite_manager::Column col2 {"Name", sqlite_manager::ColumnType::TEXT, true, false, false}; - sqlite_manager::Column col3 {"Status", sqlite_manager::ColumnType::TEXT, true, false}; - sqlite_manager::Column col4 {"Module", sqlite_manager::ColumnType::TEXT, false, false}; - sqlite_manager::Column col5 {"Orden", sqlite_manager::ColumnType::INTEGER, false, false, false}; - sqlite_manager::Column col6 {"Amount", sqlite_manager::ColumnType::REAL, false, false, false}; + Column col1 {"Id", ColumnType::INTEGER, true, true, true}; + Column col2 {"Name", ColumnType::TEXT, true, false, false}; + Column col3 {"Status", ColumnType::TEXT, true, false}; + Column col4 {"Module", ColumnType::TEXT, false, false}; + Column col5 {"Orden", ColumnType::INTEGER, false, false, false}; + Column col6 {"Amount", ColumnType::REAL, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable(m_tableName, {col1, col2, col3, col4, col5, col6})); EXPECT_TRUE(m_db->TableExists(m_tableName)); - sqlite_manager::Column col21 {"Id", sqlite_manager::ColumnType::INTEGER, true, false, true}; - sqlite_manager::Column col212 {"Id2", sqlite_manager::ColumnType::INTEGER, true, false, true}; - sqlite_manager::Column col22 {"Name", sqlite_manager::ColumnType::TEXT, true, false, true}; - sqlite_manager::Column col23 {"Status", sqlite_manager::ColumnType::TEXT, true, false}; - sqlite_manager::Column col24 {"Module", sqlite_manager::ColumnType::TEXT, false, false}; - sqlite_manager::Column col25 {"Orden", sqlite_manager::ColumnType::INTEGER, false, false, false}; - sqlite_manager::Column col26 {"Amount", sqlite_manager::ColumnType::REAL, false, false, false}; + Column col21 {"Id", ColumnType::INTEGER, true, false, true}; + Column col212 {"Id2", ColumnType::INTEGER, true, false, true}; + Column col22 {"Name", ColumnType::TEXT, true, false, true}; + Column col23 {"Status", ColumnType::TEXT, true, false}; + Column col24 {"Module", ColumnType::TEXT, false, false}; + Column col25 {"Orden", ColumnType::INTEGER, false, false, false}; + Column col26 {"Amount", ColumnType::REAL, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable("TableTest2", {col21, col212, col22, col23, col24, col25, col26})); EXPECT_TRUE(m_db->TableExists("TableTest2")); } TEST_F(SQLiteManagerTest, InsertTest) { - sqlite_manager::Column col1 {"Name", sqlite_manager::ColumnType::TEXT, "ItemName1"}; - sqlite_manager::Column col2 {"Status", sqlite_manager::ColumnType::TEXT, "ItemStatus1"}; + Column col1 {"Name", ColumnType::TEXT, "ItemName1"}; + Column col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; EXPECT_NO_THROW(m_db->Insert(m_tableName, {col1, col2})); + EXPECT_NO_THROW(m_db->Insert( + m_tableName, + {Column("Name", ColumnType::TEXT, "ItemName2"), Column("Status", ColumnType::TEXT, "ItemStatus2")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus2")})); - EXPECT_NO_THROW(m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName3"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus3"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule3")})); + {Column("Name", ColumnType::TEXT, "ItemName3"), + Column("Status", ColumnType::TEXT, "ItemStatus3"), + Column("Module", ColumnType::TEXT, "ItemModule3")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName4"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus4"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule4"), - sqlite_manager::Column("Orden", sqlite_manager::ColumnType::INTEGER, "16")})); + {Column("Name", ColumnType::TEXT, "ItemName4"), + Column("Status", ColumnType::TEXT, "ItemStatus4"), + Column("Module", ColumnType::TEXT, "ItemModule4"), + Column("Orden", ColumnType::INTEGER, "16")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "ItemName4"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus4"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule4"), - sqlite_manager::Column("Orden", sqlite_manager::ColumnType::INTEGER, "16"), - sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "4.5")})); + {Column("Name", ColumnType::TEXT, "ItemName4"), + Column("Status", ColumnType::TEXT, "ItemStatus4"), + Column("Module", ColumnType::TEXT, "ItemModule4"), + Column("Orden", ColumnType::INTEGER, "16"), + Column("Amount", ColumnType::REAL, "4.5")})); } TEST_F(SQLiteManagerTest, GetCountTest) @@ -110,8 +109,8 @@ TEST_F(SQLiteManagerTest, GetCountTest) int count = m_db->GetCount(m_tableName); EXPECT_EQ(count, 0); - sqlite_manager::Column col1 {"Name", sqlite_manager::ColumnType::TEXT, "ItemName1"}; - sqlite_manager::Column col2 {"Status", sqlite_manager::ColumnType::TEXT, "ItemStatus1"}; + Column col1 {"Name", ColumnType::TEXT, "ItemName1"}; + Column col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; EXPECT_NO_THROW(m_db->Insert(m_tableName, {col1, col2})); count = m_db->GetCount(m_tableName); @@ -123,7 +122,7 @@ TEST_F(SQLiteManagerTest, GetCountTest) EXPECT_EQ(count, 2); } -static void DumpResults(std::vector& ret) +static void DumpResults(std::vector& ret) { std::cout << "---------- " << ret.size() << " rows returned. ----------" << '\n'; for (const auto& row : ret) @@ -140,36 +139,36 @@ TEST_F(SQLiteManagerTest, SelectTest) { AddTestData(); - std::vector cols; + std::vector cols; // all fields, no selection criteria - std::vector ret = m_db->Select(m_tableName, cols); + std::vector ret = m_db->Select(m_tableName, cols); DumpResults(ret); EXPECT_NE(ret.size(), 0); // all fields with default selection criteria - ret = m_db->Select(m_tableName, - cols, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "MyTestValue")}); + ret = m_db->Select( + m_tableName, + cols, + {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); DumpResults(ret); EXPECT_NE(ret.size(), 0); // all fields with 'OR' selection criteria - ret = m_db->Select(m_tableName, - cols, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"), - sqlite_manager::Column("Module", sqlite_manager::ColumnType::TEXT, "ItemModule5")}, - sqlite_manager::LogicalOperator::OR); + ret = m_db->Select( + m_tableName, + cols, + {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Module", ColumnType::TEXT, "ItemModule5")}, + LogicalOperator::OR); DumpResults(ret); EXPECT_EQ(ret.size(), 2); // only Name field no selection criteria cols.clear(); - cols.emplace_back("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); ret.clear(); ret = m_db->Select(m_tableName, cols); @@ -178,31 +177,31 @@ TEST_F(SQLiteManagerTest, SelectTest) // only Name field with default selection criteria cols.clear(); - cols.emplace_back("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); ret.clear(); - ret = m_db->Select(m_tableName, - cols, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "MyTestValue")}); + ret = m_db->Select( + m_tableName, + cols, + {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); DumpResults(ret); EXPECT_NE(ret.size(), 0); // only Name field with single selection criteria cols.clear(); - cols.emplace_back("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); ret.clear(); - ret = m_db->Select(m_tableName, cols, {sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "3.5")}); + ret = m_db->Select(m_tableName, cols, {Column("Amount", ColumnType::REAL, "3.5")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); // only Name and Amount fields with single selection criteria cols.clear(); - cols.emplace_back("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"); - cols.emplace_back("Amount", sqlite_manager::ColumnType::REAL, "Amount"); + cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Amount", ColumnType::REAL, "Amount"); ret.clear(); - ret = m_db->Select(m_tableName, cols, {sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "2.8")}); + ret = m_db->Select(m_tableName, cols, {Column("Amount", ColumnType::REAL, "2.8")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); @@ -215,9 +214,9 @@ TEST_F(SQLiteManagerTest, RemoveTest) int initialCount = m_db->GetCount(m_tableName); // Remove a single record - EXPECT_NO_THROW(m_db->Remove(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "MyTestValue")})); + EXPECT_NO_THROW(m_db->Remove( + m_tableName, + {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")})); int count = m_db->GetCount(m_tableName); EXPECT_EQ(count, initialCount - 1); @@ -230,49 +229,43 @@ TEST_F(SQLiteManagerTest, RemoveTest) TEST_F(SQLiteManagerTest, UpdateTest) { AddTestData(); - EXPECT_NO_THROW(m_db->Update(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "Updated status")}, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "MyTestName")})); + EXPECT_NO_THROW(m_db->Update( + m_tableName, + {Column("Name", ColumnType::TEXT, "Updated name"), Column("Status", ColumnType::TEXT, "Updated status")}, + {Column("Name", ColumnType::TEXT, "MyTestName")})); - auto ret = m_db->Select( - m_tableName, {}, {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name")}); + auto ret = m_db->Select(m_tableName, {}, {Column("Name", ColumnType::TEXT, "Updated name")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); - EXPECT_NO_THROW( - m_db->Update(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "Updated status2")}, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "Updated status")})); + EXPECT_NO_THROW(m_db->Update( + m_tableName, + {Column("Name", ColumnType::TEXT, "Updated name2"), Column("Status", ColumnType::TEXT, "Updated status2")}, + {Column("Name", ColumnType::TEXT, "Updated name"), Column("Status", ColumnType::TEXT, "Updated status")})); - ret = m_db->Select( - m_tableName, {}, {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name2")}); + ret = m_db->Select(m_tableName, {}, {Column("Name", ColumnType::TEXT, "Updated name2")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); - EXPECT_NO_THROW( - m_db->Update(m_tableName, - {sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "2.0")}, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "Updated name2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus3"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "Updated status3")}, - sqlite_manager::LogicalOperator::OR)); + EXPECT_NO_THROW(m_db->Update(m_tableName, + {Column("Amount", ColumnType::REAL, "2.0")}, + {Column("Name", ColumnType::TEXT, "Updated name2"), + Column("Status", ColumnType::TEXT, "ItemStatus3"), + Column("Status", ColumnType::TEXT, "Updated status3")}, + LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); EXPECT_NO_THROW(m_db->Update(m_tableName, - {sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "2.0")}, - {sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "ItemStatus3")}, - sqlite_manager::LogicalOperator::OR)); + {Column("Amount", ColumnType::REAL, "2.0")}, + {Column("Status", ColumnType::TEXT, "ItemStatus3")}, + LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); - EXPECT_NO_THROW( - m_db->Update(m_tableName, {sqlite_manager::Column("Amount", sqlite_manager::ColumnType::REAL, "2.0")}, {})); + EXPECT_NO_THROW(m_db->Update(m_tableName, {Column("Amount", ColumnType::REAL, "2.0")}, {})); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); @@ -284,18 +277,17 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus")}); + {Column("Name", ColumnType::TEXT, "TransactionName"), + Column("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + {Column("Name", ColumnType::TEXT, "TransactionName2"), + Column("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_NO_THROW(m_db->RollbackTransaction(transaction)); } // since we rolled back the transaction we should find nothing - auto ret = m_db->Select( - m_tableName, {}, {sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + auto ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 0); @@ -303,17 +295,16 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus")}); + {Column("Name", ColumnType::TEXT, "TransactionName"), + Column("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + {Column("Name", ColumnType::TEXT, "TransactionName2"), + Column("Status", ColumnType::TEXT, "TransactionStatus2")}); } // since transaction obejct ran out of scope without being committed we should find nothing - ret = m_db->Select( - m_tableName, {}, {sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 0); @@ -321,29 +312,28 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus")}); + {Column("Name", ColumnType::TEXT, "TransactionName"), + Column("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {sqlite_manager::Column("Name", sqlite_manager::ColumnType::TEXT, "TransactionName2"), - sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + {Column("Name", ColumnType::TEXT, "TransactionName2"), + Column("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_NO_THROW(m_db->CommitTransaction(transaction)); } // since we commited the transaction we should find something - ret = m_db->Select( - m_tableName, {}, {sqlite_manager::Column("Status", sqlite_manager::ColumnType::TEXT, "TransactionStatus2")}); + ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 1); } TEST_F(SQLiteManagerTest, DropTableTest) { - sqlite_manager::Column col1 {"Id", sqlite_manager::ColumnType::INTEGER, true, true, true}; - sqlite_manager::Column col2 {"Name", sqlite_manager::ColumnType::TEXT, true, false}; - sqlite_manager::Column col3 {"Status", sqlite_manager::ColumnType::TEXT, true, false}; - sqlite_manager::Column col4 {"Module", sqlite_manager::ColumnType::TEXT, false, false}; - sqlite_manager::Column col5 {"Orden", sqlite_manager::ColumnType::INTEGER, false, false, false}; + Column col1 {"Id", ColumnType::INTEGER, true, true, true}; + Column col2 {"Name", ColumnType::TEXT, true, false}; + Column col3 {"Status", ColumnType::TEXT, true, false}; + Column col4 {"Module", ColumnType::TEXT, false, false}; + Column col5 {"Orden", ColumnType::INTEGER, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable("DropMe", {col1, col2, col3, col4, col5})); EXPECT_TRUE(m_db->TableExists("DropMe")); From b36eadb33a0ca5a9dba48efa323a4de473827fec Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Tue, 7 Jan 2025 20:23:17 +0000 Subject: [PATCH 02/18] fix: improve command store operations --- src/agent/command_store/src/command_store.cpp | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index 5b4871a1a5..c57d4ff40c 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -26,24 +26,38 @@ namespace command_store } CommandStore::CommandStore(const std::string& dbFolderPath) - : m_dataBase(std::make_unique(dbFolderPath + "/" + COMMANDSTORE_DB_NAME)) { - Column colId {"id", ColumnType::TEXT, true, false, true}; - Column colModule {"module", ColumnType::TEXT, true, false, false}; - Column colCommand {"command", ColumnType::TEXT, true, false, false}; - Column colParameter {"parameters", ColumnType::TEXT, true, false, false}; - Column colResult {"result", ColumnType::TEXT, true, false, false}; - Column colStatus {"status", ColumnType::INTEGER, true, false, false}; - Column colTime {"time", ColumnType::REAL, true, false, false}; + const auto dbFilePath = dbFolderPath + "/" + COMMANDSTORE_DB_NAME; try { - m_dataBase->CreateTable(COMMANDSTORE_TABLE_NAME, - {colId, colModule, colCommand, colParameter, colResult, colStatus, colTime}); + m_dataBase = std::make_unique(dbFilePath); + + if (!m_dataBase->TableExists(COMMANDSTORE_TABLE_NAME)) + { + std::vector columns; + columns.emplace_back("id", ColumnType::TEXT, true, false, true); + columns.emplace_back("module", ColumnType::TEXT, true, false, false); + columns.emplace_back("command", ColumnType::TEXT, true, false, false); + columns.emplace_back("parameters", ColumnType::TEXT, true, false, false); + columns.emplace_back("result", ColumnType::TEXT, true, false, false); + columns.emplace_back("status", ColumnType::INTEGER, true, false, false); + columns.emplace_back("time", ColumnType::REAL, true, false, false); + + try + { + m_dataBase->CreateTable(COMMANDSTORE_TABLE_NAME, columns); + } + catch (std::exception& e) + { + LogError("CreateTable operation failed: {}.", e.what()); + } + } } - catch (std::exception& e) + + catch (const std::exception&) { - LogError("CreateTable operation failed: {}.", e.what()); + throw std::runtime_error(std::string("Cannot open database: " + dbFilePath)); } } @@ -111,11 +125,9 @@ namespace command_store bool CommandStore::DeleteCommand(const std::string& id) { - std::vector fields; - fields.emplace_back("id", ColumnType::TEXT, id); try { - m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, fields); + m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, {Column("id", ColumnType::TEXT, id)}); } catch (const std::exception& e) { @@ -256,10 +268,9 @@ namespace command_store fields.emplace_back( "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); - Column condition("id", ColumnType::TEXT, cmd.Id); try { - m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, {condition}); + m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, {Column("id", ColumnType::TEXT, cmd.Id)}); } catch (const std::exception& e) { From 8b6ef8502afb65c0552613814d499020d5fe4bd6 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Wed, 8 Jan 2025 19:36:43 +0000 Subject: [PATCH 03/18] fix: improve sqlite manager function, mutex usage, columns improvement --- .../agent_info/src/agent_info_persistance.cpp | 24 +- src/agent/command_store/src/command_store.cpp | 36 ++- src/agent/sqlite_manager/include/column.hpp | 89 +++++++ .../sqlite_manager/include/sqlite_manager.hpp | 142 +++-------- .../sqlite_manager/src/sqlite_manager.cpp | 240 +++++++++--------- .../tests/sqlite_manager_test.cpp | 198 ++++++++------- 6 files changed, 390 insertions(+), 339 deletions(-) create mode 100644 src/agent/sqlite_manager/include/column.hpp diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 12874b8b9f..ad9e4123d7 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -60,9 +60,9 @@ void AgentInfoPersistance::CreateAgentInfoTable() { try { - const std::vector columns = {Column("name", ColumnType::TEXT, true, false), - Column("key", ColumnType::TEXT, true, false), - Column("uuid", ColumnType::TEXT, true, false, true)}; + const std::vector columns = {ColumnKey("name", ColumnType::TEXT, true, false), + ColumnKey("key", ColumnType::TEXT, true, false), + ColumnKey("uuid", ColumnType::TEXT, true, false, true)}; m_db->CreateTable(AGENT_INFO_TABLE_NAME, columns); } @@ -76,8 +76,8 @@ void AgentInfoPersistance::CreateAgentGroupTable() { try { - const std::vector columns = {Column("id", ColumnType::INTEGER, true, true, true), - Column("name", ColumnType::TEXT, true, false)}; + const std::vector columns = {ColumnKey("id", ColumnType::INTEGER, true, true, true), + ColumnKey("name", ColumnType::TEXT, true, false)}; m_db->CreateTable(AGENT_GROUP_TABLE_NAME, columns); } @@ -95,9 +95,9 @@ void AgentInfoPersistance::InsertDefaultAgentInfo() if (count == 0) { - const std::vector columns = {Column("name", ColumnType::TEXT, ""), - Column("key", ColumnType::TEXT, ""), - Column("uuid", ColumnType::TEXT, "")}; + const Row columns = {ColumnValue("name", ColumnType::TEXT, ""), + ColumnValue("key", ColumnType::TEXT, ""), + ColumnValue("uuid", ColumnType::TEXT, "")}; m_db->Insert(AGENT_INFO_TABLE_NAME, columns); } @@ -112,7 +112,7 @@ void AgentInfoPersistance::SetAgentInfoValue(const std::string& column, const st { try { - const std::vector columns = {Column(column, ColumnType::TEXT, value)}; + const Row columns = {ColumnValue(column, ColumnType::TEXT, value)}; m_db->Update(AGENT_INFO_TABLE_NAME, columns); } catch (const std::exception& e) @@ -127,7 +127,7 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c try { - const std::vector columns = {Column(column, ColumnType::TEXT, "")}; + const std::vector columns = {ColumnName(column, ColumnType::TEXT)}; const std::vector results = m_db->Select(AGENT_INFO_TABLE_NAME, columns); if (!results.empty() && !results[0].empty()) @@ -164,7 +164,7 @@ std::vector AgentInfoPersistance::GetGroups() const try { - const std::vector columns = {Column("name", ColumnType::TEXT, "")}; + const std::vector columns = {ColumnName("name", ColumnType::TEXT)}; const std::vector results = m_db->Select(AGENT_GROUP_TABLE_NAME, columns); for (const auto& row : results) @@ -208,7 +208,7 @@ bool AgentInfoPersistance::SetGroups(const std::vector& groupList) for (const auto& group : groupList) { - const std::vector columns = {Column("name", ColumnType::TEXT, group)}; + const Row columns = {ColumnValue("name", ColumnType::TEXT, group)}; m_db->Insert(AGENT_GROUP_TABLE_NAME, columns); } diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index c57d4ff40c..0e8b0af4f6 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -35,7 +35,7 @@ namespace command_store if (!m_dataBase->TableExists(COMMANDSTORE_TABLE_NAME)) { - std::vector columns; + std::vector columns; columns.emplace_back("id", ColumnType::TEXT, true, false, true); columns.emplace_back("module", ColumnType::TEXT, true, false, false); columns.emplace_back("command", ColumnType::TEXT, true, false, false); @@ -78,6 +78,7 @@ namespace command_store int CommandStore::GetCount() { int count = 0; + try { count = m_dataBase->GetCount(COMMANDSTORE_TABLE_NAME); @@ -86,7 +87,6 @@ namespace command_store { LogError("GetCount operation failed: {}.", e.what()); } - return count; } @@ -102,7 +102,7 @@ namespace command_store bool CommandStore::StoreCommand(const module_command::CommandEntry& cmd) { - std::vector fields; + Row fields; fields.emplace_back("id", ColumnType::TEXT, cmd.Id); fields.emplace_back("module", ColumnType::TEXT, cmd.Module); fields.emplace_back("command", ColumnType::TEXT, cmd.Command); @@ -111,6 +111,7 @@ namespace command_store fields.emplace_back("result", ColumnType::TEXT, cmd.ExecutionResult.Message); fields.emplace_back( "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + try { m_dataBase->Insert(COMMANDSTORE_TABLE_NAME, fields); @@ -125,9 +126,12 @@ namespace command_store bool CommandStore::DeleteCommand(const std::string& id) { + Criteria filters; + filters.emplace_back("id", ColumnType::TEXT, id); + try { - m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, {Column("id", ColumnType::TEXT, id)}); + m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, filters); } catch (const std::exception& e) { @@ -139,9 +143,12 @@ namespace command_store std::optional CommandStore::GetCommand(const std::string& id) { + Criteria filters; + filters.emplace_back("id", ColumnType::TEXT, id); + try { - auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, {Column("id", ColumnType::TEXT, id)}); + auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, filters); if (cmdData.empty()) { @@ -149,7 +156,7 @@ namespace command_store } module_command::CommandEntry cmd; - for (const Column& col : cmdData[0]) + for (const auto& col : cmdData[0]) { if (col.Name == "id") { @@ -192,12 +199,12 @@ namespace command_store std::optional> CommandStore::GetCommandByStatus(const module_command::Status& status) { + Criteria filters; + filters.emplace_back("status", ColumnType::INTEGER, std::to_string(static_cast(status))); + try { - auto cmdData = - m_dataBase->Select(COMMANDSTORE_TABLE_NAME, - {}, - {Column("status", ColumnType::INTEGER, std::to_string(static_cast(status)))}); + auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, filters); if (cmdData.empty()) { @@ -210,7 +217,7 @@ namespace command_store { module_command::CommandEntry cmd; - for (const Column& col : row) + for (const auto& col : row) { if (col.Name == "id") { @@ -255,7 +262,7 @@ namespace command_store bool CommandStore::UpdateCommand(const module_command::CommandEntry& cmd) { - std::vector fields; + Row fields; if (!cmd.Module.empty()) fields.emplace_back("module", ColumnType::TEXT, cmd.Module); if (!cmd.Command.empty()) @@ -268,9 +275,12 @@ namespace command_store fields.emplace_back( "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + Criteria filters; + filters.emplace_back("id", ColumnType::TEXT, cmd.Id); + try { - m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, {Column("id", ColumnType::TEXT, cmd.Id)}); + m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, filters); } catch (const std::exception& e) { diff --git a/src/agent/sqlite_manager/include/column.hpp b/src/agent/sqlite_manager/include/column.hpp new file mode 100644 index 0000000000..dab5215331 --- /dev/null +++ b/src/agent/sqlite_manager/include/column.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include +#include + +/// @brief Logical operators for combining selection criteria in queries. +enum class LogicalOperator +{ + AND, + OR +}; + +/// @brief Supported column data types for SQLite tables. +enum class ColumnType +{ + INTEGER, + TEXT, + REAL +}; + +/// @brief Represents a database column. +class ColumnName +{ +public: + /// @brief Constructor for defining a table column. + /// @param name The name of the column. + /// @param type The data type of the column (INTEGER, TEXT, or REAL). + ColumnName(std::string name, const ColumnType type) + : Name(std::move(name)) + , Type(type) + { + } + + /// @brief The name of the column + std::string Name; + + /// @brief The type of the column + ColumnType Type; +}; + +/// @brief Represents a database column with attributes. +class ColumnKey : public ColumnName +{ +public: + /// @brief Constructor for defining a table column with attributes. + /// @param name The name of the column. + /// @param type The data type of the column (INTEGER, TEXT, or REAL). + /// @param notNull Whether the column has a NOT NULL constraint. + /// @param autoIncr Whether the column is AUTOINCREMENT (relevant for primary keys). + /// @param primary Whether the column is part of the primary key. + ColumnKey( + std::string name, const ColumnType type, const bool notNull, const bool autoIncr, const bool primary = false) + : ColumnName(std::move(name), type) + , NotNull(notNull) + , AutoIncrement(autoIncr) + , PrimaryKey(primary) + { + } + + /// @brief Whether the column can contain NULL values + bool NotNull; + + /// @brief Whether the column is an auto-incrementing primary key + bool AutoIncrement; + + /// @brief Whether the column is a primary key + bool PrimaryKey; +}; + +/// @brief Represents a database column with data. +class ColumnValue : public ColumnName +{ +public: + /// @brief Constructor for defining a column with a specific value. + /// @param name The name of the column. + /// @param type The data type of the column. + /// @param value The value of the column. + ColumnValue(std::string name, const ColumnType type, std::string value) + : ColumnName(std::move(name), type) + , Value(std::move(value)) + { + } + + /// @brief The value of the column as a string + std::string Value; +}; + +using Row = std::vector; +using Criteria = std::vector; diff --git a/src/agent/sqlite_manager/include/sqlite_manager.hpp b/src/agent/sqlite_manager/include/sqlite_manager.hpp index a9c74a2a97..fc77c8c69c 100644 --- a/src/agent/sqlite_manager/include/sqlite_manager.hpp +++ b/src/agent/sqlite_manager/include/sqlite_manager.hpp @@ -2,6 +2,8 @@ #include +#include "column.hpp" + #include #include #include @@ -9,76 +11,6 @@ namespace sqlite_manager { - /// @brief Logical operators for combining selection criteria in queries. - enum class LogicalOperator - { - AND, - OR - }; - - /// @brief Supported column data types for SQLite tables. - enum class ColumnType - { - INTEGER, - TEXT, - REAL - }; - - /// @brief Represents a database column with attributes for table creation and data insertion. - class Column - { - public: - /// @brief Constructor for defining a table column with attributes. - /// @param name The name of the column. - /// @param type The data type of the column (INTEGER, TEXT, or REAL). - /// @param notNull Whether the column has a NOT NULL constraint. - /// @param autoIncr Whether the column is AUTOINCREMENT (relevant for primary keys). - /// @param primary Whether the column is part of the primary key. - Column(std::string name, - const ColumnType type, - const bool notNull, - const bool autoIncr, - const bool primary = false) - : Name(std::move(name)) - , Type(type) - , NotNull(notNull) - , AutoIncrement(autoIncr) - , PrimaryKey(primary) - { - } - - /// @brief Constructor for defining a column with a specific value for insertion. - /// @param name The name of the column. - /// @param type The data type of the column. - /// @param value The value to insert. - Column(std::string name, const ColumnType type, std::string value) - : Name(std::move(name)) - , Type(type) - , Value(std::move(value)) - { - } - - /// @brief The name of the column - std::string Name; - - /// @brief The type of the column - ColumnType Type; - - /// @brief Whether the column can contain NULL values - bool NotNull; - - /// @brief Whether the column is an auto-incrementing primary key - bool AutoIncrement; - - /// @brief Whether the column is a primary key - bool PrimaryKey; - - /// @brief The value of the column as a string - std::string Value; - }; - - using Row = std::vector; - /// @brief Manages SQLite database operations, including table creation, data insertion, updating, and selection. class SQLiteManager { @@ -87,44 +19,20 @@ namespace sqlite_manager /// @param dbName The name of the SQLite database file. SQLiteManager(const std::string& dbName); - /// @brief Creates a new table with specified columns if it doesn't already exist. - /// @param tableName The name of the table to create. - /// @param cols A vector of columns specifying the table schema. - void CreateTable(const std::string& tableName, const std::vector& cols); - /// @brief Checks if a specified table exists in the database. /// @param tableName The name of the table to check. /// @return True if the table exists, false otherwise. - bool TableExists(const std::string& tableName) const; + bool TableExists(const std::string& tableName); + + /// @brief Creates a new table with specified columns if it doesn't already exist. + /// @param tableName The name of the table to create. + /// @param cols A vector of columns specifying the table schema. + void CreateTable(const std::string& tableName, const std::vector& cols); /// @brief Inserts data into a specified table. /// @param tableName The name of the table where data is inserted. /// @param cols A vector of columns with values to insert. - void Insert(const std::string& tableName, const std::vector& cols); - - /// @brief Retrieves the number of rows in a specified table. - /// @param tableName The name of the table to count rows in. - /// @return The number of rows in the table. - int GetCount(const std::string& tableName); - - /// @brief Selects rows from a specified table with optional criteria. - /// @param tableName The name of the table to select from. - /// @param fields A vector of columns to retrieve. - /// @param selCriteria Optional selection criteria to filter rows. - /// @param logOp Logical operator to combine selection criteria (AND/OR). - /// @return A vector of rows matching the criteria. - std::vector Select(const std::string& tableName, - const std::vector& fields, - const std::vector& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); - - /// @brief Removes rows from a specified table with optional criteria. - /// @param tableName The name of the table to delete from. - /// @param selCriteria Optional criteria to filter rows to delete. - /// @param logOp Logical operator to combine selection criteria. - void Remove(const std::string& tableName, - const std::vector& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); + void Insert(const std::string& tableName, const Row& cols); /// @brief Updates rows in a specified table with optional criteria. /// @param tableName The name of the table to update. @@ -132,14 +40,42 @@ namespace sqlite_manager /// @param selCriteria Optional criteria to filter rows to update. /// @param logOp Logical operator to combine selection criteria. void Update(const std::string& tableName, - const std::vector& fields, - const std::vector& selCriteria = {}, + const Row& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND); + + /// @brief Removes rows from a specified table with optional criteria. + /// @param tableName The name of the table to delete from. + /// @param selCriteria Optional criteria to filter rows to delete. + /// @param logOp Logical operator to combine selection criteria. + void Remove(const std::string& tableName, + const Criteria& selCriteria = {}, LogicalOperator logOp = LogicalOperator::AND); /// @brief Drops a specified table from the database. /// @param tableName The name of the table to drop. void DropTable(const std::string& tableName); + /// @brief Selects rows from a specified table with optional criteria. + /// @param tableName The name of the table to select from. + /// @param fields A vector of columns to retrieve. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @return A vector of rows matching the criteria. + std::vector Select(const std::string& tableName, + const std::vector& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND); + + /// @brief Retrieves the number of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @return The number of rows in the table. + int GetCount(const std::string& tableName, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND); + /// @brief Begins a transaction in the SQLite database. /// @return A SQLite transaction object. SQLite::Transaction BeginTransaction(); diff --git a/src/agent/sqlite_manager/src/sqlite_manager.cpp b/src/agent/sqlite_manager/src/sqlite_manager.cpp index 2aaf0bd52b..989bc52269 100644 --- a/src/agent/sqlite_manager/src/sqlite_manager.cpp +++ b/src/agent/sqlite_manager/src/sqlite_manager.cpp @@ -30,11 +30,27 @@ namespace sqlite_manager m_db->exec("PRAGMA journal_mode=WAL;"); } - void SQLiteManager::CreateTable(const std::string& tableName, const std::vector& cols) + bool SQLiteManager::TableExists(const std::string& table) + { + try + { + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, + "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "';"); + return query.executeStep(); + } + catch (const std::exception& e) + { + LogError("Failed to check if table exists: {}.", e.what()); + return false; + } + } + + void SQLiteManager::CreateTable(const std::string& tableName, const std::vector& cols) { std::vector pk; std::vector fields; - for (const Column& col : cols) + for (const auto& col : cols) { std::string field = fmt::format("{} {}{}", col.Name, MAP_COL_TYPE_STRING.at(col.Type), (col.NotNull) ? " NOT NULL" : ""); @@ -52,27 +68,12 @@ namespace sqlite_manager Execute(queryString); } - bool SQLiteManager::TableExists(const std::string& table) const - { - try - { - SQLite::Statement query(*m_db, - "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "';"); - return query.executeStep(); - } - catch (const std::exception& e) - { - LogError("Failed to check if table exists: {}.", e.what()); - return false; - } - } - - void SQLiteManager::Insert(const std::string& tableName, const std::vector& cols) + void SQLiteManager::Insert(const std::string& tableName, const Row& cols) { std::vector names; std::vector values; - for (const Column& col : cols) + for (const auto& col : cols) { names.push_back(col.Name); if (col.Type == ColumnType::TEXT) @@ -89,36 +90,105 @@ namespace sqlite_manager Execute(queryString); } - int SQLiteManager::GetCount(const std::string& tableName) + void SQLiteManager::Update(const std::string& tableName, + const Row& fields, + const Criteria& selCriteria, + LogicalOperator logOp) { - std::string queryString = fmt::format("SELECT COUNT(*) FROM {}", tableName); - - try + if (fields.empty()) { - std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, queryString); - int count = 0; + LogError("Error: Missing update fields."); + throw; + } - if (query.executeStep()) + std::vector setFields; + for (auto& col : fields) + { + if (col.Type == ColumnType::TEXT) { - count = query.getColumn(0).getInt(); + setFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); } else { - LogError("Error getting element count."); + setFields.push_back(fmt::format("{}={}", col.Name, col.Value)); } - return count; + } + std::string updateValues = fmt::format("{}", fmt::join(setFields, ", ")); + + std::string whereClause; + if (!selCriteria.empty()) + { + std::vector conditions; + for (auto& col : selCriteria) + { + if (col.Type == ColumnType::TEXT) + { + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + } + else + { + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); + } + } + whereClause = + fmt::format(" WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } + + std::string queryString = fmt::format("UPDATE {} SET {}{}", tableName, updateValues, whereClause); + + Execute(queryString); + } + + void SQLiteManager::Remove(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) + { + std::string whereClause; + if (!selCriteria.empty()) + { + std::vector critFields; + for (auto& col : selCriteria) + { + if (col.Type == ColumnType::TEXT) + { + critFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + } + else + { + critFields.push_back(fmt::format("{}={}", col.Name, col.Value)); + } + } + whereClause = + fmt::format(" WHERE {}", fmt::join(critFields, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } + + std::string queryString = fmt::format("DELETE FROM {}{}", tableName, whereClause); + + Execute(queryString); + } + + void SQLiteManager::DropTable(const std::string& tableName) + { + std::string queryString = fmt::format("DROP TABLE {}", tableName); + + Execute(queryString); + } + + void SQLiteManager::Execute(const std::string& query) + { + try + { + std::lock_guard lock(m_mutex); + m_db->exec(query); } catch (const std::exception& e) { - LogError("Error during GetCount operation: {}.", e.what()); + LogError("Error during database operation: {}.", e.what()); throw; } } std::vector SQLiteManager::Select(const std::string& tableName, - const std::vector& fields, - const std::vector& selCriteria, + const std::vector& fields, + const Criteria& selCriteria, LogicalOperator logOp) { std::string selectedFields; @@ -145,9 +215,9 @@ namespace sqlite_manager for (auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{} = '{}'", col.Name, col.Value)); + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); else - conditions.push_back(fmt::format("{} = {}", col.Name, col.Value)); + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); } condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } @@ -158,125 +228,69 @@ namespace sqlite_manager try { std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, queryString); + while (query.executeStep()) { int nColumns = query.getColumnCount(); - std::vector queryFields; + Row queryFields; queryFields.reserve(static_cast(nColumns)); for (int i = 0; i < nColumns; i++) { - Column field(query.getColumn(i).getName(), - ColumnTypeFromSQLiteType(query.getColumn(i).getType()), - query.getColumn(i).getString()); - queryFields.push_back(field); + queryFields.emplace_back(query.getColumn(i).getName(), + ColumnTypeFromSQLiteType(query.getColumn(i).getType()), + query.getColumn(i).getString()); } results.push_back(queryFields); } } catch (const std::exception& e) { - LogError("Error during Retrieve operation: {}.", e.what()); + LogError("Error during Select operation: {}.", e.what()); throw; } return results; } - void - SQLiteManager::Remove(const std::string& tableName, const std::vector& selCriteria, LogicalOperator logOp) + int SQLiteManager::GetCount(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) { - std::string whereClause; + std::string condition; if (!selCriteria.empty()) { - std::vector critFields; + std::vector conditions; for (auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) - { - critFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - } + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); else - { - critFields.push_back(fmt::format("{}={}", col.Name, col.Value)); - } + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); } - whereClause = - fmt::format(" WHERE {}", fmt::join(critFields, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } - std::string queryString = fmt::format("DELETE FROM {}{}", tableName, whereClause); + std::string queryString = fmt::format("SELECT COUNT(*) FROM {} {}", tableName, condition); - Execute(queryString); - } - - void SQLiteManager::Update(const std::string& tableName, - const std::vector& fields, - const std::vector& selCriteria, - LogicalOperator logOp) - { - if (fields.empty()) + int count = 0; + try { - LogError("Error: Missing update fields."); - throw; - } + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, queryString); - std::vector setFields; - for (auto& col : fields) - { - if (col.Type == ColumnType::TEXT) + if (query.executeStep()) { - setFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + count = query.getColumn(0).getInt(); } else { - setFields.push_back(fmt::format("{}={}", col.Name, col.Value)); - } - } - std::string updateValues = fmt::format("{}", fmt::join(setFields, ", ")); - - std::string whereClause; - if (!selCriteria.empty()) - { - std::vector conditions; - for (auto& col : selCriteria) - { - if (col.Type == ColumnType::TEXT) - { - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - } - else - { - conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); - } + LogError("Error getting element count."); } - whereClause = - fmt::format(" WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); - } - - std::string queryString = fmt::format("UPDATE {} SET {}{}", tableName, updateValues, whereClause); - Execute(queryString); - } - - void SQLiteManager::Execute(const std::string& query) - { - try - { - std::lock_guard lock(m_mutex); - m_db->exec(query); } catch (const std::exception& e) { - LogError("Error during database operation: {}.", e.what()); + LogError("Error during GetCount operation: {}.", e.what()); throw; } - } - - void SQLiteManager::DropTable(const std::string& tableName) - { - std::string queryString = fmt::format("DROP TABLE {}", tableName); - - Execute(queryString); + return count; } SQLite::Transaction SQLiteManager::BeginTransaction() diff --git a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp index 222a144962..8f50d5f0de 100644 --- a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp +++ b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp @@ -26,81 +26,82 @@ class SQLiteManagerTest : public ::testing::Test void AddTestData() { EXPECT_NO_THROW(m_db->Remove(m_tableName)); - m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName"), Column("Status", ColumnType::TEXT, "ItemStatus")}); - m_db->Insert( - m_tableName, - {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); m_db->Insert( m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName2"), Column("Status", ColumnType::TEXT, "ItemStatus2")}); + {ColumnValue("Name", ColumnType::TEXT, "ItemName"), ColumnValue("Status", ColumnType::TEXT, "ItemStatus")}); + m_db->Insert(m_tableName, + {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), + ColumnValue("Status", ColumnType::TEXT, "MyTestValue")}); + m_db->Insert(m_tableName, + {ColumnValue("Name", ColumnType::TEXT, "ItemName2"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus2")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName3"), - Column("Status", ColumnType::TEXT, "ItemStatus3"), - Column("Module", ColumnType::TEXT, "ItemModule3")}); + {ColumnValue("Name", ColumnType::TEXT, "ItemName3"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus3"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule3")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName4"), - Column("Status", ColumnType::TEXT, "ItemStatus4"), - Column("Module", ColumnType::TEXT, "ItemModule4"), - Column("Orden", ColumnType::INTEGER, "19"), - Column("Amount", ColumnType::REAL, "2.8")}); + {ColumnValue("Name", ColumnType::TEXT, "ItemName4"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus4"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule4"), + ColumnValue("Orden", ColumnType::INTEGER, "19"), + ColumnValue("Amount", ColumnType::REAL, "2.8")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName5"), - Column("Status", ColumnType::TEXT, "ItemStatus5"), - Column("Module", ColumnType::TEXT, "ItemModule5"), - Column("Orden", ColumnType::INTEGER, "21"), - Column("Amount", ColumnType::REAL, "3.5")}); + {ColumnValue("Name", ColumnType::TEXT, "ItemName5"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus5"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule5"), + ColumnValue("Orden", ColumnType::INTEGER, "21"), + ColumnValue("Amount", ColumnType::REAL, "3.5")}); } }; TEST_F(SQLiteManagerTest, CreateTableTest) { - Column col1 {"Id", ColumnType::INTEGER, true, true, true}; - Column col2 {"Name", ColumnType::TEXT, true, false, false}; - Column col3 {"Status", ColumnType::TEXT, true, false}; - Column col4 {"Module", ColumnType::TEXT, false, false}; - Column col5 {"Orden", ColumnType::INTEGER, false, false, false}; - Column col6 {"Amount", ColumnType::REAL, false, false, false}; + ColumnKey col1 {"Id", ColumnType::INTEGER, true, true, true}; + ColumnKey col2 {"Name", ColumnType::TEXT, true, false, false}; + ColumnKey col3 {"Status", ColumnType::TEXT, true, false}; + ColumnKey col4 {"Module", ColumnType::TEXT, false, false}; + ColumnKey col5 {"Orden", ColumnType::INTEGER, false, false, false}; + ColumnKey col6 {"Amount", ColumnType::REAL, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable(m_tableName, {col1, col2, col3, col4, col5, col6})); EXPECT_TRUE(m_db->TableExists(m_tableName)); - Column col21 {"Id", ColumnType::INTEGER, true, false, true}; - Column col212 {"Id2", ColumnType::INTEGER, true, false, true}; - Column col22 {"Name", ColumnType::TEXT, true, false, true}; - Column col23 {"Status", ColumnType::TEXT, true, false}; - Column col24 {"Module", ColumnType::TEXT, false, false}; - Column col25 {"Orden", ColumnType::INTEGER, false, false, false}; - Column col26 {"Amount", ColumnType::REAL, false, false, false}; + ColumnKey col21 {"Id", ColumnType::INTEGER, true, false, true}; + ColumnKey col212 {"Id2", ColumnType::INTEGER, true, false, true}; + ColumnKey col22 {"Name", ColumnType::TEXT, true, false, true}; + ColumnKey col23 {"Status", ColumnType::TEXT, true, false}; + ColumnKey col24 {"Module", ColumnType::TEXT, false, false}; + ColumnKey col25 {"Orden", ColumnType::INTEGER, false, false, false}; + ColumnKey col26 {"Amount", ColumnType::REAL, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable("TableTest2", {col21, col212, col22, col23, col24, col25, col26})); EXPECT_TRUE(m_db->TableExists("TableTest2")); } TEST_F(SQLiteManagerTest, InsertTest) { - Column col1 {"Name", ColumnType::TEXT, "ItemName1"}; - Column col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; + ColumnValue col1 {"Name", ColumnType::TEXT, "ItemName1"}; + ColumnValue col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; EXPECT_NO_THROW(m_db->Insert(m_tableName, {col1, col2})); EXPECT_NO_THROW(m_db->Insert( m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName2"), Column("Status", ColumnType::TEXT, "ItemStatus2")})); + {ColumnValue("Name", ColumnType::TEXT, "ItemName2"), ColumnValue("Status", ColumnType::TEXT, "ItemStatus2")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName3"), - Column("Status", ColumnType::TEXT, "ItemStatus3"), - Column("Module", ColumnType::TEXT, "ItemModule3")})); + {ColumnValue("Name", ColumnType::TEXT, "ItemName3"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus3"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule3")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName4"), - Column("Status", ColumnType::TEXT, "ItemStatus4"), - Column("Module", ColumnType::TEXT, "ItemModule4"), - Column("Orden", ColumnType::INTEGER, "16")})); + {ColumnValue("Name", ColumnType::TEXT, "ItemName4"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus4"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule4"), + ColumnValue("Orden", ColumnType::INTEGER, "16")})); EXPECT_NO_THROW(m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "ItemName4"), - Column("Status", ColumnType::TEXT, "ItemStatus4"), - Column("Module", ColumnType::TEXT, "ItemModule4"), - Column("Orden", ColumnType::INTEGER, "16"), - Column("Amount", ColumnType::REAL, "4.5")})); + {ColumnValue("Name", ColumnType::TEXT, "ItemName4"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus4"), + ColumnValue("Module", ColumnType::TEXT, "ItemModule4"), + ColumnValue("Orden", ColumnType::INTEGER, "16"), + ColumnValue("Amount", ColumnType::REAL, "4.5")})); } TEST_F(SQLiteManagerTest, GetCountTest) @@ -109,8 +110,8 @@ TEST_F(SQLiteManagerTest, GetCountTest) int count = m_db->GetCount(m_tableName); EXPECT_EQ(count, 0); - Column col1 {"Name", ColumnType::TEXT, "ItemName1"}; - Column col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; + ColumnValue col1 {"Name", ColumnType::TEXT, "ItemName1"}; + ColumnValue col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; EXPECT_NO_THROW(m_db->Insert(m_tableName, {col1, col2})); count = m_db->GetCount(m_tableName); @@ -139,7 +140,7 @@ TEST_F(SQLiteManagerTest, SelectTest) { AddTestData(); - std::vector cols; + std::vector cols; // all fields, no selection criteria std::vector ret = m_db->Select(m_tableName, cols); @@ -151,7 +152,7 @@ TEST_F(SQLiteManagerTest, SelectTest) ret = m_db->Select( m_tableName, cols, - {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); + {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Status", ColumnType::TEXT, "MyTestValue")}); DumpResults(ret); EXPECT_NE(ret.size(), 0); @@ -160,7 +161,7 @@ TEST_F(SQLiteManagerTest, SelectTest) ret = m_db->Select( m_tableName, cols, - {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Module", ColumnType::TEXT, "ItemModule5")}, + {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Module", ColumnType::TEXT, "ItemModule5")}, LogicalOperator::OR); DumpResults(ret); @@ -168,7 +169,7 @@ TEST_F(SQLiteManagerTest, SelectTest) // only Name field no selection criteria cols.clear(); - cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT); ret.clear(); ret = m_db->Select(m_tableName, cols); @@ -177,31 +178,31 @@ TEST_F(SQLiteManagerTest, SelectTest) // only Name field with default selection criteria cols.clear(); - cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT); ret.clear(); ret = m_db->Select( m_tableName, cols, - {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")}); + {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Status", ColumnType::TEXT, "MyTestValue")}); DumpResults(ret); EXPECT_NE(ret.size(), 0); // only Name field with single selection criteria cols.clear(); - cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); + cols.emplace_back("Name", ColumnType::TEXT); ret.clear(); - ret = m_db->Select(m_tableName, cols, {Column("Amount", ColumnType::REAL, "3.5")}); + ret = m_db->Select(m_tableName, cols, {ColumnValue("Amount", ColumnType::REAL, "3.5")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); // only Name and Amount fields with single selection criteria cols.clear(); - cols.emplace_back("Name", ColumnType::TEXT, "MyTestName"); - cols.emplace_back("Amount", ColumnType::REAL, "Amount"); + cols.emplace_back("Name", ColumnType::TEXT); + cols.emplace_back("Amount", ColumnType::REAL); ret.clear(); - ret = m_db->Select(m_tableName, cols, {Column("Amount", ColumnType::REAL, "2.8")}); + ret = m_db->Select(m_tableName, cols, {ColumnValue("Amount", ColumnType::REAL, "2.8")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); @@ -216,7 +217,7 @@ TEST_F(SQLiteManagerTest, RemoveTest) // Remove a single record EXPECT_NO_THROW(m_db->Remove( m_tableName, - {Column("Name", ColumnType::TEXT, "MyTestName"), Column("Status", ColumnType::TEXT, "MyTestValue")})); + {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Status", ColumnType::TEXT, "MyTestValue")})); int count = m_db->GetCount(m_tableName); EXPECT_EQ(count, initialCount - 1); @@ -229,43 +230,44 @@ TEST_F(SQLiteManagerTest, RemoveTest) TEST_F(SQLiteManagerTest, UpdateTest) { AddTestData(); - EXPECT_NO_THROW(m_db->Update( - m_tableName, - {Column("Name", ColumnType::TEXT, "Updated name"), Column("Status", ColumnType::TEXT, "Updated status")}, - {Column("Name", ColumnType::TEXT, "MyTestName")})); + EXPECT_NO_THROW(m_db->Update(m_tableName, + {ColumnValue("Name", ColumnType::TEXT, "Updated name"), + ColumnValue("Status", ColumnType::TEXT, "Updated status")}, + {ColumnValue("Name", ColumnType::TEXT, "MyTestName")})); - auto ret = m_db->Select(m_tableName, {}, {Column("Name", ColumnType::TEXT, "Updated name")}); + auto ret = m_db->Select(m_tableName, {}, {ColumnValue("Name", ColumnType::TEXT, "Updated name")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); - EXPECT_NO_THROW(m_db->Update( - m_tableName, - {Column("Name", ColumnType::TEXT, "Updated name2"), Column("Status", ColumnType::TEXT, "Updated status2")}, - {Column("Name", ColumnType::TEXT, "Updated name"), Column("Status", ColumnType::TEXT, "Updated status")})); + EXPECT_NO_THROW(m_db->Update(m_tableName, + {ColumnValue("Name", ColumnType::TEXT, "Updated name2"), + ColumnValue("Status", ColumnType::TEXT, "Updated status2")}, + {ColumnValue("Name", ColumnType::TEXT, "Updated name"), + ColumnValue("Status", ColumnType::TEXT, "Updated status")})); - ret = m_db->Select(m_tableName, {}, {Column("Name", ColumnType::TEXT, "Updated name2")}); + ret = m_db->Select(m_tableName, {}, {ColumnValue("Name", ColumnType::TEXT, "Updated name2")}); DumpResults(ret); EXPECT_EQ(ret.size(), 1); EXPECT_NO_THROW(m_db->Update(m_tableName, - {Column("Amount", ColumnType::REAL, "2.0")}, - {Column("Name", ColumnType::TEXT, "Updated name2"), - Column("Status", ColumnType::TEXT, "ItemStatus3"), - Column("Status", ColumnType::TEXT, "Updated status3")}, + {ColumnValue("Amount", ColumnType::REAL, "2.0")}, + {ColumnValue("Name", ColumnType::TEXT, "Updated name2"), + ColumnValue("Status", ColumnType::TEXT, "ItemStatus3"), + ColumnValue("Status", ColumnType::TEXT, "Updated status3")}, LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); EXPECT_NO_THROW(m_db->Update(m_tableName, - {Column("Amount", ColumnType::REAL, "2.0")}, - {Column("Status", ColumnType::TEXT, "ItemStatus3")}, + {ColumnValue("Amount", ColumnType::REAL, "2.0")}, + {ColumnValue("Status", ColumnType::TEXT, "ItemStatus3")}, LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); - EXPECT_NO_THROW(m_db->Update(m_tableName, {Column("Amount", ColumnType::REAL, "2.0")}, {})); + EXPECT_NO_THROW(m_db->Update(m_tableName, {ColumnValue("Amount", ColumnType::REAL, "2.0")}, {})); ret = m_db->Select(m_tableName, {}, {}); DumpResults(ret); @@ -277,17 +279,17 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName"), - Column("Status", ColumnType::TEXT, "TransactionStatus")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName2"), - Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName2"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_NO_THROW(m_db->RollbackTransaction(transaction)); } // since we rolled back the transaction we should find nothing - auto ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + auto ret = m_db->Select(m_tableName, {}, {ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 0); @@ -295,16 +297,16 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName"), - Column("Status", ColumnType::TEXT, "TransactionStatus")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName2"), - Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName2"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); } // since transaction obejct ran out of scope without being committed we should find nothing - ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + ret = m_db->Select(m_tableName, {}, {ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 0); @@ -312,28 +314,28 @@ TEST_F(SQLiteManagerTest, TransactionTest) auto transaction = m_db->BeginTransaction(); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName"), - Column("Status", ColumnType::TEXT, "TransactionStatus")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus")}); m_db->Insert(m_tableName, - {Column("Name", ColumnType::TEXT, "TransactionName2"), - Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + {ColumnValue("Name", ColumnType::TEXT, "TransactionName2"), + ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_NO_THROW(m_db->CommitTransaction(transaction)); } // since we commited the transaction we should find something - ret = m_db->Select(m_tableName, {}, {Column("Status", ColumnType::TEXT, "TransactionStatus2")}); + ret = m_db->Select(m_tableName, {}, {ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); EXPECT_EQ(ret.size(), 1); } TEST_F(SQLiteManagerTest, DropTableTest) { - Column col1 {"Id", ColumnType::INTEGER, true, true, true}; - Column col2 {"Name", ColumnType::TEXT, true, false}; - Column col3 {"Status", ColumnType::TEXT, true, false}; - Column col4 {"Module", ColumnType::TEXT, false, false}; - Column col5 {"Orden", ColumnType::INTEGER, false, false, false}; + ColumnKey col1 {"Id", ColumnType::INTEGER, true, true, true}; + ColumnKey col2 {"Name", ColumnType::TEXT, true, false}; + ColumnKey col3 {"Status", ColumnType::TEXT, true, false}; + ColumnKey col4 {"Module", ColumnType::TEXT, false, false}; + ColumnKey col5 {"Orden", ColumnType::INTEGER, false, false, false}; EXPECT_NO_THROW(m_db->CreateTable("DropMe", {col1, col2, col3, col4, col5})); EXPECT_TRUE(m_db->TableExists("DropMe")); From 9c3b735561b873357c0fcc337415658f3885bf26 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Wed, 8 Jan 2025 20:05:36 +0000 Subject: [PATCH 04/18] fix: remove unused function from multitype queue --- .../multitype_queue/include/persistence.hpp | 10 ------- .../multitype_queue/include/sqlitestorage.hpp | 10 ------- .../multitype_queue/src/sqlitestorage.cpp | 30 ------------------- .../tests/sqlitestorage_test.cpp | 20 ------------- 4 files changed, 70 deletions(-) diff --git a/src/agent/multitype_queue/include/persistence.hpp b/src/agent/multitype_queue/include/persistence.hpp index c4724f570e..fa94c3763c 100644 --- a/src/agent/multitype_queue/include/persistence.hpp +++ b/src/agent/multitype_queue/include/persistence.hpp @@ -48,16 +48,6 @@ class Persistence const std::string& moduleName = "", const std::string& moduleType = "") = 0; - /** - * @brief Remove a JSON message from the specified queue. - * - * @param id number of messages to be removed. - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @return int The number of messages removed. - */ - virtual int Remove(int id, const std::string& queueName, const std::string& moduleName = "") = 0; - /** * @brief Remove multiple JSON messages from the specified queue. * diff --git a/src/agent/multitype_queue/include/sqlitestorage.hpp b/src/agent/multitype_queue/include/sqlitestorage.hpp index e0fd45fb57..ee950cd654 100644 --- a/src/agent/multitype_queue/include/sqlitestorage.hpp +++ b/src/agent/multitype_queue/include/sqlitestorage.hpp @@ -78,16 +78,6 @@ class SQLiteStorage : public Persistence const std::string& moduleName = "", const std::string& moduleType = "") override; - /** - * @brief Remove a JSON message by its ID. - * - * @param id The number the message to remove. - * @param tableName The name of the table to remove the message from. - * @param moduleName The name of the module that created the message. - * @return The number of removed elements. - */ - int Remove(int id, const std::string& tableName, const std::string& moduleName = "") override; - /** * @brief Remove multiple JSON messages. * diff --git a/src/agent/multitype_queue/src/sqlitestorage.cpp b/src/agent/multitype_queue/src/sqlitestorage.cpp index 06ea05753e..034d5359de 100644 --- a/src/agent/multitype_queue/src/sqlitestorage.cpp +++ b/src/agent/multitype_queue/src/sqlitestorage.cpp @@ -144,36 +144,6 @@ nlohmann::json SQLiteStorage::RetrieveMultiple(int n, return ProcessRequest(query); } -int SQLiteStorage::Remove(int id, const std::string& tableName, const std::string& moduleName) -{ - std::string deleteQuery; - if (moduleName.empty()) - { - constexpr std::string_view DELETE_QUERY {"DELETE FROM {} WHERE rowid = ?;"}; - deleteQuery = fmt::format(DELETE_QUERY, tableName); - } - else - { - constexpr std::string_view DELETE_QUERY {"DELETE FROM {} WHERE module_name LIKE \"{}\" AND rowid = ?;"}; - deleteQuery = fmt::format(DELETE_QUERY, tableName, moduleName); - } - - try - { - SQLite::Statement query(*m_db, deleteQuery); - query.bind(1, id); - SQLite::Transaction transaction(*m_db); - query.exec(); - transaction.commit(); - return 1; - } - catch (const std::exception& e) - { - LogError("Error during Remove operation: {}.", e.what()); - return 0; - } -} - int SQLiteStorage::RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName) { std::string deleteQuery; diff --git a/src/agent/multitype_queue/tests/sqlitestorage_test.cpp b/src/agent/multitype_queue/tests/sqlitestorage_test.cpp index bda81e4226..d42e256b24 100644 --- a/src/agent/multitype_queue/tests/sqlitestorage_test.cpp +++ b/src/agent/multitype_queue/tests/sqlitestorage_test.cpp @@ -120,26 +120,6 @@ TEST_F(SQLiteStorageTest, RetrieveMultipleMessagesWithModule) } } -TEST_F(SQLiteStorageTest, RemoveMessage) -{ - nlohmann::json message = {{"key", "value"}}; - EXPECT_EQ(storage->Store(message, tableName), 1); - EXPECT_EQ(storage->Remove(1, tableName), 1); - EXPECT_EQ(storage->GetElementCount(tableName), 0); -} - -TEST_F(SQLiteStorageTest, RemoveMessageWithModule) -{ - nlohmann::json message = {{"key", "value"}}; - EXPECT_EQ(storage->Store(message, tableName, moduleName), 1); - EXPECT_EQ(storage->Remove(1, tableName), 1); - EXPECT_EQ(storage->Store(message, tableName, moduleName), 1); - EXPECT_EQ(storage->Remove(1, tableName, "unavailableModuleName"), 1); - EXPECT_EQ(storage->GetElementCount(tableName), 1); - EXPECT_EQ(storage->Remove(1, tableName, moduleName), 1); - EXPECT_EQ(storage->GetElementCount(tableName), 0); -} - TEST_F(SQLiteStorageTest, RemoveMultipleMessages) { auto messages = nlohmann::json::array(); From fdaa3041d42692ad88a7ef94ee60980835082443 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Wed, 8 Jan 2025 20:32:46 +0000 Subject: [PATCH 05/18] fix: organize database and column names --- .../agent_info/src/agent_info_persistance.cpp | 46 ++++--- .../command_store/include/command_store.hpp | 3 - src/agent/command_store/src/command_store.cpp | 114 ++++++++++-------- 3 files changed, 96 insertions(+), 67 deletions(-) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index ad9e4123d7..2f4d1cf8d8 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -6,9 +6,19 @@ using namespace sqlite_manager; namespace { + // database + const std::string AGENT_INFO_DB_NAME = "agent_info.db"; + + // agent_info table const std::string AGENT_INFO_TABLE_NAME = "agent_info"; + const std::string AGENT_INFO_NAME_COLUMN_NAME = "name"; + const std::string AGENT_INFO_KEY_COLUMN_NAME = "key"; + const std::string AGENT_INFO_UUID_COLUMN_NAME = "uuid"; + + // agent_group table const std::string AGENT_GROUP_TABLE_NAME = "agent_group"; - const std::string AGENT_INFO_DB_NAME = "agent_info.db"; + const std::string AGENT_GROUP_ID_COLUMN_NAME = "id"; + const std::string AGENT_GROUP_NAME_COLUMN_NAME = "name"; } // namespace AgentInfoPersistance::AgentInfoPersistance(const std::string& dbFolderPath) @@ -60,9 +70,10 @@ void AgentInfoPersistance::CreateAgentInfoTable() { try { - const std::vector columns = {ColumnKey("name", ColumnType::TEXT, true, false), - ColumnKey("key", ColumnType::TEXT, true, false), - ColumnKey("uuid", ColumnType::TEXT, true, false, true)}; + const std::vector columns = { + ColumnKey(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, true, false), + ColumnKey(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, true, false), + ColumnKey(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, true, false, true)}; m_db->CreateTable(AGENT_INFO_TABLE_NAME, columns); } @@ -76,8 +87,9 @@ void AgentInfoPersistance::CreateAgentGroupTable() { try { - const std::vector columns = {ColumnKey("id", ColumnType::INTEGER, true, true, true), - ColumnKey("name", ColumnType::TEXT, true, false)}; + const std::vector columns = { + ColumnKey(AGENT_GROUP_ID_COLUMN_NAME, ColumnType::INTEGER, true, true, true), + ColumnKey(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, true, false)}; m_db->CreateTable(AGENT_GROUP_TABLE_NAME, columns); } @@ -95,9 +107,9 @@ void AgentInfoPersistance::InsertDefaultAgentInfo() if (count == 0) { - const Row columns = {ColumnValue("name", ColumnType::TEXT, ""), - ColumnValue("key", ColumnType::TEXT, ""), - ColumnValue("uuid", ColumnType::TEXT, "")}; + const Row columns = {ColumnValue(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, ""), + ColumnValue(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, ""), + ColumnValue(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, "")}; m_db->Insert(AGENT_INFO_TABLE_NAME, columns); } @@ -145,17 +157,17 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c std::string AgentInfoPersistance::GetName() const { - return GetAgentInfoValue("name"); + return GetAgentInfoValue(AGENT_INFO_NAME_COLUMN_NAME); } std::string AgentInfoPersistance::GetKey() const { - return GetAgentInfoValue("key"); + return GetAgentInfoValue(AGENT_INFO_KEY_COLUMN_NAME); } std::string AgentInfoPersistance::GetUUID() const { - return GetAgentInfoValue("uuid"); + return GetAgentInfoValue(AGENT_INFO_UUID_COLUMN_NAME); } std::vector AgentInfoPersistance::GetGroups() const @@ -164,7 +176,7 @@ std::vector AgentInfoPersistance::GetGroups() const try { - const std::vector columns = {ColumnName("name", ColumnType::TEXT)}; + const std::vector columns = {ColumnName(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT)}; const std::vector results = m_db->Select(AGENT_GROUP_TABLE_NAME, columns); for (const auto& row : results) @@ -185,17 +197,17 @@ std::vector AgentInfoPersistance::GetGroups() const void AgentInfoPersistance::SetName(const std::string& name) { - SetAgentInfoValue("name", name); + SetAgentInfoValue(AGENT_INFO_NAME_COLUMN_NAME, name); } void AgentInfoPersistance::SetKey(const std::string& key) { - SetAgentInfoValue("key", key); + SetAgentInfoValue(AGENT_INFO_KEY_COLUMN_NAME, key); } void AgentInfoPersistance::SetUUID(const std::string& uuid) { - SetAgentInfoValue("uuid", uuid); + SetAgentInfoValue(AGENT_INFO_UUID_COLUMN_NAME, uuid); } bool AgentInfoPersistance::SetGroups(const std::vector& groupList) @@ -208,7 +220,7 @@ bool AgentInfoPersistance::SetGroups(const std::vector& groupList) for (const auto& group : groupList) { - const Row columns = {ColumnValue("name", ColumnType::TEXT, group)}; + const Row columns = {ColumnValue(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, group)}; m_db->Insert(AGENT_GROUP_TABLE_NAME, columns); } diff --git a/src/agent/command_store/include/command_store.hpp b/src/agent/command_store/include/command_store.hpp index aacd769978..6b8f353028 100644 --- a/src/agent/command_store/include/command_store.hpp +++ b/src/agent/command_store/include/command_store.hpp @@ -9,9 +9,6 @@ namespace command_store { - const std::string COMMANDSTORE_DB_NAME = "command_store.db"; - const std::string COMMANDSTORE_TABLE_NAME = "COMMAND"; - /// @brief CommandStore class /// /// This class provides methods for storing, retrieving, and deleting commands diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index 0e8b0af4f6..d136ea6faa 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -9,6 +9,22 @@ using namespace sqlite_manager; +namespace +{ + // database + const std::string COMMANDSTORE_DB_NAME = "command_store.db"; + + // command_store table + const std::string COMMAND_STORE_TABLE_NAME = "command_store"; + const std::string COMMAND_STORE_ID_COLUMN_NAME = "id"; + const std::string COMMAND_STORE_MODULE_COLUMN_NAME = "module"; + const std::string COMMAND_STORE_COMMAND_COLUMN_NAME = "command"; + const std::string COMMAND_STORE_PARAMETERS_COLUMN_NAME = "parameters"; + const std::string COMMAND_STORE_RESULT_COLUMN_NAME = "result"; + const std::string COMMAND_STORE_STATUS_COLUMN_NAME = "status"; + const std::string COMMAND_STORE_TIME_COLUMN_NAME = "time"; +} // namespace + namespace command_store { constexpr double MILLISECS_IN_A_SEC = 1000.0; @@ -33,20 +49,20 @@ namespace command_store { m_dataBase = std::make_unique(dbFilePath); - if (!m_dataBase->TableExists(COMMANDSTORE_TABLE_NAME)) + if (!m_dataBase->TableExists(COMMAND_STORE_TABLE_NAME)) { std::vector columns; - columns.emplace_back("id", ColumnType::TEXT, true, false, true); - columns.emplace_back("module", ColumnType::TEXT, true, false, false); - columns.emplace_back("command", ColumnType::TEXT, true, false, false); - columns.emplace_back("parameters", ColumnType::TEXT, true, false, false); - columns.emplace_back("result", ColumnType::TEXT, true, false, false); - columns.emplace_back("status", ColumnType::INTEGER, true, false, false); - columns.emplace_back("time", ColumnType::REAL, true, false, false); + columns.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, true, false, true); + columns.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, true, false, false); + columns.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, true, false, false); + columns.emplace_back(COMMAND_STORE_PARAMETERS_COLUMN_NAME, ColumnType::TEXT, true, false, false); + columns.emplace_back(COMMAND_STORE_RESULT_COLUMN_NAME, ColumnType::TEXT, true, false, false); + columns.emplace_back(COMMAND_STORE_STATUS_COLUMN_NAME, ColumnType::INTEGER, true, false, false); + columns.emplace_back(COMMAND_STORE_TIME_COLUMN_NAME, ColumnType::REAL, true, false, false); try { - m_dataBase->CreateTable(COMMANDSTORE_TABLE_NAME, columns); + m_dataBase->CreateTable(COMMAND_STORE_TABLE_NAME, columns); } catch (std::exception& e) { @@ -65,7 +81,7 @@ namespace command_store { try { - m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, {}); + m_dataBase->Remove(COMMAND_STORE_TABLE_NAME, {}); } catch (const std::exception& e) { @@ -81,7 +97,7 @@ namespace command_store try { - count = m_dataBase->GetCount(COMMANDSTORE_TABLE_NAME); + count = m_dataBase->GetCount(COMMAND_STORE_TABLE_NAME); } catch (const std::exception& e) { @@ -103,18 +119,20 @@ namespace command_store bool CommandStore::StoreCommand(const module_command::CommandEntry& cmd) { Row fields; - fields.emplace_back("id", ColumnType::TEXT, cmd.Id); - fields.emplace_back("module", ColumnType::TEXT, cmd.Module); - fields.emplace_back("command", ColumnType::TEXT, cmd.Command); - fields.emplace_back("time", ColumnType::REAL, std::to_string(GetCurrentTimestampAsReal())); - fields.emplace_back("parameters", ColumnType::TEXT, cmd.Parameters.dump()); - fields.emplace_back("result", ColumnType::TEXT, cmd.ExecutionResult.Message); + fields.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, cmd.Id); + fields.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, cmd.Module); + fields.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, cmd.Command); fields.emplace_back( - "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + COMMAND_STORE_TIME_COLUMN_NAME, ColumnType::REAL, std::to_string(GetCurrentTimestampAsReal())); + fields.emplace_back(COMMAND_STORE_PARAMETERS_COLUMN_NAME, ColumnType::TEXT, cmd.Parameters.dump()); + fields.emplace_back(COMMAND_STORE_RESULT_COLUMN_NAME, ColumnType::TEXT, cmd.ExecutionResult.Message); + fields.emplace_back(COMMAND_STORE_STATUS_COLUMN_NAME, + ColumnType::INTEGER, + std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); try { - m_dataBase->Insert(COMMANDSTORE_TABLE_NAME, fields); + m_dataBase->Insert(COMMAND_STORE_TABLE_NAME, fields); } catch (const std::exception& e) { @@ -127,11 +145,11 @@ namespace command_store bool CommandStore::DeleteCommand(const std::string& id) { Criteria filters; - filters.emplace_back("id", ColumnType::TEXT, id); + filters.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, id); try { - m_dataBase->Remove(COMMANDSTORE_TABLE_NAME, filters); + m_dataBase->Remove(COMMAND_STORE_TABLE_NAME, filters); } catch (const std::exception& e) { @@ -144,11 +162,11 @@ namespace command_store std::optional CommandStore::GetCommand(const std::string& id) { Criteria filters; - filters.emplace_back("id", ColumnType::TEXT, id); + filters.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, id); try { - auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, filters); + auto cmdData = m_dataBase->Select(COMMAND_STORE_TABLE_NAME, {}, filters); if (cmdData.empty()) { @@ -158,31 +176,31 @@ namespace command_store module_command::CommandEntry cmd; for (const auto& col : cmdData[0]) { - if (col.Name == "id") + if (col.Name == COMMAND_STORE_ID_COLUMN_NAME) { cmd.Id = col.Value; } - else if (col.Name == "module") + else if (col.Name == COMMAND_STORE_MODULE_COLUMN_NAME) { cmd.Module = col.Value; } - else if (col.Name == "command") + else if (col.Name == COMMAND_STORE_COMMAND_COLUMN_NAME) { cmd.Command = col.Value; } - else if (col.Name == "parameters") + else if (col.Name == COMMAND_STORE_PARAMETERS_COLUMN_NAME) { cmd.Parameters = nlohmann::json::parse(col.Value); } - else if (col.Name == "result") + else if (col.Name == COMMAND_STORE_RESULT_COLUMN_NAME) { cmd.ExecutionResult.Message = col.Value; } - else if (col.Name == "status") + else if (col.Name == COMMAND_STORE_STATUS_COLUMN_NAME) { cmd.ExecutionResult.ErrorCode = StatusFromInt(std::stoi(col.Value)); } - else if (col.Name == "time") + else if (col.Name == COMMAND_STORE_TIME_COLUMN_NAME) { cmd.Time = std::stod(col.Value); } @@ -200,11 +218,12 @@ namespace command_store CommandStore::GetCommandByStatus(const module_command::Status& status) { Criteria filters; - filters.emplace_back("status", ColumnType::INTEGER, std::to_string(static_cast(status))); + filters.emplace_back( + COMMAND_STORE_STATUS_COLUMN_NAME, ColumnType::INTEGER, std::to_string(static_cast(status))); try { - auto cmdData = m_dataBase->Select(COMMANDSTORE_TABLE_NAME, {}, filters); + auto cmdData = m_dataBase->Select(COMMAND_STORE_TABLE_NAME, {}, filters); if (cmdData.empty()) { @@ -219,31 +238,31 @@ namespace command_store for (const auto& col : row) { - if (col.Name == "id") + if (col.Name == COMMAND_STORE_ID_COLUMN_NAME) { cmd.Id = col.Value; } - else if (col.Name == "module") + else if (col.Name == COMMAND_STORE_MODULE_COLUMN_NAME) { cmd.Module = col.Value; } - else if (col.Name == "command") + else if (col.Name == COMMAND_STORE_COMMAND_COLUMN_NAME) { cmd.Command = col.Value; } - else if (col.Name == "parameters") + else if (col.Name == COMMAND_STORE_PARAMETERS_COLUMN_NAME) { cmd.Parameters = nlohmann::json::parse(col.Value); } - else if (col.Name == "result") + else if (col.Name == COMMAND_STORE_RESULT_COLUMN_NAME) { cmd.ExecutionResult.Message = col.Value; } - else if (col.Name == "status") + else if (col.Name == COMMAND_STORE_STATUS_COLUMN_NAME) { cmd.ExecutionResult.ErrorCode = StatusFromInt(std::stoi(col.Value)); } - else if (col.Name == "time") + else if (col.Name == COMMAND_STORE_TIME_COLUMN_NAME) { cmd.Time = std::stod(col.Value); } @@ -264,23 +283,24 @@ namespace command_store { Row fields; if (!cmd.Module.empty()) - fields.emplace_back("module", ColumnType::TEXT, cmd.Module); + fields.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, cmd.Module); if (!cmd.Command.empty()) - fields.emplace_back("command", ColumnType::TEXT, cmd.Command); + fields.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, cmd.Command); if (!cmd.Parameters.empty()) - fields.emplace_back("parameters", ColumnType::TEXT, cmd.Parameters.dump()); + fields.emplace_back(COMMAND_STORE_PARAMETERS_COLUMN_NAME, ColumnType::TEXT, cmd.Parameters.dump()); if (!cmd.ExecutionResult.Message.empty()) - fields.emplace_back("result", ColumnType::TEXT, cmd.ExecutionResult.Message); + fields.emplace_back(COMMAND_STORE_RESULT_COLUMN_NAME, ColumnType::TEXT, cmd.ExecutionResult.Message); if (cmd.ExecutionResult.ErrorCode != module_command::Status::UNKNOWN) - fields.emplace_back( - "status", ColumnType::INTEGER, std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); + fields.emplace_back(COMMAND_STORE_STATUS_COLUMN_NAME, + ColumnType::INTEGER, + std::to_string(static_cast(cmd.ExecutionResult.ErrorCode))); Criteria filters; - filters.emplace_back("id", ColumnType::TEXT, cmd.Id); + filters.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, cmd.Id); try { - m_dataBase->Update(COMMANDSTORE_TABLE_NAME, fields, filters); + m_dataBase->Update(COMMAND_STORE_TABLE_NAME, fields, filters); } catch (const std::exception& e) { From 146b37f3c3807d6f09698a161de3984122902cb7 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Wed, 8 Jan 2025 22:19:18 +0000 Subject: [PATCH 06/18] feat: add order by and limit to select query --- src/agent/sqlite_manager/include/column.hpp | 7 ++ .../sqlite_manager/include/sqlite_manager.hpp | 8 +- .../sqlite_manager/src/sqlite_manager.cpp | 35 +++++++-- .../tests/sqlite_manager_test.cpp | 77 +++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) diff --git a/src/agent/sqlite_manager/include/column.hpp b/src/agent/sqlite_manager/include/column.hpp index dab5215331..69a25b0bbb 100644 --- a/src/agent/sqlite_manager/include/column.hpp +++ b/src/agent/sqlite_manager/include/column.hpp @@ -10,6 +10,13 @@ enum class LogicalOperator OR }; +/// @brief Supported order types for sorting results. +enum class OrderType +{ + ASC, + DESC +}; + /// @brief Supported column data types for SQLite tables. enum class ColumnType { diff --git a/src/agent/sqlite_manager/include/sqlite_manager.hpp b/src/agent/sqlite_manager/include/sqlite_manager.hpp index fc77c8c69c..5297922929 100644 --- a/src/agent/sqlite_manager/include/sqlite_manager.hpp +++ b/src/agent/sqlite_manager/include/sqlite_manager.hpp @@ -61,11 +61,17 @@ namespace sqlite_manager /// @param fields A vector of columns to retrieve. /// @param selCriteria Optional selection criteria to filter rows. /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @param orderBy A vector of columns to order the results by. + /// @param orderType The order type (ASC or DESC). + /// @param limit The maximum number of rows to retrieve. /// @return A vector of rows matching the criteria. std::vector Select(const std::string& tableName, const std::vector& fields, const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); + LogicalOperator logOp = LogicalOperator::AND, + const std::vector& orderBy = {}, + OrderType orderType = OrderType::ASC, + unsigned int limit = 0); /// @brief Retrieves the number of rows in a specified table. /// @param tableName The name of the table to count rows in. diff --git a/src/agent/sqlite_manager/src/sqlite_manager.cpp b/src/agent/sqlite_manager/src/sqlite_manager.cpp index 989bc52269..93cdf6fa7c 100644 --- a/src/agent/sqlite_manager/src/sqlite_manager.cpp +++ b/src/agent/sqlite_manager/src/sqlite_manager.cpp @@ -11,6 +11,7 @@ namespace sqlite_manager {ColumnType::INTEGER, "INTEGER"}, {ColumnType::TEXT, "TEXT"}, {ColumnType::REAL, "REAL"}}; const std::map MAP_LOGOP_STRING {{LogicalOperator::AND, "AND"}, {LogicalOperator::OR, "OR"}}; + const std::map MAP_ORDER_STRING {{OrderType::ASC, "ASC"}, {OrderType::DESC, "DESC"}}; ColumnType SQLiteManager::ColumnTypeFromSQLiteType(const int type) const { @@ -102,7 +103,7 @@ namespace sqlite_manager } std::vector setFields; - for (auto& col : fields) + for (const auto& col : fields) { if (col.Type == ColumnType::TEXT) { @@ -119,7 +120,7 @@ namespace sqlite_manager if (!selCriteria.empty()) { std::vector conditions; - for (auto& col : selCriteria) + for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) { @@ -145,7 +146,7 @@ namespace sqlite_manager if (!selCriteria.empty()) { std::vector critFields; - for (auto& col : selCriteria) + for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) { @@ -189,7 +190,10 @@ namespace sqlite_manager std::vector SQLiteManager::Select(const std::string& tableName, const std::vector& fields, const Criteria& selCriteria, - LogicalOperator logOp) + LogicalOperator logOp, + const std::vector& orderBy, + OrderType orderType, + unsigned int limit) { std::string selectedFields; if (fields.empty()) @@ -201,7 +205,7 @@ namespace sqlite_manager std::vector fieldNames; fieldNames.reserve(fields.size()); - for (auto& col : fields) + for (const auto& col : fields) { fieldNames.push_back(col.Name); } @@ -212,7 +216,7 @@ namespace sqlite_manager if (!selCriteria.empty()) { std::vector conditions; - for (auto& col : selCriteria) + for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); @@ -222,6 +226,23 @@ namespace sqlite_manager condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } + if (!orderBy.empty()) + { + std::vector orderFields; + orderFields.reserve(orderBy.size()); + for (const auto& col : orderBy) + { + orderFields.push_back(col.Name); + } + condition += fmt::format(" ORDER BY {}", fmt::join(orderFields, ", ")); + condition += fmt::format(" {}", MAP_ORDER_STRING.at(orderType)); + } + + if (limit > 0) + { + condition += fmt::format(" LIMIT {}", limit); + } + std::string queryString = fmt::format("SELECT {} FROM {} {}", selectedFields, tableName, condition); std::vector results; @@ -258,7 +279,7 @@ namespace sqlite_manager if (!selCriteria.empty()) { std::vector conditions; - for (auto& col : selCriteria) + for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); diff --git a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp index 8f50d5f0de..c049850c61 100644 --- a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp +++ b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp @@ -206,6 +206,83 @@ TEST_F(SQLiteManagerTest, SelectTest) DumpResults(ret); EXPECT_EQ(ret.size(), 1); + + // only Name field with ordered criteria + cols.clear(); + cols.emplace_back("Name", ColumnType::TEXT); + ret.clear(); + ret = m_db->Select( + m_tableName, cols, {}, LogicalOperator::AND, {ColumnName("Name", ColumnType::TEXT)}, OrderType::DESC); + + DumpResults(ret); + EXPECT_EQ(ret.size(), 6); + EXPECT_EQ(ret[0][0].Value, "MyTestName"); + EXPECT_EQ(ret[1][0].Value, "ItemName5"); + EXPECT_EQ(ret[2][0].Value, "ItemName4"); + EXPECT_EQ(ret[3][0].Value, "ItemName3"); + EXPECT_EQ(ret[4][0].Value, "ItemName2"); + EXPECT_EQ(ret[5][0].Value, "ItemName"); + + // only Name ans Amount fields with selection criteria and ordered criteria + cols.clear(); + cols.emplace_back("Name", ColumnType::TEXT); + cols.emplace_back("Amount", ColumnType::REAL); + ret.clear(); + ret = m_db->Select(m_tableName, + cols, + {ColumnValue("Amount", ColumnType::REAL, "2.8"), ColumnValue("Amount", ColumnType::REAL, "3.5")}, + LogicalOperator::OR, + {ColumnName("Amount", ColumnType::REAL)}, + OrderType::DESC); + + DumpResults(ret); + EXPECT_EQ(ret.size(), 2); + EXPECT_EQ(ret[0][0].Value, "ItemName5"); + EXPECT_EQ(ret[0][1].Value, "3.5"); + EXPECT_EQ(ret[1][0].Value, "ItemName4"); + EXPECT_EQ(ret[1][1].Value, "2.8"); + + // only Name field with limit criteria + cols.clear(); + cols.emplace_back("Name", ColumnType::TEXT); + ret.clear(); + ret = m_db->Select(m_tableName, cols, {}, LogicalOperator::AND, {}, OrderType::ASC, 3); + + DumpResults(ret); + EXPECT_EQ(ret.size(), 3); + + // only Name ans Amount fields with selection criteria and limit criteria + cols.clear(); + cols.emplace_back("Name", ColumnType::TEXT); + ret.clear(); + ret = m_db->Select(m_tableName, + cols, + {ColumnValue("Amount", ColumnType::REAL, "2.8"), ColumnValue("Amount", ColumnType::REAL, "3.5")}, + LogicalOperator::OR, + {}, + OrderType::ASC, + 1); + + DumpResults(ret); + EXPECT_EQ(ret.size(), 1); + + // only Name ans Amount fields with selection criteria, ordered criteria and limit criteria + cols.clear(); + cols.emplace_back("Name", ColumnType::TEXT); + cols.emplace_back("Amount", ColumnType::REAL); + ret.clear(); + ret = m_db->Select(m_tableName, + cols, + {ColumnValue("Amount", ColumnType::REAL, "2.8"), ColumnValue("Amount", ColumnType::REAL, "3.5")}, + LogicalOperator::OR, + {ColumnName("Amount", ColumnType::REAL)}, + OrderType::DESC, + 1); + + DumpResults(ret); + EXPECT_EQ(ret.size(), 1); + EXPECT_EQ(ret[0][0].Value, "ItemName5"); + EXPECT_EQ(ret[0][1].Value, "3.5"); } TEST_F(SQLiteManagerTest, RemoveTest) From 79afad7de6d48c6bbbd99c70598a0c5c77f1977c Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Thu, 9 Jan 2025 18:11:34 +0000 Subject: [PATCH 07/18] feat: add functions to calculate row size to sqlite manager --- .../sqlite_manager/include/sqlite_manager.hpp | 6 +++ .../sqlite_manager/src/sqlite_manager.cpp | 43 +++++++++++++++++++ .../tests/sqlite_manager_test.cpp | 20 +++++++++ 3 files changed, 69 insertions(+) diff --git a/src/agent/sqlite_manager/include/sqlite_manager.hpp b/src/agent/sqlite_manager/include/sqlite_manager.hpp index 5297922929..548d7e92fb 100644 --- a/src/agent/sqlite_manager/include/sqlite_manager.hpp +++ b/src/agent/sqlite_manager/include/sqlite_manager.hpp @@ -82,6 +82,12 @@ namespace sqlite_manager const Criteria& selCriteria = {}, LogicalOperator logOp = LogicalOperator::AND); + /// @brief Retrieves the size in bytes of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param fields A vector of columns to retrieve. + /// @return The size in bytes of the rows in the table. + size_t GetSize(const std::string& tableName, const std::vector& fields); + /// @brief Begins a transaction in the SQLite database. /// @return A SQLite transaction object. SQLite::Transaction BeginTransaction(); diff --git a/src/agent/sqlite_manager/src/sqlite_manager.cpp b/src/agent/sqlite_manager/src/sqlite_manager.cpp index 93cdf6fa7c..7d4d5eaf41 100644 --- a/src/agent/sqlite_manager/src/sqlite_manager.cpp +++ b/src/agent/sqlite_manager/src/sqlite_manager.cpp @@ -314,6 +314,49 @@ namespace sqlite_manager return count; } + size_t SQLiteManager::GetSize(const std::string& tableName, const std::vector& fields) + { + if (fields.empty()) + { + LogError("Error: Missing size fields."); + throw; + } + + std::string selectedFields; + std::vector fieldNames; + fieldNames.reserve(fields.size()); + + for (const auto& col : fields) + { + fieldNames.push_back("LENGTH(" + col.Name + ")"); + } + selectedFields = fmt::format("{}", fmt::join(fieldNames, " + ")); + + std::string queryString = fmt::format("SELECT SUM({}) AS total_bytes FROM {}", selectedFields, tableName); + + size_t count = 0; + try + { + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, queryString); + + if (query.executeStep()) + { + count = query.getColumn(0).getUInt(); + } + else + { + LogError("Error getting element count."); + } + } + catch (const std::exception& e) + { + LogError("Error during GetSize operation: {}.", e.what()); + throw; + } + return count; + } + SQLite::Transaction SQLiteManager::BeginTransaction() { return SQLite::Transaction(*m_db); diff --git a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp index c049850c61..4cec36a748 100644 --- a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp +++ b/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp @@ -123,6 +123,26 @@ TEST_F(SQLiteManagerTest, GetCountTest) EXPECT_EQ(count, 2); } +TEST_F(SQLiteManagerTest, GetSizeTest) +{ + EXPECT_NO_THROW(m_db->Remove(m_tableName)); + int count = m_db->GetCount(m_tableName); + EXPECT_EQ(count, 0); + + ColumnValue col1 {"Name", ColumnType::TEXT, "ItemName1"}; + ColumnValue col2 {"Status", ColumnType::TEXT, "ItemStatus1"}; + EXPECT_NO_THROW(m_db->Insert(m_tableName, {col1, col2})); + + size_t size = m_db->GetSize(m_tableName, {ColumnName("Name", ColumnType::TEXT)}); + EXPECT_EQ(size, 9); + + size = m_db->GetSize(m_tableName, {ColumnName("Status", ColumnType::TEXT)}); + EXPECT_EQ(size, 11); + + size = m_db->GetSize(m_tableName, {ColumnName("Name", ColumnType::TEXT), ColumnName("Status", ColumnType::TEXT)}); + EXPECT_EQ(size, 20); +} + static void DumpResults(std::vector& ret) { std::cout << "---------- " << ret.size() << " rows returned. ----------" << '\n'; From db73338a5860743ca95581a160574a7251837ba8 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Thu, 9 Jan 2025 18:37:54 +0000 Subject: [PATCH 08/18] refactor: change sqlite_manager name to persistence --- src/agent/CMakeLists.txt | 6 +++--- src/agent/{sqlite_manager => persistence}/CMakeLists.txt | 0 .../{sqlite_manager => persistence}/include/column.hpp | 0 .../include/sqlite_manager.hpp | 0 .../{sqlite_manager => persistence}/src/sqlite_manager.cpp | 0 .../{sqlite_manager => persistence}/tests/CMakeLists.txt | 0 src/agent/{sqlite_manager => persistence}/tests/main.cpp | 0 .../tests/sqlite_manager_test.cpp | 0 8 files changed, 3 insertions(+), 3 deletions(-) rename src/agent/{sqlite_manager => persistence}/CMakeLists.txt (100%) rename src/agent/{sqlite_manager => persistence}/include/column.hpp (100%) rename src/agent/{sqlite_manager => persistence}/include/sqlite_manager.hpp (100%) rename src/agent/{sqlite_manager => persistence}/src/sqlite_manager.cpp (100%) rename src/agent/{sqlite_manager => persistence}/tests/CMakeLists.txt (100%) rename src/agent/{sqlite_manager => persistence}/tests/main.cpp (100%) rename src/agent/{sqlite_manager => persistence}/tests/sqlite_manager_test.cpp (100%) diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index 6d50e37dfc..4aa8cc5c7f 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -8,16 +8,16 @@ project(Agent) include(../cmake/CommonSettings.cmake) set_common_settings() -add_subdirectory(task_manager) add_subdirectory(agent_info) add_subdirectory(centralized_configuration) add_subdirectory(command_handler) +add_subdirectory(command_store) add_subdirectory(communicator) add_subdirectory(configuration_parser) add_subdirectory(module_command) add_subdirectory(multitype_queue) -add_subdirectory(sqlite_manager) -add_subdirectory(command_store) +add_subdirectory(persistence) +add_subdirectory(task_manager) find_package(OpenSSL REQUIRED) find_package(Boost REQUIRED COMPONENTS asio beast system program_options) diff --git a/src/agent/sqlite_manager/CMakeLists.txt b/src/agent/persistence/CMakeLists.txt similarity index 100% rename from src/agent/sqlite_manager/CMakeLists.txt rename to src/agent/persistence/CMakeLists.txt diff --git a/src/agent/sqlite_manager/include/column.hpp b/src/agent/persistence/include/column.hpp similarity index 100% rename from src/agent/sqlite_manager/include/column.hpp rename to src/agent/persistence/include/column.hpp diff --git a/src/agent/sqlite_manager/include/sqlite_manager.hpp b/src/agent/persistence/include/sqlite_manager.hpp similarity index 100% rename from src/agent/sqlite_manager/include/sqlite_manager.hpp rename to src/agent/persistence/include/sqlite_manager.hpp diff --git a/src/agent/sqlite_manager/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp similarity index 100% rename from src/agent/sqlite_manager/src/sqlite_manager.cpp rename to src/agent/persistence/src/sqlite_manager.cpp diff --git a/src/agent/sqlite_manager/tests/CMakeLists.txt b/src/agent/persistence/tests/CMakeLists.txt similarity index 100% rename from src/agent/sqlite_manager/tests/CMakeLists.txt rename to src/agent/persistence/tests/CMakeLists.txt diff --git a/src/agent/sqlite_manager/tests/main.cpp b/src/agent/persistence/tests/main.cpp similarity index 100% rename from src/agent/sqlite_manager/tests/main.cpp rename to src/agent/persistence/tests/main.cpp diff --git a/src/agent/sqlite_manager/tests/sqlite_manager_test.cpp b/src/agent/persistence/tests/sqlite_manager_test.cpp similarity index 100% rename from src/agent/sqlite_manager/tests/sqlite_manager_test.cpp rename to src/agent/persistence/tests/sqlite_manager_test.cpp From 6fb3483c5bf3a8d8c69c45e654cdf404c03d0287 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Thu, 9 Jan 2025 22:14:14 +0000 Subject: [PATCH 09/18] feat: create persistence component with persistence and sqlite_manager --- src/agent/agent_info/CMakeLists.txt | 2 +- .../agent_info/src/agent_info_persistance.cpp | 22 +- .../agent_info/src/agent_info_persistance.hpp | 8 +- src/agent/agent_info/tests/CMakeLists.txt | 4 +- src/agent/command_store/CMakeLists.txt | 2 +- .../command_store/include/command_store.hpp | 10 +- src/agent/command_store/src/command_store.cpp | 11 +- src/agent/multitype_queue/CMakeLists.txt | 3 +- .../include/multitype_queue.hpp | 8 +- .../multitype_queue/include/persistence.hpp | 91 --- .../include/persistence_factory.hpp | 29 - .../multitype_queue/include/sqlitestorage.hpp | 18 +- .../src/persistence_factory.cpp | 21 - .../multitype_queue/src/sqlitestorage.cpp | 2 - src/agent/persistence/CMakeLists.txt | 10 +- src/agent/persistence/include/column.hpp | 2 + src/agent/persistence/include/persistence.hpp | 97 ++++ .../include/persistence_factory.hpp | 24 + .../persistence/include/sqlite_manager.hpp | 122 ---- .../persistence/src/persistence_factory.cpp | 14 + src/agent/persistence/src/sqlite_manager.cpp | 544 +++++++++--------- src/agent/persistence/src/sqlite_manager.hpp | 139 +++++ src/agent/persistence/tests/CMakeLists.txt | 2 +- .../persistence/tests/sqlite_manager_test.cpp | 21 +- 24 files changed, 601 insertions(+), 605 deletions(-) delete mode 100644 src/agent/multitype_queue/include/persistence.hpp delete mode 100644 src/agent/multitype_queue/include/persistence_factory.hpp delete mode 100644 src/agent/multitype_queue/src/persistence_factory.cpp create mode 100644 src/agent/persistence/include/persistence.hpp create mode 100644 src/agent/persistence/include/persistence_factory.hpp delete mode 100644 src/agent/persistence/include/sqlite_manager.hpp create mode 100644 src/agent/persistence/src/persistence_factory.cpp create mode 100644 src/agent/persistence/src/sqlite_manager.hpp diff --git a/src/agent/agent_info/CMakeLists.txt b/src/agent/agent_info/CMakeLists.txt index d1f5aceac5..fabe640508 100644 --- a/src/agent/agent_info/CMakeLists.txt +++ b/src/agent/agent_info/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(AgentInfo src/agent_info.cpp src/agent_info_persistance.cpp) target_include_directories(AgentInfo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(AgentInfo PUBLIC nlohmann_json::nlohmann_json Config PRIVATE SQLiteManager Boost::uuid Logger) +target_link_libraries(AgentInfo PUBLIC nlohmann_json::nlohmann_json Config PRIVATE Persistence Boost::uuid Logger) if(MSVC) target_link_libraries(AgentInfo PRIVATE bcrypt) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 2f4d1cf8d8..8fee4455bb 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -2,7 +2,9 @@ #include -using namespace sqlite_manager; +#include +#include +#include namespace { @@ -27,7 +29,7 @@ AgentInfoPersistance::AgentInfoPersistance(const std::string& dbFolderPath) try { - m_db = std::make_unique(dbFilePath); + m_db = PersistenceFactory::CreatePersistence(PersistenceFactory::PersistenceType::SQLITE3, dbFilePath); if (!m_db->TableExists(AGENT_INFO_TABLE_NAME)) { @@ -70,10 +72,9 @@ void AgentInfoPersistance::CreateAgentInfoTable() { try { - const std::vector columns = { - ColumnKey(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, true, false), - ColumnKey(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, true, false), - ColumnKey(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, true, false, true)}; + const Keys columns = {ColumnKey(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, true, false), + ColumnKey(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, true, false), + ColumnKey(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, true, false, true)}; m_db->CreateTable(AGENT_INFO_TABLE_NAME, columns); } @@ -87,9 +88,8 @@ void AgentInfoPersistance::CreateAgentGroupTable() { try { - const std::vector columns = { - ColumnKey(AGENT_GROUP_ID_COLUMN_NAME, ColumnType::INTEGER, true, true, true), - ColumnKey(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, true, false)}; + const Keys columns = {ColumnKey(AGENT_GROUP_ID_COLUMN_NAME, ColumnType::INTEGER, true, true, true), + ColumnKey(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, true, false)}; m_db->CreateTable(AGENT_GROUP_TABLE_NAME, columns); } @@ -139,7 +139,7 @@ std::string AgentInfoPersistance::GetAgentInfoValue(const std::string& column) c try { - const std::vector columns = {ColumnName(column, ColumnType::TEXT)}; + const Names columns = {ColumnName(column, ColumnType::TEXT)}; const std::vector results = m_db->Select(AGENT_INFO_TABLE_NAME, columns); if (!results.empty() && !results[0].empty()) @@ -176,7 +176,7 @@ std::vector AgentInfoPersistance::GetGroups() const try { - const std::vector columns = {ColumnName(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT)}; + const Names columns = {ColumnName(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT)}; const std::vector results = m_db->Select(AGENT_GROUP_TABLE_NAME, columns); for (const auto& row : results) diff --git a/src/agent/agent_info/src/agent_info_persistance.hpp b/src/agent/agent_info/src/agent_info_persistance.hpp index 47f40c8f60..3ca1da461e 100644 --- a/src/agent/agent_info/src/agent_info_persistance.hpp +++ b/src/agent/agent_info/src/agent_info_persistance.hpp @@ -1,11 +1,11 @@ #pragma once -#include - #include #include #include +class Persistence; + /// @brief Manages persistence of agent information and groups in a SQLite database. class AgentInfoPersistance { @@ -89,6 +89,6 @@ class AgentInfoPersistance /// @return The value from the specified column as a string. std::string GetAgentInfoValue(const std::string& column) const; - /// @brief Unique pointer to the SQLite database manager instance. - std::unique_ptr m_db; + /// @brief Unique pointer to the persistence instance. + std::unique_ptr m_db; }; diff --git a/src/agent/agent_info/tests/CMakeLists.txt b/src/agent/agent_info/tests/CMakeLists.txt index 48f32e71e3..4e4ff6c449 100644 --- a/src/agent/agent_info/tests/CMakeLists.txt +++ b/src/agent/agent_info/tests/CMakeLists.txt @@ -3,11 +3,11 @@ find_package(GTest CONFIG REQUIRED) add_executable(agent_info_test agent_info_test.cpp) configure_target(agent_info_test) target_include_directories(agent_info_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) -target_link_libraries(agent_info_test PRIVATE AgentInfo SQLiteManager GTest::gtest) +target_link_libraries(agent_info_test PRIVATE AgentInfo Persistence GTest::gtest) add_test(NAME AgentInfoTest COMMAND agent_info_test) add_executable(agent_info_persistance_test agent_info_persistance_test.cpp) configure_target(agent_info_persistance_test) target_include_directories(agent_info_persistance_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) -target_link_libraries(agent_info_persistance_test PRIVATE AgentInfo SQLiteManager GTest::gtest) +target_link_libraries(agent_info_persistance_test PRIVATE AgentInfo Persistence GTest::gtest) add_test(NAME AgentInfoPersistanceTest COMMAND agent_info_persistance_test) diff --git a/src/agent/command_store/CMakeLists.txt b/src/agent/command_store/CMakeLists.txt index 677c1d391d..fe1b41af89 100644 --- a/src/agent/command_store/CMakeLists.txt +++ b/src/agent/command_store/CMakeLists.txt @@ -14,7 +14,7 @@ include(../../cmake/ConfigureTarget.cmake) configure_target(CommandStore) target_include_directories(CommandStore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) -target_link_libraries(CommandStore PUBLIC SQLiteManager ModuleCommand PRIVATE Logger) +target_link_libraries(CommandStore PUBLIC ModuleCommand PRIVATE Persistence Logger) if(BUILD_TESTS) enable_testing() diff --git a/src/agent/command_store/include/command_store.hpp b/src/agent/command_store/include/command_store.hpp index 6b8f353028..57481d77f9 100644 --- a/src/agent/command_store/include/command_store.hpp +++ b/src/agent/command_store/include/command_store.hpp @@ -1,12 +1,13 @@ #pragma once #include -#include #include #include #include +class Persistence; + namespace command_store { /// @brief CommandStore class @@ -17,8 +18,8 @@ namespace command_store class CommandStore { private: - /// @brief The SQLite database object - std::unique_ptr m_dataBase; + /// @brief Unique pointer to the persistence instance. + std::unique_ptr m_dataBase; /// @brief Gets the current timestamp in seconds /// @return The current timestamp in seconds @@ -34,6 +35,9 @@ namespace command_store /// @param dbFolderPath The path to the database folder CommandStore(const std::string& dbFolderPath); + /// @brief CommandStore destructor + ~CommandStore(); + /// @brief Clears all commands from the database /// @return True if successful, false otherwise bool Clear(); diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index d136ea6faa..21f007b2e7 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -7,7 +7,9 @@ #include -using namespace sqlite_manager; +#include +#include +#include namespace { @@ -47,11 +49,12 @@ namespace command_store try { - m_dataBase = std::make_unique(dbFilePath); + m_dataBase = + PersistenceFactory::CreatePersistence(PersistenceFactory::PersistenceType::SQLITE3, dbFilePath); if (!m_dataBase->TableExists(COMMAND_STORE_TABLE_NAME)) { - std::vector columns; + Keys columns; columns.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, true, false, true); columns.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, true, false, false); columns.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, true, false, false); @@ -77,6 +80,8 @@ namespace command_store } } + CommandStore::~CommandStore() = default; + bool CommandStore::Clear() { try diff --git a/src/agent/multitype_queue/CMakeLists.txt b/src/agent/multitype_queue/CMakeLists.txt index d00ebffa7f..3e20b2ace6 100644 --- a/src/agent/multitype_queue/CMakeLists.txt +++ b/src/agent/multitype_queue/CMakeLists.txt @@ -13,13 +13,14 @@ find_package(nlohmann_json REQUIRED) find_package(fmt REQUIRED) find_package(Boost REQUIRED COMPONENTS asio) -add_library(MultiTypeQueue src/sqlitestorage.cpp src/multitype_queue.cpp src/persistence_factory.cpp) +add_library(MultiTypeQueue src/sqlitestorage.cpp src/multitype_queue.cpp) target_include_directories(MultiTypeQueue PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(MultiTypeQueue PUBLIC + Persistence Config nlohmann_json::nlohmann_json Boost::asio diff --git a/src/agent/multitype_queue/include/multitype_queue.hpp b/src/agent/multitype_queue/include/multitype_queue.hpp index 8aeee4975b..fb1683bcdc 100644 --- a/src/agent/multitype_queue/include/multitype_queue.hpp +++ b/src/agent/multitype_queue/include/multitype_queue.hpp @@ -1,8 +1,7 @@ #pragma once #include -#include -#include +#include #include #include @@ -42,7 +41,7 @@ class MultiTypeQueue : public IMultiTypeQueue const std::chrono::milliseconds m_timeout; /// @brief class for persistence implementation - std::unique_ptr m_persistenceDest; + std::unique_ptr m_persistenceDest; /// @brief mutex for protecting the queue access std::mutex m_mtx; @@ -86,8 +85,7 @@ class MultiTypeQueue : public IMultiTypeQueue try { - m_persistenceDest = PersistenceFactory::createPersistence(PersistenceFactory::PersistenceType::SQLITE3, - {dbFilePath, m_vMessageTypeStrings}); + m_persistenceDest = std::make_unique(dbFilePath, m_vMessageTypeStrings); } catch (const std::exception& e) { diff --git a/src/agent/multitype_queue/include/persistence.hpp b/src/agent/multitype_queue/include/persistence.hpp deleted file mode 100644 index fa94c3763c..0000000000 --- a/src/agent/multitype_queue/include/persistence.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include - -#include -#include - -/** - * @brief Interface for persistence storage. - * - * This interface defines methods for storing, retrieving, and removing JSON messages. - */ -class Persistence -{ -public: - /** - * @brief Virtual destructor. - */ - virtual ~Persistence() = default; - - /** - * @brief Store a JSON message in the specified queue. - * - * @param message The JSON message to be stored. - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @param moduleType The type of the module. - * @param metadata The metadata message to store. - * @return int The number of messages stored. - */ - virtual int Store(const nlohmann::json& message, - const std::string& tableName, - const std::string& moduleName = "", - const std::string& moduleType = "", - const std::string& metadata = "") = 0; - - /** - * @brief Retrieve multiple JSON messages from the specified queue. - * - * @param n number of messages to be retrieved. - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @param moduleType The type of the module. - * @return nlohmann::json The retrieved JSON messages. - */ - virtual nlohmann::json RetrieveMultiple(int n, - const std::string& queueName, - const std::string& moduleName = "", - const std::string& moduleType = "") = 0; - - /** - * @brief Remove multiple JSON messages from the specified queue. - * - * @param n number of messages to be removed. - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @return int The number of messages removed. - */ - virtual int RemoveMultiple(int n, const std::string& queueName, const std::string& moduleName = "") = 0; - - /** - * @brief Get the quantity of elements stored in the specified queue. - * - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @return int The quantity of elements stored in the specified queue. - */ - virtual int GetElementCount(const std::string& queueName, const std::string& moduleName = "") = 0; - - /** - * @brief Get the bytes occupied by elements stored in the specified queue. - * - * @param queueName The name of the queue. - * @return size_t The bytes occupied by elements stored in the specified queue. - */ - virtual size_t GetElementsStoredSize(const std::string& queueName) = 0; - - /** - * @brief Retrieve multiple JSON messages based on size from the specified queue. - * - * @param n size occupied by the messages to be retrieved. - * @param queueName The name of the queue. - * @param moduleName The name of the module. - * @param moduleType The type of the module. - * @return nlohmann::json The retrieved JSON messages. - */ - virtual nlohmann::json RetrieveBySize(size_t n, - const std::string& queueName, - const std::string& moduleName = "", - const std::string& moduleType = "") = 0; -}; diff --git a/src/agent/multitype_queue/include/persistence_factory.hpp b/src/agent/multitype_queue/include/persistence_factory.hpp deleted file mode 100644 index 0fdac483cb..0000000000 --- a/src/agent/multitype_queue/include/persistence_factory.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -/** - * @brief Class to create a persistence. - * - */ -class PersistenceFactory -{ -public: - /** - * @brief Types of persistence enum - * - */ - enum class PersistenceType - { - SQLITE3 - }; - - /** - * @brief Create a persistence - */ - static std::unique_ptr createPersistence(PersistenceType type, const std::vector& args); -}; diff --git a/src/agent/multitype_queue/include/sqlitestorage.hpp b/src/agent/multitype_queue/include/sqlitestorage.hpp index ee950cd654..11abcfeae5 100644 --- a/src/agent/multitype_queue/include/sqlitestorage.hpp +++ b/src/agent/multitype_queue/include/sqlitestorage.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include #include #include @@ -18,7 +16,7 @@ * This class provides methods to store, retrieve, and remove JSON messages * in a SQLite database. */ -class SQLiteStorage : public Persistence +class SQLiteStorage { public: SQLiteStorage(const std::string& dbName, const std::vector& tableName); @@ -46,7 +44,7 @@ class SQLiteStorage : public Persistence /** * @brief Destructor. */ - ~SQLiteStorage() override; + ~SQLiteStorage() = default; /** * @brief Store a JSON message in the storage. @@ -62,7 +60,7 @@ class SQLiteStorage : public Persistence const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = "", - const std::string& metadata = "") override; + const std::string& metadata = ""); /** * @brief Retrieve multiple JSON messages. @@ -76,7 +74,7 @@ class SQLiteStorage : public Persistence nlohmann::json RetrieveMultiple(int n, const std::string& tableName, const std::string& moduleName = "", - const std::string& moduleType = "") override; + const std::string& moduleType = ""); /** * @brief Remove multiple JSON messages. @@ -86,7 +84,7 @@ class SQLiteStorage : public Persistence * @param moduleName The name of the module that created the message. * @return The number of removed elements. */ - int RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName = "") override; + int RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName = ""); /** * @brief Get the number of elements in the table. @@ -94,7 +92,7 @@ class SQLiteStorage : public Persistence * @param moduleName The name of the module that created the message. * @return The number of elements in the table. */ - int GetElementCount(const std::string& tableName, const std::string& moduleName = "") override; + int GetElementCount(const std::string& tableName, const std::string& moduleName = ""); /** * @brief Get the bytes occupied by elements stored in the specified queue. @@ -102,7 +100,7 @@ class SQLiteStorage : public Persistence * @param tableName The name of the table. * @return size_t The bytes occupied by elements stored in the specified queue. */ - size_t GetElementsStoredSize(const std::string& tableName) override; + size_t GetElementsStoredSize(const std::string& tableName); /** * @brief Retrieve multiple JSON messages based on size from the specified queue. @@ -116,7 +114,7 @@ class SQLiteStorage : public Persistence nlohmann::json RetrieveBySize(size_t n, const std::string& tableName, const std::string& moduleName = "", - const std::string& moduleType = "") override; + const std::string& moduleType = ""); private: /** diff --git a/src/agent/multitype_queue/src/persistence_factory.cpp b/src/agent/multitype_queue/src/persistence_factory.cpp deleted file mode 100644 index 61b69299cd..0000000000 --- a/src/agent/multitype_queue/src/persistence_factory.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -#include -#include - -std::unique_ptr PersistenceFactory::createPersistence(PersistenceType type, - const std::vector& args) -{ - if (type == PersistenceType::SQLITE3) - { - if (args.size() != 2 || !std::any_cast(&args[0]) || - !std::any_cast>(&args[1])) - { - throw std::invalid_argument("SQLite3 requires db name and table names as arguments"); - } - return std::make_unique(std::any_cast(args[0]), - std::any_cast>(args[1])); - } - throw std::runtime_error("Unknown persistence type"); -} diff --git a/src/agent/multitype_queue/src/sqlitestorage.cpp b/src/agent/multitype_queue/src/sqlitestorage.cpp index 034d5359de..f3342c6be8 100644 --- a/src/agent/multitype_queue/src/sqlitestorage.cpp +++ b/src/agent/multitype_queue/src/sqlitestorage.cpp @@ -29,8 +29,6 @@ SQLiteStorage::SQLiteStorage(const std::string& dbName, const std::vector; +using Keys = std::vector; using Row = std::vector; using Criteria = std::vector; diff --git a/src/agent/persistence/include/persistence.hpp b/src/agent/persistence/include/persistence.hpp new file mode 100644 index 0000000000..24f79e0a3d --- /dev/null +++ b/src/agent/persistence/include/persistence.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include "column.hpp" + +#include +#include + +using TransactionId = unsigned int; + +/// @brief Interface for persistence storage. +class Persistence +{ +public: + /// @brief Virtual destructor. + virtual ~Persistence() = default; + + /// @brief Checks if a specified table exists in the database. + /// @param tableName The name of the table to check. + /// @return True if the table exists, false otherwise. + virtual bool TableExists(const std::string& tableName) = 0; + + /// @brief Creates a new table with specified keys if it doesn't already exist. + /// @param tableName The name of the table to create. + /// @param cols Keys specifying the table schema. + virtual void CreateTable(const std::string& tableName, const Keys& cols) = 0; + + /// @brief Inserts data into a specified table. + /// @param tableName The name of the table where data is inserted. + /// @param cols Row with values to insert. + virtual void Insert(const std::string& tableName, const Row& cols) = 0; + + /// @brief Updates rows in a specified table with optional criteria. + /// @param tableName The name of the table to update. + /// @param fields Row with new values to set. + /// @param selCriteria Optional criteria to filter rows to update. + /// @param logOp Logical operator to combine selection criteria. + virtual void Update(const std::string& tableName, + const Row& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) = 0; + + /// @brief Removes rows from a specified table with optional criteria. + /// @param tableName The name of the table to delete from. + /// @param selCriteria Optional criteria to filter rows to delete. + /// @param logOp Logical operator to combine selection criteria. + virtual void Remove(const std::string& tableName, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) = 0; + + /// @brief Drops a specified table from the database. + /// @param tableName The name of the table to drop. + virtual void DropTable(const std::string& tableName) = 0; + + /// @brief Selects rows from a specified table with optional criteria. + /// @param tableName The name of the table to select from. + /// @param fields Names to retrieve. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @param orderBy Names to order the results by. + /// @param orderType The order type (ASC or DESC). + /// @param limit The maximum number of rows to retrieve. + /// @return A vector of rows matching the criteria. + virtual std::vector Select(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND, + const Names& orderBy = {}, + OrderType orderType = OrderType::ASC, + unsigned int limit = 0) = 0; + + /// @brief Retrieves the number of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @return The number of rows in the table. + virtual int GetCount(const std::string& tableName, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) = 0; + + /// @brief Retrieves the size in bytes of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param fields Names to retrieve. + /// @return The size in bytes of the rows in the table. + virtual size_t GetSize(const std::string& tableName, const Names& fields) = 0; + + /// @brief Begins a transaction in the database. + /// @return The transaction ID. + virtual TransactionId BeginTransaction() = 0; + + /// @brief Commits a transaction in the database. + /// @param transactionId The transaction to commit. + virtual void CommitTransaction(TransactionId transactionId) = 0; + + /// @brief Rolls back a transaction in the database. + /// @param transactionId The transaction to rollback. + virtual void RollbackTransaction(TransactionId transactionId) = 0; +}; diff --git a/src/agent/persistence/include/persistence_factory.hpp b/src/agent/persistence/include/persistence_factory.hpp new file mode 100644 index 0000000000..f51a1db460 --- /dev/null +++ b/src/agent/persistence/include/persistence_factory.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include +#include +#include + +/// @brief Class to create a persistence. +class PersistenceFactory +{ +public: + /// @brief Types of persistence enum. + enum class PersistenceType + { + SQLITE3 + }; + + /// @brief Create a persistence. + /// @param type Type of persistence. + /// @param dbName Name of the database. + /// @return A unique pointer to the created persistence. + static std::unique_ptr CreatePersistence(PersistenceType type, const std::string& dbName); +}; diff --git a/src/agent/persistence/include/sqlite_manager.hpp b/src/agent/persistence/include/sqlite_manager.hpp deleted file mode 100644 index 548d7e92fb..0000000000 --- a/src/agent/persistence/include/sqlite_manager.hpp +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include - -#include "column.hpp" - -#include -#include -#include -#include - -namespace sqlite_manager -{ - /// @brief Manages SQLite database operations, including table creation, data insertion, updating, and selection. - class SQLiteManager - { - public: - /// @brief Initializes a SQLiteManager instance and opens the specified database. - /// @param dbName The name of the SQLite database file. - SQLiteManager(const std::string& dbName); - - /// @brief Checks if a specified table exists in the database. - /// @param tableName The name of the table to check. - /// @return True if the table exists, false otherwise. - bool TableExists(const std::string& tableName); - - /// @brief Creates a new table with specified columns if it doesn't already exist. - /// @param tableName The name of the table to create. - /// @param cols A vector of columns specifying the table schema. - void CreateTable(const std::string& tableName, const std::vector& cols); - - /// @brief Inserts data into a specified table. - /// @param tableName The name of the table where data is inserted. - /// @param cols A vector of columns with values to insert. - void Insert(const std::string& tableName, const Row& cols); - - /// @brief Updates rows in a specified table with optional criteria. - /// @param tableName The name of the table to update. - /// @param fields A vector of columns with new values to set. - /// @param selCriteria Optional criteria to filter rows to update. - /// @param logOp Logical operator to combine selection criteria. - void Update(const std::string& tableName, - const Row& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); - - /// @brief Removes rows from a specified table with optional criteria. - /// @param tableName The name of the table to delete from. - /// @param selCriteria Optional criteria to filter rows to delete. - /// @param logOp Logical operator to combine selection criteria. - void Remove(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); - - /// @brief Drops a specified table from the database. - /// @param tableName The name of the table to drop. - void DropTable(const std::string& tableName); - - /// @brief Selects rows from a specified table with optional criteria. - /// @param tableName The name of the table to select from. - /// @param fields A vector of columns to retrieve. - /// @param selCriteria Optional selection criteria to filter rows. - /// @param logOp Logical operator to combine selection criteria (AND/OR). - /// @param orderBy A vector of columns to order the results by. - /// @param orderType The order type (ASC or DESC). - /// @param limit The maximum number of rows to retrieve. - /// @return A vector of rows matching the criteria. - std::vector Select(const std::string& tableName, - const std::vector& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND, - const std::vector& orderBy = {}, - OrderType orderType = OrderType::ASC, - unsigned int limit = 0); - - /// @brief Retrieves the number of rows in a specified table. - /// @param tableName The name of the table to count rows in. - /// @param selCriteria Optional selection criteria to filter rows. - /// @param logOp Logical operator to combine selection criteria (AND/OR). - /// @return The number of rows in the table. - int GetCount(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND); - - /// @brief Retrieves the size in bytes of rows in a specified table. - /// @param tableName The name of the table to count rows in. - /// @param fields A vector of columns to retrieve. - /// @return The size in bytes of the rows in the table. - size_t GetSize(const std::string& tableName, const std::vector& fields); - - /// @brief Begins a transaction in the SQLite database. - /// @return A SQLite transaction object. - SQLite::Transaction BeginTransaction(); - - /// @brief Commits a transaction in the SQLite database. - /// @param transaction The transaction to commit. - void CommitTransaction(SQLite::Transaction& transaction); - - /// @brief Rolls back a transaction in the SQLite database. - /// @param transaction The transaction to roll back. - void RollbackTransaction(SQLite::Transaction& transaction); - - private: - /// @brief Converts SQLite data types to ColumnType enums. - /// @param type SQLite data type integer code. - /// @return Corresponding ColumnType enum. - ColumnType ColumnTypeFromSQLiteType(const int type) const; - - /// @brief Executes a raw SQL query on the database. - /// @param query The SQL query string to execute. - void Execute(const std::string& query); - - /// @brief Mutex for thread-safe operations. - std::mutex m_mutex; - - /// @brief The name of the SQLite database file. - const std::string m_dbName; - - /// @brief Pointer to the SQLite database connection. - std::unique_ptr m_db; - }; -} // namespace sqlite_manager diff --git a/src/agent/persistence/src/persistence_factory.cpp b/src/agent/persistence/src/persistence_factory.cpp new file mode 100644 index 0000000000..67ef66078a --- /dev/null +++ b/src/agent/persistence/src/persistence_factory.cpp @@ -0,0 +1,14 @@ +#include +#include + +#include +#include + +std::unique_ptr PersistenceFactory::CreatePersistence(PersistenceType type, const std::string& dbName) +{ + if (type == PersistenceType::SQLITE3) + { + return std::make_unique(dbName); + } + throw std::runtime_error("Unknown persistence type"); +} diff --git a/src/agent/persistence/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp index 7d4d5eaf41..56d6dc204d 100644 --- a/src/agent/persistence/src/sqlite_manager.cpp +++ b/src/agent/persistence/src/sqlite_manager.cpp @@ -5,370 +5,368 @@ #include #include -namespace sqlite_manager +const std::map MAP_COL_TYPE_STRING { + {ColumnType::INTEGER, "INTEGER"}, {ColumnType::TEXT, "TEXT"}, {ColumnType::REAL, "REAL"}}; +const std::map MAP_LOGOP_STRING {{LogicalOperator::AND, "AND"}, + {LogicalOperator::OR, "OR"}}; +const std::map MAP_ORDER_STRING {{OrderType::ASC, "ASC"}, {OrderType::DESC, "DESC"}}; + +ColumnType SQLiteManager::ColumnTypeFromSQLiteType(const int type) const { - const std::map MAP_COL_TYPE_STRING { - {ColumnType::INTEGER, "INTEGER"}, {ColumnType::TEXT, "TEXT"}, {ColumnType::REAL, "REAL"}}; - const std::map MAP_LOGOP_STRING {{LogicalOperator::AND, "AND"}, - {LogicalOperator::OR, "OR"}}; - const std::map MAP_ORDER_STRING {{OrderType::ASC, "ASC"}, {OrderType::DESC, "DESC"}}; + if (type == SQLite::INTEGER) + return ColumnType::INTEGER; - ColumnType SQLiteManager::ColumnTypeFromSQLiteType(const int type) const - { - if (type == SQLite::INTEGER) - return ColumnType::INTEGER; + if (type == SQLite::FLOAT) + return ColumnType::REAL; - if (type == SQLite::FLOAT) - return ColumnType::REAL; + return ColumnType::TEXT; +} - return ColumnType::TEXT; - } +SQLiteManager::SQLiteManager(const std::string& dbName) + : m_dbName(dbName) + , m_db(std::make_unique(dbName, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE)) +{ + m_db->exec("PRAGMA journal_mode=WAL;"); +} - SQLiteManager::SQLiteManager(const std::string& dbName) - : m_dbName(dbName) - , m_db(std::make_unique(dbName, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE)) +bool SQLiteManager::TableExists(const std::string& table) +{ + try { - m_db->exec("PRAGMA journal_mode=WAL;"); + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "';"); + return query.executeStep(); } - - bool SQLiteManager::TableExists(const std::string& table) + catch (const std::exception& e) { - try - { - std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, - "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "';"); - return query.executeStep(); - } - catch (const std::exception& e) - { - LogError("Failed to check if table exists: {}.", e.what()); - return false; - } + LogError("Failed to check if table exists: {}.", e.what()); + return false; } +} - void SQLiteManager::CreateTable(const std::string& tableName, const std::vector& cols) +void SQLiteManager::CreateTable(const std::string& tableName, const Keys& cols) +{ + std::vector pk; + std::vector fields; + for (const auto& col : cols) { - std::vector pk; - std::vector fields; - for (const auto& col : cols) + std::string field = + fmt::format("{} {}{}", col.Name, MAP_COL_TYPE_STRING.at(col.Type), (col.NotNull) ? " NOT NULL" : ""); + if (col.PrimaryKey) { - std::string field = - fmt::format("{} {}{}", col.Name, MAP_COL_TYPE_STRING.at(col.Type), (col.NotNull) ? " NOT NULL" : ""); - if (col.PrimaryKey) - { - pk.push_back(col.AutoIncrement ? fmt::format("{} AUTOINCREMENT", col.Name) : col.Name); - } - fields.push_back(field); + pk.push_back(col.AutoIncrement ? fmt::format("{} AUTOINCREMENT", col.Name) : col.Name); } + fields.push_back(field); + } - std::string primaryKey = pk.empty() ? "" : fmt::format(", PRIMARY KEY({})", fmt::join(pk, ", ")); - std::string queryString = fmt::format( - "CREATE TABLE IF NOT EXISTS {} ({}{})", tableName, fmt::format("{}", fmt::join(fields, ", ")), primaryKey); + std::string primaryKey = pk.empty() ? "" : fmt::format(", PRIMARY KEY({})", fmt::join(pk, ", ")); + std::string queryString = fmt::format( + "CREATE TABLE IF NOT EXISTS {} ({}{})", tableName, fmt::format("{}", fmt::join(fields, ", ")), primaryKey); - Execute(queryString); - } + Execute(queryString); +} - void SQLiteManager::Insert(const std::string& tableName, const Row& cols) - { - std::vector names; - std::vector values; +void SQLiteManager::Insert(const std::string& tableName, const Row& cols) +{ + std::vector names; + std::vector values; - for (const auto& col : cols) + for (const auto& col : cols) + { + names.push_back(col.Name); + if (col.Type == ColumnType::TEXT) { - names.push_back(col.Name); - if (col.Type == ColumnType::TEXT) - { - values.push_back(fmt::format("'{}'", col.Value)); - } - else - values.push_back(col.Value); + values.push_back(fmt::format("'{}'", col.Value)); } + else + values.push_back(col.Value); + } + + std::string queryString = + fmt::format("INSERT INTO {} ({}) VALUES ({})", tableName, fmt::join(names, ", "), fmt::join(values, ", ")); - std::string queryString = - fmt::format("INSERT INTO {} ({}) VALUES ({})", tableName, fmt::join(names, ", "), fmt::join(values, ", ")); + Execute(queryString); +} - Execute(queryString); +void SQLiteManager::Update(const std::string& tableName, + const Row& fields, + const Criteria& selCriteria, + LogicalOperator logOp) +{ + if (fields.empty()) + { + LogError("Error: Missing update fields."); + throw; } - void SQLiteManager::Update(const std::string& tableName, - const Row& fields, - const Criteria& selCriteria, - LogicalOperator logOp) + std::vector setFields; + for (const auto& col : fields) { - if (fields.empty()) + if (col.Type == ColumnType::TEXT) { - LogError("Error: Missing update fields."); - throw; + setFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); } + else + { + setFields.push_back(fmt::format("{}={}", col.Name, col.Value)); + } + } + std::string updateValues = fmt::format("{}", fmt::join(setFields, ", ")); - std::vector setFields; - for (const auto& col : fields) + std::string whereClause; + if (!selCriteria.empty()) + { + std::vector conditions; + for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) { - setFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); } else { - setFields.push_back(fmt::format("{}={}", col.Name, col.Value)); + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); } } - std::string updateValues = fmt::format("{}", fmt::join(setFields, ", ")); - - std::string whereClause; - if (!selCriteria.empty()) - { - std::vector conditions; - for (const auto& col : selCriteria) - { - if (col.Type == ColumnType::TEXT) - { - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - } - else - { - conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); - } - } - whereClause = - fmt::format(" WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); - } + whereClause = fmt::format(" WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } - std::string queryString = fmt::format("UPDATE {} SET {}{}", tableName, updateValues, whereClause); + std::string queryString = fmt::format("UPDATE {} SET {}{}", tableName, updateValues, whereClause); - Execute(queryString); - } + Execute(queryString); +} - void SQLiteManager::Remove(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) +void SQLiteManager::Remove(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) +{ + std::string whereClause; + if (!selCriteria.empty()) { - std::string whereClause; - if (!selCriteria.empty()) + std::vector critFields; + for (const auto& col : selCriteria) { - std::vector critFields; - for (const auto& col : selCriteria) + if (col.Type == ColumnType::TEXT) { - if (col.Type == ColumnType::TEXT) - { - critFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - } - else - { - critFields.push_back(fmt::format("{}={}", col.Name, col.Value)); - } + critFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + } + else + { + critFields.push_back(fmt::format("{}={}", col.Name, col.Value)); } - whereClause = - fmt::format(" WHERE {}", fmt::join(critFields, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } + whereClause = fmt::format(" WHERE {}", fmt::join(critFields, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } - std::string queryString = fmt::format("DELETE FROM {}{}", tableName, whereClause); + std::string queryString = fmt::format("DELETE FROM {}{}", tableName, whereClause); - Execute(queryString); - } + Execute(queryString); +} - void SQLiteManager::DropTable(const std::string& tableName) - { - std::string queryString = fmt::format("DROP TABLE {}", tableName); +void SQLiteManager::DropTable(const std::string& tableName) +{ + std::string queryString = fmt::format("DROP TABLE {}", tableName); - Execute(queryString); - } + Execute(queryString); +} - void SQLiteManager::Execute(const std::string& query) +void SQLiteManager::Execute(const std::string& query) +{ + try { - try - { - std::lock_guard lock(m_mutex); - m_db->exec(query); - } - catch (const std::exception& e) + std::lock_guard lock(m_mutex); + m_db->exec(query); + } + catch (const std::exception& e) + { + LogError("Error during database operation: {}.", e.what()); + throw; + } +} + +std::vector SQLiteManager::Select(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria, + LogicalOperator logOp, + const Names& orderBy, + OrderType orderType, + unsigned int limit) +{ + std::string selectedFields; + if (fields.empty()) + { + selectedFields = "*"; + } + else + { + std::vector fieldNames; + fieldNames.reserve(fields.size()); + + for (const auto& col : fields) { - LogError("Error during database operation: {}.", e.what()); - throw; + fieldNames.push_back(col.Name); } + selectedFields = fmt::format("{}", fmt::join(fieldNames, ", ")); } - std::vector SQLiteManager::Select(const std::string& tableName, - const std::vector& fields, - const Criteria& selCriteria, - LogicalOperator logOp, - const std::vector& orderBy, - OrderType orderType, - unsigned int limit) + std::string condition; + if (!selCriteria.empty()) { - std::string selectedFields; - if (fields.empty()) - { - selectedFields = "*"; - } - else + std::vector conditions; + for (const auto& col : selCriteria) { - std::vector fieldNames; - fieldNames.reserve(fields.size()); - - for (const auto& col : fields) - { - fieldNames.push_back(col.Name); - } - selectedFields = fmt::format("{}", fmt::join(fieldNames, ", ")); + if (col.Type == ColumnType::TEXT) + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + else + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); } + condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } - std::string condition; - if (!selCriteria.empty()) + if (!orderBy.empty()) + { + std::vector orderFields; + orderFields.reserve(orderBy.size()); + for (const auto& col : orderBy) { - std::vector conditions; - for (const auto& col : selCriteria) - { - if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - else - conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); - } - condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + orderFields.push_back(col.Name); } + condition += fmt::format(" ORDER BY {}", fmt::join(orderFields, ", ")); + condition += fmt::format(" {}", MAP_ORDER_STRING.at(orderType)); + } - if (!orderBy.empty()) - { - std::vector orderFields; - orderFields.reserve(orderBy.size()); - for (const auto& col : orderBy) - { - orderFields.push_back(col.Name); - } - condition += fmt::format(" ORDER BY {}", fmt::join(orderFields, ", ")); - condition += fmt::format(" {}", MAP_ORDER_STRING.at(orderType)); - } + if (limit > 0) + { + condition += fmt::format(" LIMIT {}", limit); + } - if (limit > 0) - { - condition += fmt::format(" LIMIT {}", limit); - } + std::string queryString = fmt::format("SELECT {} FROM {} {}", selectedFields, tableName, condition); - std::string queryString = fmt::format("SELECT {} FROM {} {}", selectedFields, tableName, condition); + std::vector results; + try + { + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, queryString); - std::vector results; - try + while (query.executeStep()) { - std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, queryString); - - while (query.executeStep()) + int nColumns = query.getColumnCount(); + Row queryFields; + queryFields.reserve(static_cast(nColumns)); + for (int i = 0; i < nColumns; i++) { - int nColumns = query.getColumnCount(); - Row queryFields; - queryFields.reserve(static_cast(nColumns)); - for (int i = 0; i < nColumns; i++) - { - queryFields.emplace_back(query.getColumn(i).getName(), - ColumnTypeFromSQLiteType(query.getColumn(i).getType()), - query.getColumn(i).getString()); - } - results.push_back(queryFields); + queryFields.emplace_back(query.getColumn(i).getName(), + ColumnTypeFromSQLiteType(query.getColumn(i).getType()), + query.getColumn(i).getString()); } + results.push_back(queryFields); } - catch (const std::exception& e) - { - LogError("Error during Select operation: {}.", e.what()); - throw; - } - return results; } + catch (const std::exception& e) + { + LogError("Error during Select operation: {}.", e.what()); + throw; + } + return results; +} - int SQLiteManager::GetCount(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) +int SQLiteManager::GetCount(const std::string& tableName, const Criteria& selCriteria, LogicalOperator logOp) +{ + std::string condition; + if (!selCriteria.empty()) { - std::string condition; - if (!selCriteria.empty()) + std::vector conditions; + for (const auto& col : selCriteria) { - std::vector conditions; - for (const auto& col : selCriteria) - { - if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); - else - conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); - } - condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + if (col.Type == ColumnType::TEXT) + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + else + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); } + condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } - std::string queryString = fmt::format("SELECT COUNT(*) FROM {} {}", tableName, condition); + std::string queryString = fmt::format("SELECT COUNT(*) FROM {} {}", tableName, condition); - int count = 0; - try - { - std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, queryString); + int count = 0; + try + { + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, queryString); - if (query.executeStep()) - { - count = query.getColumn(0).getInt(); - } - else - { - LogError("Error getting element count."); - } + if (query.executeStep()) + { + count = query.getColumn(0).getInt(); } - catch (const std::exception& e) + else { - LogError("Error during GetCount operation: {}.", e.what()); - throw; + LogError("Error getting element count."); } - return count; } + catch (const std::exception& e) + { + LogError("Error during GetCount operation: {}.", e.what()); + throw; + } + return count; +} - size_t SQLiteManager::GetSize(const std::string& tableName, const std::vector& fields) +size_t SQLiteManager::GetSize(const std::string& tableName, const Names& fields) +{ + if (fields.empty()) { - if (fields.empty()) - { - LogError("Error: Missing size fields."); - throw; - } + LogError("Error: Missing size fields."); + throw; + } - std::string selectedFields; - std::vector fieldNames; - fieldNames.reserve(fields.size()); + std::string selectedFields; + std::vector fieldNames; + fieldNames.reserve(fields.size()); - for (const auto& col : fields) - { - fieldNames.push_back("LENGTH(" + col.Name + ")"); - } - selectedFields = fmt::format("{}", fmt::join(fieldNames, " + ")); + for (const auto& col : fields) + { + fieldNames.push_back("LENGTH(" + col.Name + ")"); + } + selectedFields = fmt::format("{}", fmt::join(fieldNames, " + ")); - std::string queryString = fmt::format("SELECT SUM({}) AS total_bytes FROM {}", selectedFields, tableName); + std::string queryString = fmt::format("SELECT SUM({}) AS total_bytes FROM {}", selectedFields, tableName); - size_t count = 0; - try - { - std::lock_guard lock(m_mutex); - SQLite::Statement query(*m_db, queryString); + size_t count = 0; + try + { + std::lock_guard lock(m_mutex); + SQLite::Statement query(*m_db, queryString); - if (query.executeStep()) - { - count = query.getColumn(0).getUInt(); - } - else - { - LogError("Error getting element count."); - } + if (query.executeStep()) + { + count = query.getColumn(0).getUInt(); } - catch (const std::exception& e) + else { - LogError("Error during GetSize operation: {}.", e.what()); - throw; + LogError("Error getting element count."); } - return count; } - - SQLite::Transaction SQLiteManager::BeginTransaction() + catch (const std::exception& e) { - return SQLite::Transaction(*m_db); + LogError("Error during GetSize operation: {}.", e.what()); + throw; } + return count; +} - void SQLiteManager::CommitTransaction(SQLite::Transaction& transaction) - { - transaction.commit(); - } +TransactionId SQLiteManager::BeginTransaction() +{ + TransactionId transactionId = m_nextTransactionId++; + m_transactions.emplace(transactionId, std::make_unique(*m_db)); + return transactionId; +} - void SQLiteManager::RollbackTransaction(SQLite::Transaction& transaction) - { - transaction.rollback(); - } -} // namespace sqlite_manager +void SQLiteManager::CommitTransaction(TransactionId transactionId) +{ + m_transactions.at(transactionId)->commit(); + m_transactions.erase(transactionId); +} + +void SQLiteManager::RollbackTransaction(TransactionId transactionId) +{ + m_transactions.at(transactionId)->rollback(); + m_transactions.erase(transactionId); +} diff --git a/src/agent/persistence/src/sqlite_manager.hpp b/src/agent/persistence/src/sqlite_manager.hpp new file mode 100644 index 0000000000..f9241ffd89 --- /dev/null +++ b/src/agent/persistence/src/sqlite_manager.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include + +#include "column.hpp" +#include "persistence.hpp" + +#include +#include +#include +#include +#include + +/// @brief Manages SQLite database operations, including table creation, data insertion, updating, and selection. +class SQLiteManager : public Persistence +{ +public: + /// @brief Initializes a SQLiteManager instance and opens the specified database. + /// @param dbName The name of the SQLite database file. + SQLiteManager(const std::string& dbName); + + /// @brief Delete copy constructor. + SQLiteManager(const SQLiteManager&) = delete; + + /// @brief Delete copy assignment operator. + SQLiteManager& operator=(const SQLiteManager&) = delete; + + /// @brief Delete move constructor. + SQLiteManager(SQLiteManager&&) = delete; + + /// @brief Delete move assignment operator. + SQLiteManager& operator=(SQLiteManager&&) = delete; + + /// @brief Checks if a specified table exists in the database. + /// @param tableName The name of the table to check. + /// @return True if the table exists, false otherwise. + bool TableExists(const std::string& tableName) override; + + /// @brief Creates a new table with specified keys if it doesn't already exist. + /// @param tableName The name of the table to create. + /// @param cols Keys specifying the table schema. + void CreateTable(const std::string& tableName, const Keys& cols) override; + + /// @brief Inserts data into a specified table. + /// @param tableName The name of the table where data is inserted. + /// @param cols Row with values to insert. + void Insert(const std::string& tableName, const Row& cols) override; + + /// @brief Updates rows in a specified table with optional criteria. + /// @param tableName The name of the table to update. + /// @param fields Row with new values to set. + /// @param selCriteria Optional criteria to filter rows to update. + /// @param logOp Logical operator to combine selection criteria. + void Update(const std::string& tableName, + const Row& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) override; + + /// @brief Removes rows from a specified table with optional criteria. + /// @param tableName The name of the table to delete from. + /// @param selCriteria Optional criteria to filter rows to delete. + /// @param logOp Logical operator to combine selection criteria. + void Remove(const std::string& tableName, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) override; + + /// @brief Drops a specified table from the database. + /// @param tableName The name of the table to drop. + void DropTable(const std::string& tableName) override; + + /// @brief Selects rows from a specified table with optional criteria. + /// @param tableName The name of the table to select from. + /// @param fields Names to retrieve. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @param orderBy Names to order the results by. + /// @param orderType The order type (ASC or DESC). + /// @param limit The maximum number of rows to retrieve. + /// @return A vector of rows matching the criteria. + std::vector Select(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND, + const Names& orderBy = {}, + OrderType orderType = OrderType::ASC, + unsigned int limit = 0) override; + + /// @brief Retrieves the number of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). + /// @return The number of rows in the table. + int GetCount(const std::string& tableName, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) override; + + /// @brief Retrieves the size in bytes of rows in a specified table. + /// @param tableName The name of the table to count rows in. + /// @param fields Names to retrieve. + /// @return The size in bytes of the rows in the table. + size_t GetSize(const std::string& tableName, const Names& fields) override; + + /// @brief Begins a transaction in the SQLite database. + /// @return The transaction ID. + TransactionId BeginTransaction() override; + + /// @brief Commits a transaction in the SQLite database. + /// @param transactionId The transaction to commit. + void CommitTransaction(TransactionId transactionId) override; + + /// @brief Rolls back a transaction in the SQLite database. + /// @param transactionId The transaction to rollback. + void RollbackTransaction(TransactionId transactionId) override; + +private: + /// @brief Converts SQLite data types to ColumnType enums. + /// @param type SQLite data type integer code. + /// @return Corresponding ColumnType enum. + ColumnType ColumnTypeFromSQLiteType(const int type) const; + + /// @brief Executes a raw SQL query on the database. + /// @param query The SQL query string to execute. + void Execute(const std::string& query); + + /// @brief Mutex for thread-safe operations. + std::mutex m_mutex; + + /// @brief The name of the SQLite database file. + const std::string m_dbName; + + /// @brief Pointer to the SQLite database connection. + std::unique_ptr m_db; + + /// @brief Map of open transactions. + std::map> m_transactions; + + /// @brief The next available transaction ID. + TransactionId m_nextTransactionId = 0; +}; diff --git a/src/agent/persistence/tests/CMakeLists.txt b/src/agent/persistence/tests/CMakeLists.txt index 5f06f13402..f80430db17 100644 --- a/src/agent/persistence/tests/CMakeLists.txt +++ b/src/agent/persistence/tests/CMakeLists.txt @@ -3,7 +3,7 @@ find_package(GTest REQUIRED) add_executable(test_SQLiteManager sqlite_manager_test.cpp) configure_target(test_SQLiteManager) target_link_libraries(test_SQLiteManager PRIVATE - SQLiteManager + Persistence GTest::gtest GTest::gtest_main GTest::gmock diff --git a/src/agent/persistence/tests/sqlite_manager_test.cpp b/src/agent/persistence/tests/sqlite_manager_test.cpp index 4cec36a748..494ce610ba 100644 --- a/src/agent/persistence/tests/sqlite_manager_test.cpp +++ b/src/agent/persistence/tests/sqlite_manager_test.cpp @@ -6,8 +6,6 @@ #include #include -using namespace sqlite_manager; - class SQLiteManagerTest : public ::testing::Test { protected: @@ -160,7 +158,7 @@ TEST_F(SQLiteManagerTest, SelectTest) { AddTestData(); - std::vector cols; + Names cols; // all fields, no selection criteria std::vector ret = m_db->Select(m_tableName, cols); @@ -390,23 +388,6 @@ TEST_F(SQLiteManagerTest, TransactionTest) EXPECT_EQ(ret.size(), 0); - { - auto transaction = m_db->BeginTransaction(); - - m_db->Insert(m_tableName, - {ColumnValue("Name", ColumnType::TEXT, "TransactionName"), - ColumnValue("Status", ColumnType::TEXT, "TransactionStatus")}); - - m_db->Insert(m_tableName, - {ColumnValue("Name", ColumnType::TEXT, "TransactionName2"), - ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); - } - - // since transaction obejct ran out of scope without being committed we should find nothing - ret = m_db->Select(m_tableName, {}, {ColumnValue("Status", ColumnType::TEXT, "TransactionStatus2")}); - - EXPECT_EQ(ret.size(), 0); - { auto transaction = m_db->BeginTransaction(); From 6e4501bf2f75d0d38c3e48244d571116f9053a97 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Fri, 10 Jan 2025 13:57:33 +0000 Subject: [PATCH 10/18] refactor: remove sqlite references where not necessary --- src/agent/agent_info/include/agent_info.hpp | 2 +- .../agent_info/src/agent_info_persistance.hpp | 4 +- .../command_store/include/command_store.hpp | 2 +- src/agent/multitype_queue/CMakeLists.txt | 2 +- .../include/multitype_queue.hpp | 6 +-- .../{sqlitestorage.hpp => storage.hpp} | 24 +++++----- .../src/{sqlitestorage.cpp => storage.cpp} | 48 +++++++++---------- .../multitype_queue/tests/CMakeLists.txt | 10 ++-- ...qlitestorage_test.cpp => storage_test.cpp} | 48 +++++++++---------- src/agent/persistence/include/column.hpp | 2 +- 10 files changed, 74 insertions(+), 74 deletions(-) rename src/agent/multitype_queue/include/{sqlitestorage.hpp => storage.hpp} (88%) rename src/agent/multitype_queue/src/{sqlitestorage.cpp => storage.cpp} (84%) rename src/agent/multitype_queue/tests/{sqlitestorage_test.cpp => storage_test.cpp} (86%) diff --git a/src/agent/agent_info/include/agent_info.hpp b/src/agent/agent_info/include/agent_info.hpp index c22287fa10..a02b18c1d1 100644 --- a/src/agent/agent_info/include/agent_info.hpp +++ b/src/agent/agent_info/include/agent_info.hpp @@ -21,7 +21,7 @@ class AgentInfo /// information retrieval functions. It also generates a UUID for the agent if one /// does not already exist, and loads endpoint, metadata, and header information. /// - /// @param dbFolderPath Path to the SQLite database folder. + /// @param dbFolderPath Path to the database folder. /// @param getOSInfo Function to retrieve OS information in JSON format. /// @param getNetworksInfo Function to retrieve network information in JSON format. AgentInfo(std::string dbFolderPath = config::DEFAULT_DATA_PATH, diff --git a/src/agent/agent_info/src/agent_info_persistance.hpp b/src/agent/agent_info/src/agent_info_persistance.hpp index 3ca1da461e..2896f5deb6 100644 --- a/src/agent/agent_info/src/agent_info_persistance.hpp +++ b/src/agent/agent_info/src/agent_info_persistance.hpp @@ -6,12 +6,12 @@ class Persistence; -/// @brief Manages persistence of agent information and groups in a SQLite database. +/// @brief Manages persistence of agent information and groups in a database. class AgentInfoPersistance { public: /// @brief Constructs the persistence manager for agent info, initializing the database and tables if necessary. - /// @param dbFolderPath Path to the SQLite database folder. + /// @param dbFolderPath Path to the database folder. explicit AgentInfoPersistance(const std::string& dbFolderPath); /// @brief Destructor for AgentInfoPersistance. diff --git a/src/agent/command_store/include/command_store.hpp b/src/agent/command_store/include/command_store.hpp index 57481d77f9..48d8dde7f6 100644 --- a/src/agent/command_store/include/command_store.hpp +++ b/src/agent/command_store/include/command_store.hpp @@ -13,7 +13,7 @@ namespace command_store /// @brief CommandStore class /// /// This class provides methods for storing, retrieving, and deleting commands - /// in the command store database. It uses a SQLite database to store the + /// in the command store database. It uses a database to store the /// commands. class CommandStore { diff --git a/src/agent/multitype_queue/CMakeLists.txt b/src/agent/multitype_queue/CMakeLists.txt index 3e20b2ace6..2e9dd6d53b 100644 --- a/src/agent/multitype_queue/CMakeLists.txt +++ b/src/agent/multitype_queue/CMakeLists.txt @@ -13,7 +13,7 @@ find_package(nlohmann_json REQUIRED) find_package(fmt REQUIRED) find_package(Boost REQUIRED COMPONENTS asio) -add_library(MultiTypeQueue src/sqlitestorage.cpp src/multitype_queue.cpp) +add_library(MultiTypeQueue src/storage.cpp src/multitype_queue.cpp) target_include_directories(MultiTypeQueue PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/src/agent/multitype_queue/include/multitype_queue.hpp b/src/agent/multitype_queue/include/multitype_queue.hpp index fb1683bcdc..f76ca23bdc 100644 --- a/src/agent/multitype_queue/include/multitype_queue.hpp +++ b/src/agent/multitype_queue/include/multitype_queue.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -41,7 +41,7 @@ class MultiTypeQueue : public IMultiTypeQueue const std::chrono::milliseconds m_timeout; /// @brief class for persistence implementation - std::unique_ptr m_persistenceDest; + std::unique_ptr m_persistenceDest; /// @brief mutex for protecting the queue access std::mutex m_mtx; @@ -85,7 +85,7 @@ class MultiTypeQueue : public IMultiTypeQueue try { - m_persistenceDest = std::make_unique(dbFilePath, m_vMessageTypeStrings); + m_persistenceDest = std::make_unique(dbFilePath, m_vMessageTypeStrings); } catch (const std::exception& e) { diff --git a/src/agent/multitype_queue/include/sqlitestorage.hpp b/src/agent/multitype_queue/include/storage.hpp similarity index 88% rename from src/agent/multitype_queue/include/sqlitestorage.hpp rename to src/agent/multitype_queue/include/storage.hpp index 11abcfeae5..2b27af5958 100644 --- a/src/agent/multitype_queue/include/sqlitestorage.hpp +++ b/src/agent/multitype_queue/include/storage.hpp @@ -11,40 +11,40 @@ #include /** - * @brief SQLite implementation of the Persistence interface. + * @brief Implementation of the Persistence interface. * * This class provides methods to store, retrieve, and remove JSON messages - * in a SQLite database. + * in a database. */ -class SQLiteStorage +class Storage { public: - SQLiteStorage(const std::string& dbName, const std::vector& tableName); + Storage(const std::string& dbName, const std::vector& tableName); /** * @brief Delete copy constructor */ - SQLiteStorage(const SQLiteStorage&) = delete; + Storage(const Storage&) = delete; /** * @brief Delete copy assignment operator */ - SQLiteStorage& operator=(const SQLiteStorage&) = delete; + Storage& operator=(const Storage&) = delete; /** * @brief Delete move constructor */ - SQLiteStorage(SQLiteStorage&&) = delete; + Storage(Storage&&) = delete; /** * @brief Delete move assignment operator */ - SQLiteStorage& operator=(SQLiteStorage&&) = delete; + Storage& operator=(Storage&&) = delete; /** * @brief Destructor. */ - ~SQLiteStorage() = default; + ~Storage() = default; /** * @brief Store a JSON message in the storage. @@ -118,7 +118,7 @@ class SQLiteStorage private: /** - * @brief Initialize the table in the SQLite database. + * @brief Initialize the table in the database. * This method creates the table if it does not already exist. * @param tableName The name of the table to initialize. */ @@ -142,7 +142,7 @@ class SQLiteStorage nlohmann::json ProcessRequest(SQLite::Statement& sqlStatementQuery, size_t maxSize = 0); /** - * @brief The name of the SQLite database file. + * @brief The name of the database file. */ const std::string m_dbName; @@ -152,7 +152,7 @@ class SQLiteStorage const std::string m_tableName; /** - * @brief Pointer to the SQLite database connection. + * @brief Pointer to the database connection. */ std::unique_ptr m_db; diff --git a/src/agent/multitype_queue/src/sqlitestorage.cpp b/src/agent/multitype_queue/src/storage.cpp similarity index 84% rename from src/agent/multitype_queue/src/sqlitestorage.cpp rename to src/agent/multitype_queue/src/storage.cpp index f3342c6be8..4d8d323705 100644 --- a/src/agent/multitype_queue/src/sqlitestorage.cpp +++ b/src/agent/multitype_queue/src/storage.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -9,7 +9,7 @@ #include #include -SQLiteStorage::SQLiteStorage(const std::string& dbName, const std::vector& tableNames) +Storage::Storage(const std::string& dbName, const std::vector& tableNames) : m_dbName(dbName) , m_db(make_unique(dbName, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE)) { @@ -29,7 +29,7 @@ SQLiteStorage::SQLiteStorage(const std::string& dbName, const std::vector lock(m_mutex); m_cv.wait(lock, [this] { return !m_dbInUse; }); m_dbInUse = true; } -void SQLiteStorage::ReleaseDatabaseAccess() +void Storage::ReleaseDatabaseAccess() { std::lock_guard lock(m_mutex); m_dbInUse = false; m_cv.notify_one(); } -int SQLiteStorage::Store(const nlohmann::json& message, - const std::string& tableName, - const std::string& moduleName, - const std::string& moduleType, - const std::string& metadata) +int Storage::Store(const nlohmann::json& message, + const std::string& tableName, + const std::string& moduleName, + const std::string& moduleType, + const std::string& metadata) { std::string insertQuery; @@ -117,10 +117,10 @@ int SQLiteStorage::Store(const nlohmann::json& message, return result; } -nlohmann::json SQLiteStorage::RetrieveMultiple(int n, - const std::string& tableName, - const std::string& moduleName, - [[maybe_unused]] const std::string& moduleType) +nlohmann::json Storage::RetrieveMultiple(int n, + const std::string& tableName, + const std::string& moduleName, + [[maybe_unused]] const std::string& moduleType) { std::string selectQuery; if (moduleName.empty()) @@ -142,7 +142,7 @@ nlohmann::json SQLiteStorage::RetrieveMultiple(int n, return ProcessRequest(query); } -int SQLiteStorage::RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName) +int Storage::RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName) { std::string deleteQuery; int rowsModified = 0; @@ -178,7 +178,7 @@ int SQLiteStorage::RemoveMultiple(int n, const std::string& tableName, const std } } -int SQLiteStorage::GetElementCount(const std::string& tableName, const std::string& moduleName) +int Storage::GetElementCount(const std::string& tableName, const std::string& moduleName) { std::string countQuery; if (moduleName.empty()) @@ -202,7 +202,7 @@ int SQLiteStorage::GetElementCount(const std::string& tableName, const std::stri } else { - LogError("Error SQLiteStorage get element count."); + LogError("Error Storage get element count."); } return count; } @@ -213,7 +213,7 @@ int SQLiteStorage::GetElementCount(const std::string& tableName, const std::stri } } -size_t SQLiteStorage::GetElementsStoredSize(const std::string& tableName) +size_t Storage::GetElementsStoredSize(const std::string& tableName) { std::string sizeQuery = fmt::format( R"(SELECT SUM(LENGTH(module_name) + LENGTH(module_type) + LENGTH(metadata) + LENGTH(message)) AS total_bytes FROM {};)", @@ -229,7 +229,7 @@ size_t SQLiteStorage::GetElementsStoredSize(const std::string& tableName) } else { - LogError("Error SQLiteStorage get element count."); + LogError("Error Storage get element count."); } return count; } @@ -240,7 +240,7 @@ size_t SQLiteStorage::GetElementsStoredSize(const std::string& tableName) } } -nlohmann::json SQLiteStorage::ProcessRequest(SQLite::Statement& sqlStatementQuery, size_t maxSize) +nlohmann::json Storage::ProcessRequest(SQLite::Statement& sqlStatementQuery, size_t maxSize) { try { @@ -303,10 +303,10 @@ nlohmann::json SQLiteStorage::ProcessRequest(SQLite::Statement& sqlStatementQuer } } -nlohmann::json SQLiteStorage::RetrieveBySize(size_t n, - const std::string& tableName, - const std::string& moduleName, - [[maybe_unused]] const std::string& moduleType) +nlohmann::json Storage::RetrieveBySize(size_t n, + const std::string& tableName, + const std::string& moduleName, + [[maybe_unused]] const std::string& moduleType) { std::string selectQuery; if (moduleName.empty()) diff --git a/src/agent/multitype_queue/tests/CMakeLists.txt b/src/agent/multitype_queue/tests/CMakeLists.txt index 8abc76a1fd..fb8626a7c2 100644 --- a/src/agent/multitype_queue/tests/CMakeLists.txt +++ b/src/agent/multitype_queue/tests/CMakeLists.txt @@ -11,14 +11,14 @@ target_link_libraries(test_MultiTypeQueue PUBLIC GTest::gmock_main) add_test(NAME MultiTypeQueueTest COMMAND test_MultiTypeQueue) -add_executable(test_sqlitestorage sqlitestorage_test.cpp) -configure_target(test_sqlitestorage) -target_include_directories(test_sqlitestorage PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) -target_link_libraries(test_sqlitestorage +add_executable(test_storage storage_test.cpp) +configure_target(test_storage) +target_include_directories(test_storage PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) +target_link_libraries(test_storage MultiTypeQueue SQLiteCpp GTest::gtest GTest::gtest_main GTest::gmock GTest::gmock_main) -add_test(NAME SqliteStorageTest COMMAND test_sqlitestorage) +add_test(NAME StorageTest COMMAND test_storage) diff --git a/src/agent/multitype_queue/tests/sqlitestorage_test.cpp b/src/agent/multitype_queue/tests/storage_test.cpp similarity index 86% rename from src/agent/multitype_queue/tests/sqlitestorage_test.cpp rename to src/agent/multitype_queue/tests/storage_test.cpp index d42e256b24..1d9bff7de6 100644 --- a/src/agent/multitype_queue/tests/sqlitestorage_test.cpp +++ b/src/agent/multitype_queue/tests/storage_test.cpp @@ -8,16 +8,16 @@ #include "gtest/gtest.h" #include -#include "sqlitestorage.hpp" +#include "storage.hpp" -class SQLiteStorageTest : public ::testing::Test +class StorageTest : public ::testing::Test { protected: const std::string dbName = "testdb.db"; const std::string tableName = "test_table"; const std::string moduleName = "moduleX"; const std::vector m_vMessageTypeStrings {"test_table", "test_table2"}; - std::unique_ptr storage; + std::unique_ptr storage; void SetUp() override { @@ -32,7 +32,7 @@ class SQLiteStorageTest : public ::testing::Test } } - storage = std::make_unique(dbName, m_vMessageTypeStrings); + storage = std::make_unique(dbName, m_vMessageTypeStrings); } void TearDown() override @@ -50,7 +50,7 @@ class SQLiteStorageTest : public ::testing::Test } }; -TEST_F(SQLiteStorageTest, StoreSingleMessage) +TEST_F(StorageTest, StoreSingleMessage) { const nlohmann::json message = {{"key", "value"}}; EXPECT_EQ(storage->Store(message, tableName), 1); @@ -59,7 +59,7 @@ TEST_F(SQLiteStorageTest, StoreSingleMessage) EXPECT_EQ(storage->GetElementCount(tableName), 2); } -TEST_F(SQLiteStorageTest, StoreSingleMessageWithModule) +TEST_F(StorageTest, StoreSingleMessageWithModule) { const nlohmann::json message = {{"key", "value"}}; EXPECT_EQ(storage->Store(message, tableName, moduleName), 1); @@ -70,7 +70,7 @@ TEST_F(SQLiteStorageTest, StoreSingleMessageWithModule) EXPECT_EQ(storage->GetElementCount(tableName, moduleName), 1); } -TEST_F(SQLiteStorageTest, StoreMultipleMessages) +TEST_F(StorageTest, StoreMultipleMessages) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -79,7 +79,7 @@ TEST_F(SQLiteStorageTest, StoreMultipleMessages) EXPECT_EQ(storage->GetElementCount(tableName), 2); } -TEST_F(SQLiteStorageTest, StoreMultipleMessagesWithModule) +TEST_F(StorageTest, StoreMultipleMessagesWithModule) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -90,7 +90,7 @@ TEST_F(SQLiteStorageTest, StoreMultipleMessagesWithModule) EXPECT_EQ(storage->GetElementCount(tableName, "unavailableModuleName"), 0); } -TEST_F(SQLiteStorageTest, RetrieveMultipleMessages) +TEST_F(StorageTest, RetrieveMultipleMessages) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -101,7 +101,7 @@ TEST_F(SQLiteStorageTest, RetrieveMultipleMessages) EXPECT_EQ(retrievedMessages.size(), 2); } -TEST_F(SQLiteStorageTest, RetrieveMultipleMessagesWithModule) +TEST_F(StorageTest, RetrieveMultipleMessagesWithModule) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -120,7 +120,7 @@ TEST_F(SQLiteStorageTest, RetrieveMultipleMessagesWithModule) } } -TEST_F(SQLiteStorageTest, RemoveMultipleMessages) +TEST_F(StorageTest, RemoveMultipleMessages) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -130,7 +130,7 @@ TEST_F(SQLiteStorageTest, RemoveMultipleMessages) EXPECT_EQ(storage->GetElementCount(tableName), 0); } -TEST_F(SQLiteStorageTest, RemoveMultipleMessagesWithModule) +TEST_F(StorageTest, RemoveMultipleMessagesWithModule) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -142,14 +142,14 @@ TEST_F(SQLiteStorageTest, RemoveMultipleMessagesWithModule) EXPECT_EQ(storage->GetElementCount(tableName), 0); } -TEST_F(SQLiteStorageTest, GetElementCount) +TEST_F(StorageTest, GetElementCount) { nlohmann::json message = {{"key", "value"}}; EXPECT_EQ(storage->Store(message, tableName), 1); EXPECT_EQ(storage->GetElementCount(tableName), 1); } -TEST_F(SQLiteStorageTest, GetElementCountWithModule) +TEST_F(StorageTest, GetElementCountWithModule) { nlohmann::json message = {{"key", "value"}}; EXPECT_EQ(storage->Store(message, tableName, moduleName), 1); @@ -158,7 +158,7 @@ TEST_F(SQLiteStorageTest, GetElementCountWithModule) EXPECT_EQ(storage->GetElementCount(tableName, "unavailableModuleName"), 0); } -TEST_F(SQLiteStorageTest, MessagesSizes) +TEST_F(StorageTest, MessagesSizes) { auto messages = nlohmann::json::array(); messages.push_back({{"key", "value1"}}); @@ -176,7 +176,7 @@ TEST_F(SQLiteStorageTest, MessagesSizes) EXPECT_EQ(storedSizes, 64); } -TEST_F(SQLiteStorageTest, GetMessagesBySize) +TEST_F(StorageTest, GetMessagesBySize) { auto messages = nlohmann::json::array(); auto message1 = R"({{"key","value1"}})"; @@ -197,7 +197,7 @@ TEST_F(SQLiteStorageTest, GetMessagesBySize) EXPECT_EQ(retrievedMessages.size(), 1); } -TEST_F(SQLiteStorageTest, GetMessagesBySizeLower) +TEST_F(StorageTest, GetMessagesBySizeLower) { auto messages = nlohmann::json::array(); auto message1 = R"({{"key","value1"}})"; @@ -214,7 +214,7 @@ TEST_F(SQLiteStorageTest, GetMessagesBySizeLower) EXPECT_EQ(retrievedMessages.size(), 1); } -TEST_F(SQLiteStorageTest, GetMessagesByMoreSize) +TEST_F(StorageTest, GetMessagesByMoreSize) { auto messages = nlohmann::json::array(); auto message1 = R"({{"key","value1"}})"; @@ -232,7 +232,7 @@ TEST_F(SQLiteStorageTest, GetMessagesByMoreSize) EXPECT_EQ(retrievedMessages.size(), 2); } -class SQLiteStorageMultithreadedTest : public ::testing::Test +class StorageMultithreadedTest : public ::testing::Test { protected: const std::string dbName = "testdb"; @@ -240,7 +240,7 @@ class SQLiteStorageMultithreadedTest : public ::testing::Test void SetUp() override { - // Clean up: Delete the SQLiteStorage instances and remove the database file + // Clean up: Delete the Storage instances and remove the database file std::error_code ec; if (std::filesystem::exists(dbName.c_str())) { @@ -257,7 +257,7 @@ class SQLiteStorageMultithreadedTest : public ::testing::Test namespace { - void StoreMessages(SQLiteStorage& storage, const nlohmann::json& messages, const std::string& tableName) + void StoreMessages(Storage& storage, const nlohmann::json& messages, const std::string& tableName) { for (const auto& message : messages) { @@ -265,17 +265,17 @@ namespace } } - void RemoveMessages(SQLiteStorage& storage, size_t count, const std::string& tableName) + void RemoveMessages(Storage& storage, size_t count, const std::string& tableName) { storage.RemoveMultiple(static_cast(count), tableName); } } // namespace -TEST_F(SQLiteStorageMultithreadedTest, MultithreadedStoreAndRetrieve) +TEST_F(StorageMultithreadedTest, MultithreadedStoreAndRetrieve) { constexpr size_t messagesToStore = 100; - SQLiteStorage storage1(dbName, m_vMessageTypeStrings); + Storage storage1(dbName, m_vMessageTypeStrings); auto messages1 = nlohmann::json::array(); auto messages2 = nlohmann::json::array(); diff --git a/src/agent/persistence/include/column.hpp b/src/agent/persistence/include/column.hpp index 9c546384f0..b795cf3138 100644 --- a/src/agent/persistence/include/column.hpp +++ b/src/agent/persistence/include/column.hpp @@ -17,7 +17,7 @@ enum class OrderType DESC }; -/// @brief Supported column data types for SQLite tables. +/// @brief Supported column data types for tables. enum class ColumnType { INTEGER, From 2e46eee705344ad6355d5c30e16d61922e906680 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Fri, 10 Jan 2025 20:54:22 +0000 Subject: [PATCH 11/18] feat: integrate db_manager in multitype_queue --- src/agent/multitype_queue/CMakeLists.txt | 6 +- .../include/multitype_queue.hpp | 21 +- src/agent/multitype_queue/src/storage.cpp | 444 +++++++++--------- .../{include => src}/storage.hpp | 115 ++--- .../multitype_queue/tests/CMakeLists.txt | 1 - src/agent/persistence/CMakeLists.txt | 2 +- src/agent/persistence/include/persistence.hpp | 9 +- src/agent/persistence/src/sqlite_manager.cpp | 27 +- src/agent/persistence/src/sqlite_manager.hpp | 23 +- 9 files changed, 342 insertions(+), 306 deletions(-) rename src/agent/multitype_queue/{include => src}/storage.hpp (69%) diff --git a/src/agent/multitype_queue/CMakeLists.txt b/src/agent/multitype_queue/CMakeLists.txt index 2e9dd6d53b..04aa53298a 100644 --- a/src/agent/multitype_queue/CMakeLists.txt +++ b/src/agent/multitype_queue/CMakeLists.txt @@ -8,7 +8,6 @@ project(MultiTypeQueue) include(../../cmake/CommonSettings.cmake) set_common_settings() -find_package(SQLiteCpp REQUIRED) find_package(nlohmann_json REQUIRED) find_package(fmt REQUIRED) find_package(Boost REQUIRED COMPONENTS asio) @@ -16,17 +15,16 @@ find_package(Boost REQUIRED COMPONENTS asio) add_library(MultiTypeQueue src/storage.cpp src/multitype_queue.cpp) target_include_directories(MultiTypeQueue PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include) + ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) target_link_libraries(MultiTypeQueue PUBLIC - Persistence Config nlohmann_json::nlohmann_json Boost::asio Logger PRIVATE - SQLiteCpp + Persistence fmt::fmt) include(../../cmake/ConfigureTarget.cmake) diff --git a/src/agent/multitype_queue/include/multitype_queue.hpp b/src/agent/multitype_queue/include/multitype_queue.hpp index f76ca23bdc..596c5891da 100644 --- a/src/agent/multitype_queue/include/multitype_queue.hpp +++ b/src/agent/multitype_queue/include/multitype_queue.hpp @@ -16,7 +16,16 @@ #include #include -constexpr auto QUEUE_DB_NAME = "queue.db"; +namespace +{ + // database + const std::string QUEUE_DB_NAME = "queue.db"; + + // table names + const std::string STATELESS_TABLE_NAME = "STATELESS"; + const std::string STATEFUL_TABLE_NAME = "STATEFUL"; + const std::string COMMAND_TABLE_NAME = "COMMAND"; +} // namespace /** * @brief MultiTypeQueue implementation that handles multiple types of messages. @@ -27,11 +36,12 @@ constexpr auto QUEUE_DB_NAME = "queue.db"; class MultiTypeQueue : public IMultiTypeQueue { private: - const std::vector m_vMessageTypeStrings {"STATELESS", "STATEFUL", "COMMAND"}; + const std::vector m_vMessageTypeStrings { + STATELESS_TABLE_NAME, STATEFUL_TABLE_NAME, COMMAND_TABLE_NAME}; const std::map m_mapMessageTypeName { - {MessageType::STATELESS, "STATELESS"}, - {MessageType::STATEFUL, "STATEFUL"}, - {MessageType::COMMAND, "COMMAND"}, + {MessageType::STATELESS, STATELESS_TABLE_NAME}, + {MessageType::STATEFUL, STATEFUL_TABLE_NAME}, + {MessageType::COMMAND, COMMAND_TABLE_NAME}, }; /// @brief maximun quantity of message to stored on the queue @@ -81,6 +91,7 @@ class MultiTypeQueue : public IMultiTypeQueue config::agent::QUEUE_DEFAULT_SIZE); m_maxItems = config::agent::QUEUE_DEFAULT_SIZE; } + const auto dbFilePath = dbFolderPath + "/" + QUEUE_DB_NAME; try diff --git a/src/agent/multitype_queue/src/storage.cpp b/src/agent/multitype_queue/src/storage.cpp index 4d8d323705..bd8eb2d6b1 100644 --- a/src/agent/multitype_queue/src/storage.cpp +++ b/src/agent/multitype_queue/src/storage.cpp @@ -2,327 +2,339 @@ #include -#include +#include +#include +#include -#include -#include -#include -#include +namespace +{ + // column names + const std::string ROW_ID_COLUMN_NAME = "rowid"; + const std::string MODULE_NAME_COLUMN_NAME = "module_name"; + const std::string MODULE_TYPE_COLUMN_NAME = "module_type"; + const std::string METADATA_COLUMN_NAME = "metadata"; + const std::string MESSAGE_COLUMN_NAME = "message"; + + nlohmann::json ProcessRequest(const std::vector& rows, size_t maxSize = 0) + { + nlohmann::json messages = nlohmann::json::array(); + size_t sizeAccum = 0; + + for (const auto& row : rows) + { + std::string moduleNameString = row[0].Value; + std::string moduleTypeString = row[1].Value; + std::string metadataString = row[2].Value; + std::string dataString = row[3].Value; + + nlohmann::json outputJson = {{"moduleName", ""}, {"moduleType", ""}, {"metadata", ""}, {"data", {}}}; + + if (!dataString.empty()) + { + outputJson["data"] = nlohmann::json::parse(dataString); + } + + if (!metadataString.empty()) + { + outputJson["metadata"] = metadataString; + } + + if (!moduleNameString.empty()) + { + outputJson["moduleName"] = moduleNameString; + } + + if (!moduleTypeString.empty()) + { + outputJson["moduleType"] = moduleTypeString; + } + + messages.push_back(outputJson); + if (maxSize) + { + size_t messageSize = moduleNameString.size() + moduleTypeString.size() + metadataString.size() + + outputJson["data"].dump().size(); + if (sizeAccum + messageSize >= maxSize) + { + break; + } + sizeAccum += messageSize; + } + } + + return messages; + } +} // namespace -Storage::Storage(const std::string& dbName, const std::vector& tableNames) - : m_dbName(dbName) - , m_db(make_unique(dbName, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE)) +Storage::Storage(const std::string& dbFilePath, const std::vector& tableNames) { try { - // Open the database in WAL mode - m_db->exec("PRAGMA journal_mode=WAL;"); + m_db = PersistenceFactory::CreatePersistence(PersistenceFactory::PersistenceType::SQLITE3, dbFilePath); + for (const auto& table : tableNames) { - InitializeTable(table); + if (!m_db->TableExists(table)) + { + CreateTable(table); + } } } - catch (const std::exception& e) + catch (const std::exception&) { - LogError("Error initializing database: {}.", e.what()); - throw; + throw std::runtime_error(std::string("Cannot open database: " + dbFilePath)); } } -void Storage::InitializeTable(const std::string& tableName) +Storage::~Storage() = default; + +void Storage::CreateTable(const std::string& tableName) { - // TODO: all queries should be in the same place. - constexpr std::string_view CREATE_TABLE_QUERY { - "CREATE TABLE IF NOT EXISTS {} (module_name TEXT, module_type TEXT, metadata TEXT, message TEXT NOT NULL);"}; - auto createTableQuery = fmt::format(CREATE_TABLE_QUERY, tableName); - std::lock_guard lock(m_mutex); try { - m_db->exec(createTableQuery); + Keys columns; + columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, false, false); + columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, false, false); + columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT, false, false); + columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT, true, false); + + m_db->CreateTable(tableName, columns); } catch (const std::exception& e) { - LogError("Error initializing table: {}.", e.what()); - throw; + LogError("Error creating table: {}.", e.what()); } } -void Storage::WaitForDatabaseAccess() -{ - std::unique_lock lock(m_mutex); - m_cv.wait(lock, [this] { return !m_dbInUse; }); - m_dbInUse = true; -} - -void Storage::ReleaseDatabaseAccess() -{ - std::lock_guard lock(m_mutex); - m_dbInUse = false; - m_cv.notify_one(); -} - int Storage::Store(const nlohmann::json& message, const std::string& tableName, const std::string& moduleName, const std::string& moduleType, const std::string& metadata) { - std::string insertQuery; - - constexpr std::string_view INSERT_QUERY { - R"(INSERT INTO {} (module_name, module_type, metadata, message) VALUES ("{}", "{}", '{}', ?);)"}; - insertQuery = fmt::format(INSERT_QUERY, tableName, moduleName, moduleType, metadata); + Row fields; + fields.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + fields.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); + fields.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT, metadata); int result = 0; - WaitForDatabaseAccess(); - SQLite::Statement query = SQLite::Statement(*m_db, insertQuery); + std::unique_lock lock(m_mutex); + + auto transaction = m_db->BeginTransaction(); if (message.is_array()) { - SQLite::Transaction transaction(*m_db); for (const auto& singleMessageData : message) { + fields.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT, singleMessageData.dump()); + try { - query.bind(1, singleMessageData.dump()); - result += query.exec(); + m_db->Insert(tableName, fields); + result++; } catch (const std::exception& e) { LogError("Error during Store operation: {}.", e.what()); - break; } - // Reset the query to reuse it for the next message - query.reset(); + fields.pop_back(); } - transaction.commit(); } else { + fields.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT, message.dump()); + try { - SQLite::Transaction transaction(*m_db); - query.bind(1, message.dump()); - result = query.exec(); - transaction.commit(); + m_db->Insert(tableName, fields); + result++; } catch (const std::exception& e) { LogError("Error during Store operation: {}.", e.what()); } } - ReleaseDatabaseAccess(); + + m_db->CommitTransaction(transaction); return result; } -nlohmann::json Storage::RetrieveMultiple(int n, - const std::string& tableName, - const std::string& moduleName, - [[maybe_unused]] const std::string& moduleType) +int Storage::RemoveMultiple(int n, + const std::string& tableName, + const std::string& moduleName, + const std::string& moduleType) { - std::string selectQuery; - if (moduleName.empty()) - { - constexpr std::string_view SELECT_MULTIPLE_QUERY { - "SELECT module_name, module_type, metadata, message FROM {} ORDER BY rowid ASC LIMIT ?;"}; - selectQuery = fmt::format(SELECT_MULTIPLE_QUERY, tableName); - } - else - { - constexpr std::string_view SELECT_MULTIPLE_QUERY { - "SELECT module_name, module_type, metadata, message FROM {} WHERE " - "module_name LIKE \"{}\" ORDER BY rowid ASC LIMIT ?;"}; - selectQuery = fmt::format(SELECT_MULTIPLE_QUERY, tableName, moduleName); - } + Criteria filters; + if (!moduleName.empty()) + filters.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + if (!moduleType.empty()) + filters.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); - SQLite::Statement query(*m_db, selectQuery); - query.bind(1, n); - return ProcessRequest(query); -} + int result = 0; -int Storage::RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName) -{ - std::string deleteQuery; - int rowsModified = 0; - if (moduleName.empty()) - { - constexpr std::string_view DELETE_MULTIPLE_QUERY { - "DELETE FROM {} WHERE rowid IN (SELECT rowid FROM {} ORDER BY rowid ASC LIMIT ?);"}; - deleteQuery = fmt::format(DELETE_MULTIPLE_QUERY, tableName, tableName); - } - else - { - constexpr std::string_view DELETE_MULTIPLE_QUERY {"DELETE FROM {} WHERE module_name LIKE \"{}\" AND rowid IN " - "(SELECT rowid FROM {} WHERE module_name LIKE \"{}\" ORDER " - "BY rowid ASC LIMIT ?);"}; - deleteQuery = fmt::format(DELETE_MULTIPLE_QUERY, tableName, moduleName, tableName, moduleName); - } + std::unique_lock lock(m_mutex); + + auto transaction = m_db->BeginTransaction(); try { - WaitForDatabaseAccess(); - SQLite::Statement query(*m_db, deleteQuery); - SQLite::Transaction transaction(*m_db); - query.bind(1, n); - rowsModified = query.exec(); - transaction.commit(); - ReleaseDatabaseAccess(); - return rowsModified; + Names columns; + columns.emplace_back(ROW_ID_COLUMN_NAME, ColumnType::INTEGER); + + // Select first n messages + const auto results = + m_db->Select(tableName, columns, filters, LogicalOperator::AND, columns, OrderType::ASC, n); + + if (!results.empty()) + { + filters.clear(); + + for (const auto& row : results) + { + filters.emplace_back(ROW_ID_COLUMN_NAME, ColumnType::INTEGER, row[0].Value); + + try + { + // Remove selected message + m_db->Remove(tableName, filters, LogicalOperator::AND); + result++; + } + catch (const std::exception& e) + { + LogError("Error during Remove operation: {}.", e.what()); + } + filters.pop_back(); + } + } } catch (const std::exception& e) { LogError("Error during RemoveMultiple operation: {}.", e.what()); - return rowsModified; } + + m_db->CommitTransaction(transaction); + + return result; } -int Storage::GetElementCount(const std::string& tableName, const std::string& moduleName) +nlohmann::json Storage::RetrieveMultiple(int n, + const std::string& tableName, + const std::string& moduleName, + const std::string& moduleType) { - std::string countQuery; - if (moduleName.empty()) - { - constexpr std::string_view COUNT_QUERY {"SELECT COUNT(*) FROM {}"}; - countQuery = fmt::format(COUNT_QUERY, tableName); - } - else - { - constexpr std::string_view COUNT_QUERY {"SELECT COUNT(*) FROM {} WHERE module_name LIKE \"{}\""}; - countQuery = fmt::format(COUNT_QUERY, tableName, moduleName); - } + Names columns; + columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT); + + Criteria filters; + if (!moduleName.empty()) + filters.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + if (!moduleType.empty()) + filters.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); + + Names orderColumns; + orderColumns.emplace_back(ROW_ID_COLUMN_NAME, ColumnType::INTEGER); try { - SQLite::Statement query(*m_db, countQuery); - int count = 0; - if (query.executeStep()) - { - count = query.getColumn(0).getInt(); - } - else - { - LogError("Error Storage get element count."); - } - return count; + const auto results = + m_db->Select(tableName, columns, filters, LogicalOperator::AND, orderColumns, OrderType::ASC, n); + + return ProcessRequest(results); } catch (const std::exception& e) { - LogError("Error during GetElementCount operation: {}.", e.what()); - return 0; + LogError("Error during RetrieveMultiple operation: {}.", e.what()); + return {}; } } -size_t Storage::GetElementsStoredSize(const std::string& tableName) +nlohmann::json Storage::RetrieveBySize(size_t n, + const std::string& tableName, + const std::string& moduleName, + const std::string& moduleType) { - std::string sizeQuery = fmt::format( - R"(SELECT SUM(LENGTH(module_name) + LENGTH(module_type) + LENGTH(metadata) + LENGTH(message)) AS total_bytes FROM {};)", - tableName); + Names columns; + columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT); + + Criteria filters; + if (!moduleName.empty()) + filters.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + if (!moduleType.empty()) + filters.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); + + Names orderColumns; + orderColumns.emplace_back(ROW_ID_COLUMN_NAME, ColumnType::INTEGER); try { - SQLite::Statement query(*m_db, sizeQuery); - size_t count = 0; - if (query.executeStep()) - { - count = query.getColumn(0).getUInt(); - } - else - { - LogError("Error Storage get element count."); - } - return count; + const auto results = + m_db->Select(tableName, columns, filters, LogicalOperator::AND, orderColumns, OrderType::ASC); + + return ProcessRequest(results, n); } catch (const std::exception& e) { - LogError("Error during GetElementCount operation: {}.", e.what()); - return 0; + LogError("Error during RetrieveBySize operation: {}.", e.what()); + return {}; } } -nlohmann::json Storage::ProcessRequest(SQLite::Statement& sqlStatementQuery, size_t maxSize) +int Storage::GetElementCount(const std::string& tableName, const std::string& moduleName, const std::string& moduleType) { - try - { - nlohmann::json messages = nlohmann::json::array(); - size_t sizeAccum = 0; - while (sqlStatementQuery.executeStep()) - { - if (sqlStatementQuery.getColumnCount() == 4 && sqlStatementQuery.getColumn(3).getType() == SQLite::TEXT && - sqlStatementQuery.getColumn(2).getType() == SQLite::TEXT && - sqlStatementQuery.getColumn(1).getType() == SQLite::TEXT && - sqlStatementQuery.getColumn(0).getType() == SQLite::TEXT) - { - std::string moduleNameString = sqlStatementQuery.getColumn(0).getString(); - std::string moduleTypeString = sqlStatementQuery.getColumn(1).getString(); - std::string metadataString = sqlStatementQuery.getColumn(2).getString(); - std::string dataString = sqlStatementQuery.getColumn(3).getString(); - - nlohmann::json outputJson = {{"moduleName", ""}, {"moduleType", ""}, {"metadata", ""}, {"data", {}}}; + Criteria filters; + if (!moduleName.empty()) + filters.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + if (!moduleType.empty()) + filters.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); - if (!dataString.empty()) - { - outputJson["data"] = nlohmann::json::parse(dataString); - } - - if (!metadataString.empty()) - { - outputJson["metadata"] = metadataString; - } + int count = 0; - if (!moduleNameString.empty()) - { - outputJson["moduleName"] = moduleNameString; - } - - if (!moduleTypeString.empty()) - { - outputJson["moduleType"] = moduleTypeString; - } - - messages.push_back(outputJson); - if (maxSize) - { - size_t messageSize = moduleNameString.size() + moduleTypeString.size() + metadataString.size() + - outputJson["data"].dump().size(); - if (sizeAccum + messageSize >= maxSize) - { - break; - } - sizeAccum += messageSize; - } - } - } - - return messages; + try + { + count = m_db->GetCount(tableName, filters, LogicalOperator::AND); } catch (const std::exception& e) { - LogError("Error during RetrieveMultiple operation: {}.", e.what()); - return {}; + LogError("Error during GetElementCount operation: {}.", e.what()); } + + return count; } -nlohmann::json Storage::RetrieveBySize(size_t n, - const std::string& tableName, - const std::string& moduleName, - [[maybe_unused]] const std::string& moduleType) +size_t Storage::GetElementsStoredSize(const std::string& tableName, + const std::string& moduleName, + const std::string& moduleType) { - std::string selectQuery; - if (moduleName.empty()) + Criteria filters; + if (!moduleName.empty()) + filters.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, moduleName); + if (!moduleType.empty()) + filters.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, moduleType); + + size_t count = 0; + + try { - constexpr std::string_view SELECT_MULTIPLE_QUERY { - "SELECT module_name, module_type, metadata, message FROM {} ORDER BY rowid ASC;"}; - selectQuery = fmt::format(SELECT_MULTIPLE_QUERY, tableName); + Names columns; + columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT); + + count = m_db->GetSize(tableName, columns, filters, LogicalOperator::AND); } - else + catch (const std::exception& e) { - constexpr std::string_view SELECT_MULTIPLE_QUERY { - "SELECT module_name, module_type, metadata, message FROM {} WHERE " - "module_name LIKE \"{}\" ORDER BY rowid ASC;"}; - selectQuery = fmt::format(SELECT_MULTIPLE_QUERY, tableName, moduleName); + LogError("Error during GetElementsStoredSize operation: {}.", e.what()); } - SQLite::Statement query(*m_db, selectQuery); - return ProcessRequest(query, n); + return count; } diff --git a/src/agent/multitype_queue/include/storage.hpp b/src/agent/multitype_queue/src/storage.hpp similarity index 69% rename from src/agent/multitype_queue/include/storage.hpp rename to src/agent/multitype_queue/src/storage.hpp index 2b27af5958..ce38e3d3b7 100644 --- a/src/agent/multitype_queue/include/storage.hpp +++ b/src/agent/multitype_queue/src/storage.hpp @@ -1,17 +1,15 @@ #pragma once -#include -#include #include -#include #include #include #include -#include + +class Persistence; /** - * @brief Implementation of the Persistence interface. + * @brief Storage class. * * This class provides methods to store, retrieve, and remove JSON messages * in a database. @@ -19,7 +17,13 @@ class Storage { public: - Storage(const std::string& dbName, const std::vector& tableName); + /** + * @brief Constructor. + * + * @param dbFilePath The path to the database. + * @param tableNames A vector of table names. + */ + Storage(const std::string& dbFilePath, const std::vector& tableNames); /** * @brief Delete copy constructor @@ -44,7 +48,7 @@ class Storage /** * @brief Destructor. */ - ~Storage() = default; + ~Storage(); /** * @brief Store a JSON message in the storage. @@ -62,45 +66,33 @@ class Storage const std::string& moduleType = "", const std::string& metadata = ""); - /** - * @brief Retrieve multiple JSON messages. - * - * @param n The number of messages to retrieve. - * @param tableName The name of the table to retrieve the message from. - * @param moduleName The name of the module that created the message. - * @param moduleType The module type that created the message. - * @return A vector of retrieved JSON messages. - */ - nlohmann::json RetrieveMultiple(int n, - const std::string& tableName, - const std::string& moduleName = "", - const std::string& moduleType = ""); - /** * @brief Remove multiple JSON messages. * * @param n The number of messages to remove. * @param tableName The name of the table to remove the message from. * @param moduleName The name of the module that created the message. + * @param moduleType The module type that created the message. * @return The number of removed elements. */ - int RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName = ""); + int RemoveMultiple(int n, + const std::string& tableName, + const std::string& moduleName = "", + const std::string& moduleType = ""); /** - * @brief Get the number of elements in the table. + * @brief Retrieve multiple JSON messages. + * + * @param n The number of messages to retrieve. * @param tableName The name of the table to retrieve the message from. * @param moduleName The name of the module that created the message. - * @return The number of elements in the table. - */ - int GetElementCount(const std::string& tableName, const std::string& moduleName = ""); - - /** - * @brief Get the bytes occupied by elements stored in the specified queue. - * - * @param tableName The name of the table. - * @return size_t The bytes occupied by elements stored in the specified queue. + * @param moduleType The module type that created the message. + * @return A vector of retrieved JSON messages. */ - size_t GetElementsStoredSize(const std::string& tableName); + nlohmann::json RetrieveMultiple(int n, + const std::string& tableName, + const std::string& moduleName = "", + const std::string& moduleType = ""); /** * @brief Retrieve multiple JSON messages based on size from the specified queue. @@ -116,58 +108,43 @@ class Storage const std::string& moduleName = "", const std::string& moduleType = ""); -private: - /** - * @brief Initialize the table in the database. - * This method creates the table if it does not already exist. - * @param tableName The name of the table to initialize. - */ - void InitializeTable(const std::string& tableName); - /** - * @brief Private method for waiting for database access. - * + * @brief Get the number of elements in the table. + * @param tableName The name of the table to retrieve the message from. + * @param moduleName The name of the module that created the message. + * @param moduleType The module type that created the message. + * @return The number of elements in the table. */ - void WaitForDatabaseAccess(); + int GetElementCount(const std::string& tableName, + const std::string& moduleName = "", + const std::string& moduleType = ""); /** - * @brief Private method for releasing database access. + * @brief Get the bytes occupied by elements stored in the specified queue. * + * @param tableName The name of the table. + * @param moduleName The name of the module. + * @param moduleType The type of the module. + * @return size_t The bytes occupied by elements stored in the specified queue. */ - void ReleaseDatabaseAccess(); - - /** - * @brief Intermediate function for processing Retrieve queries. - */ - nlohmann::json ProcessRequest(SQLite::Statement& sqlStatementQuery, size_t maxSize = 0); - - /** - * @brief The name of the database file. - */ - const std::string m_dbName; + size_t GetElementsStoredSize(const std::string& tableName, + const std::string& moduleName = "", + const std::string& moduleType = ""); +private: /** - * @brief The name of the table to use for storing messages. + * @brief Create a table in the database. + * @param tableName The name of the table to create. */ - const std::string m_tableName; + void CreateTable(const std::string& tableName); /** * @brief Pointer to the database connection. */ - std::unique_ptr m_db; + std::unique_ptr m_db; /** * @brief Mutex to ensure thread-safe operations. */ std::mutex m_mutex; - - /** - * @brief condition variable to wait for database access. - */ - std::condition_variable m_cv; - - /** - * @brief flag for notifying the use of the db. - */ - bool m_dbInUse = false; }; diff --git a/src/agent/multitype_queue/tests/CMakeLists.txt b/src/agent/multitype_queue/tests/CMakeLists.txt index fb8626a7c2..702d99d2d2 100644 --- a/src/agent/multitype_queue/tests/CMakeLists.txt +++ b/src/agent/multitype_queue/tests/CMakeLists.txt @@ -16,7 +16,6 @@ configure_target(test_storage) target_include_directories(test_storage PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) target_link_libraries(test_storage MultiTypeQueue - SQLiteCpp GTest::gtest GTest::gtest_main GTest::gmock diff --git a/src/agent/persistence/CMakeLists.txt b/src/agent/persistence/CMakeLists.txt index c19a5949fc..7e6a532619 100644 --- a/src/agent/persistence/CMakeLists.txt +++ b/src/agent/persistence/CMakeLists.txt @@ -17,7 +17,7 @@ include(../../cmake/ConfigureTarget.cmake) configure_target(Persistence) target_include_directories(Persistence PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(Persistence PUBLIC SQLiteCpp PRIVATE fmt::fmt Logger) +target_link_libraries(Persistence PRIVATE SQLiteCpp fmt::fmt Logger) if(BUILD_TESTS) enable_testing() diff --git a/src/agent/persistence/include/persistence.hpp b/src/agent/persistence/include/persistence.hpp index 24f79e0a3d..f21fa021a8 100644 --- a/src/agent/persistence/include/persistence.hpp +++ b/src/agent/persistence/include/persistence.hpp @@ -66,7 +66,7 @@ class Persistence LogicalOperator logOp = LogicalOperator::AND, const Names& orderBy = {}, OrderType orderType = OrderType::ASC, - unsigned int limit = 0) = 0; + int limit = 0) = 0; /// @brief Retrieves the number of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -80,8 +80,13 @@ class Persistence /// @brief Retrieves the size in bytes of rows in a specified table. /// @param tableName The name of the table to count rows in. /// @param fields Names to retrieve. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The size in bytes of the rows in the table. - virtual size_t GetSize(const std::string& tableName, const Names& fields) = 0; + virtual size_t GetSize(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) = 0; /// @brief Begins a transaction in the database. /// @return The transaction ID. diff --git a/src/agent/persistence/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp index 56d6dc204d..1ae9349be9 100644 --- a/src/agent/persistence/src/sqlite_manager.cpp +++ b/src/agent/persistence/src/sqlite_manager.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -11,6 +12,8 @@ const std::map MAP_LOGOP_STRING {{LogicalOperator: {LogicalOperator::OR, "OR"}}; const std::map MAP_ORDER_STRING {{OrderType::ASC, "ASC"}, {OrderType::DESC, "DESC"}}; +SQLiteManager::~SQLiteManager() = default; + ColumnType SQLiteManager::ColumnTypeFromSQLiteType(const int type) const { if (type == SQLite::INTEGER) @@ -188,7 +191,7 @@ std::vector SQLiteManager::Select(const std::string& tableName, LogicalOperator logOp, const Names& orderBy, OrderType orderType, - unsigned int limit) + int limit) { std::string selectedFields; if (fields.empty()) @@ -309,7 +312,10 @@ int SQLiteManager::GetCount(const std::string& tableName, const Criteria& selCri return count; } -size_t SQLiteManager::GetSize(const std::string& tableName, const Names& fields) +size_t SQLiteManager::GetSize(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria, + LogicalOperator logOp) { if (fields.empty()) { @@ -327,7 +333,22 @@ size_t SQLiteManager::GetSize(const std::string& tableName, const Names& fields) } selectedFields = fmt::format("{}", fmt::join(fieldNames, " + ")); - std::string queryString = fmt::format("SELECT SUM({}) AS total_bytes FROM {}", selectedFields, tableName); + std::string condition; + if (!selCriteria.empty()) + { + std::vector conditions; + for (const auto& col : selCriteria) + { + if (col.Type == ColumnType::TEXT) + conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + else + conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); + } + condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); + } + + std::string queryString = + fmt::format("SELECT SUM({}) AS total_bytes FROM {} {}", selectedFields, tableName, condition); size_t count = 0; try diff --git a/src/agent/persistence/src/sqlite_manager.hpp b/src/agent/persistence/src/sqlite_manager.hpp index f9241ffd89..e722dc6fe9 100644 --- a/src/agent/persistence/src/sqlite_manager.hpp +++ b/src/agent/persistence/src/sqlite_manager.hpp @@ -1,16 +1,21 @@ #pragma once -#include - #include "column.hpp" #include "persistence.hpp" +#include #include #include #include #include #include +namespace SQLite +{ + class Database; + class Transaction; +} // namespace SQLite + /// @brief Manages SQLite database operations, including table creation, data insertion, updating, and selection. class SQLiteManager : public Persistence { @@ -31,6 +36,9 @@ class SQLiteManager : public Persistence /// @brief Delete move assignment operator. SQLiteManager& operator=(SQLiteManager&&) = delete; + /// @brief Destructor. + ~SQLiteManager() override; + /// @brief Checks if a specified table exists in the database. /// @param tableName The name of the table to check. /// @return True if the table exists, false otherwise. @@ -83,7 +91,7 @@ class SQLiteManager : public Persistence LogicalOperator logOp = LogicalOperator::AND, const Names& orderBy = {}, OrderType orderType = OrderType::ASC, - unsigned int limit = 0) override; + int limit = 0) override; /// @brief Retrieves the number of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -97,8 +105,13 @@ class SQLiteManager : public Persistence /// @brief Retrieves the size in bytes of rows in a specified table. /// @param tableName The name of the table to count rows in. /// @param fields Names to retrieve. + /// @param selCriteria Optional selection criteria to filter rows. + /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The size in bytes of the rows in the table. - size_t GetSize(const std::string& tableName, const Names& fields) override; + size_t GetSize(const std::string& tableName, + const Names& fields, + const Criteria& selCriteria = {}, + LogicalOperator logOp = LogicalOperator::AND) override; /// @brief Begins a transaction in the SQLite database. /// @return The transaction ID. @@ -135,5 +148,5 @@ class SQLiteManager : public Persistence std::map> m_transactions; /// @brief The next available transaction ID. - TransactionId m_nextTransactionId = 0; + std::atomic m_nextTransactionId = 0; }; From 825f2441a90b9e990560706a6fc783446839d5c7 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Fri, 10 Jan 2025 21:13:56 +0000 Subject: [PATCH 12/18] refactor: change multitype queue comments format --- .../include/imultitype_queue.hpp | 160 +++++++----------- src/agent/multitype_queue/include/message.hpp | 12 +- .../include/multitype_queue.hpp | 86 +++------- src/agent/multitype_queue/src/storage.hpp | 140 ++++++--------- 4 files changed, 138 insertions(+), 260 deletions(-) diff --git a/src/agent/multitype_queue/include/imultitype_queue.hpp b/src/agent/multitype_queue/include/imultitype_queue.hpp index 292fc9a601..f87fa5ecf8 100644 --- a/src/agent/multitype_queue/include/imultitype_queue.hpp +++ b/src/agent/multitype_queue/include/imultitype_queue.hpp @@ -7,138 +7,98 @@ #include #include -/** - * @brief Interface for a multi-type message queue. - * - * This interface defines the operations for managing messages in a queue - * that supports multiple message types. Classes that implement this interface - * must provide the functionality described by these methods. - */ +/// @brief Interface for a multi-type message queue. +/// +/// This interface defines the operations for managing messages in a queue +/// that supports multiple message types. Classes that implement this interface +/// must provide the functionality described by these methods. class IMultiTypeQueue { public: - /** - * @brief Virtual destructor. - */ + /// @brief Virtual destructor. virtual ~IMultiTypeQueue() = default; - /** - * @brief Pushes a single message onto the queue. - * - * @param message The message to be pushed. - * @param shouldWait If true, the function waits until the message is pushed. - * @return int The number of messages pushed. - */ + /// @brief Pushes a single message onto the queue. + /// @param message The message to be pushed. + /// @param shouldWait If true, the function waits until the message is pushed. + /// @return int The number of messages pushed. virtual int push(Message message, bool shouldWait = false) = 0; - /** - * @brief Pushes a single message onto the queue asynchronously. - * - * @param message The message to be pushed. - * @return boost::asio::awaitable The number of messages pushed. - */ + /// @brief Pushes a single message onto the queue asynchronously. + /// @param message The message to be pushed. + /// @return boost::asio::awaitable The number of messages pushed. virtual boost::asio::awaitable pushAwaitable(Message message) = 0; - /** - * @brief Pushes a vector of messages onto the queue. - * - * @param messages The vector of messages to be pushed. - * @return int The number of messages pushed. - */ + /// @brief Pushes a vector of messages onto the queue. + /// @param messages The vector of messages to be pushed. + /// @return int The number of messages pushed. virtual int push(std::vector messages) = 0; - /** - * @brief Retrieves the next message from the queue. - * - * @param type The type of the queue to use as the source. - * @param moduleName The name of the module requesting the message. - * @param moduleType The type of the module requesting the messages. - * @return Message The next message from the queue. - */ + /// @brief Retrieves the next message from the queue. + /// @param type The type of the queue to use as the source. + /// @param moduleName The name of the module requesting the message. + /// @param moduleType The type of the module requesting the messages. + /// @return Message The next message from the queue. virtual Message getNext(MessageType type, const std::string moduleName = "", const std::string moduleType = "") = 0; - /** - * @brief Retrieves the next Bytes of messages from the queue asynchronously. - * - * @param type The type of the queue to use as the source. - * @param messageQuantity In bytes of messages. - * @param moduleName The name of the module requesting the message. - * @param moduleType The type of the module requesting the messages. - * @return boost::asio::awaitable> Awaitable object representing the next N messages. - */ + /// @brief Retrieves the next Bytes of messages from the queue asynchronously. + /// @param type The type of the queue to use as the source. + /// @param messageQuantity In bytes of messages. + /// @param moduleName The name of the module requesting the message. + /// @param moduleType The type of the module requesting the messages. + /// @return boost::asio::awaitable> Awaitable object representing the next N messages. virtual boost::asio::awaitable> getNextBytesAwaitable(MessageType type, const size_t messageQuantity, const std::string moduleName = "", const std::string moduleType = "") = 0; - /** - * @brief Retrieves the next N messages from the queue. - * - * @param type The type of the queue to use as the source. - * @param messageQuantity The quantity of bytes of messages to return. - * @param moduleName The name of the module requesting the messages. - * @param moduleType The type of the module requesting the messages. - * @return std::vector A vector of messages fetched from the queue. - */ + /// @brief Retrieves the next N messages from the queue. + /// @param type The type of the queue to use as the source. + /// @param messageQuantity The quantity of bytes of messages to return. + /// @param moduleName The name of the module requesting the messages. + /// @param moduleType The type of the module requesting the messages. + /// @return std::vector A vector of messages fetched from the queue. virtual std::vector getNextBytes(MessageType type, const size_t messageQuantity, const std::string moduleName = "", const std::string moduleType = "") = 0; - /** - * @brief Deletes a message from the queue. - * - * @param type The type of the queue from which to pop the message. - * @param moduleName The name of the module requesting the pop. - * @return true If the message was popped successfully. - * @return false If the message could not be popped. - */ + /// @brief Deletes a message from the queue. + /// @param type The type of the queue from which to pop the message. + /// @param moduleName The name of the module requesting the pop. + /// @return true If the message was popped successfully. + /// @return false If the message could not be popped. virtual bool pop(MessageType type, const std::string moduleName = "") = 0; - /** - * @brief Deletes N messages from the queue. - * - * @param type The type of the queue from which to pop the messages. - * @param moduleName The name of the module requesting the pop. - * @param messageQuantity The quantity of messages to pop. - * @return int The number of messages deleted. - */ + /// @brief Deletes N messages from the queue. + /// @param type The type of the queue from which to pop the messages. + /// @param messageQuantity The quantity of messages to pop. + /// @param moduleName The name of the module requesting the pop. + /// @return int The number of messages deleted. virtual int popN(MessageType type, int messageQuantity, const std::string moduleName = "") = 0; - /** - * @brief Checks if a queue is empty. - * - * @param type The type of the queue. - * @param moduleName The name of the module requesting the check. - * @return true If the queue is empty. - * @return false If the queue is not empty. - */ + /// @brief Checks if a queue is empty. + /// @param type The type of the queue. + /// @param moduleName The name of the module requesting the check. + /// @return true If the queue is empty. + /// @return false If the queue is not empty. virtual bool isEmpty(MessageType type, const std::string moduleName = "") = 0; - /** - * @brief Checks if a queue is full. - * - * @param type The type of the queue. - * @param moduleName The name of the module requesting the check. - * @return true If the queue is full. - * @return false If the queue is not full. - */ + /// @brief Checks if a queue is full + /// @param type The type of the queue. + /// @param moduleName The name of the module requesting the check. + /// @return true If the queue is full. + /// @return false If the queue is not full. virtual bool isFull(MessageType type, const std::string moduleName = "") = 0; - /** - * @brief Returns the number of items stored in the queue. - * - * @param type The type of the queue. - * @param moduleName The name of the module requesting the count. - * @return int The number of items in the queue. - */ + /// @brief Returns the number of items stored in the queue. + /// @param type The type of the queue. + /// @param moduleName The name of the module requesting the count. + /// @return int The number of items in the queue. virtual int storedItems(MessageType type, const std::string moduleName = "") = 0; - /** - * @brief Returns the number of bytes stored in the queue. - * - * @param type The type of the queue. - * @return size_t The number of bytes in the queue. - */ + /// @brief Returns the size of the queue per type + /// @param type The type of the queue. + /// @return size_t The size of the queue. virtual size_t sizePerType(MessageType type) = 0; }; diff --git a/src/agent/multitype_queue/include/message.hpp b/src/agent/multitype_queue/include/message.hpp index b6253fe0ee..7508d4e10d 100644 --- a/src/agent/multitype_queue/include/message.hpp +++ b/src/agent/multitype_queue/include/message.hpp @@ -4,10 +4,7 @@ #include -/** - * @brief Types of messages enum - * - */ +/// @brief Types of messages enum enum class MessageType { STATELESS, @@ -15,11 +12,8 @@ enum class MessageType COMMAND }; -/** - * @brief Wrapper for Message, contains the message type, the json data, the - * module name, the module type and the metadata. - * - */ +/// @brief Wrapper for Message, contains the message type, the json data, the +/// module name, the module type and the metadata. class Message { public: diff --git a/src/agent/multitype_queue/include/multitype_queue.hpp b/src/agent/multitype_queue/include/multitype_queue.hpp index 596c5891da..feda44dfbc 100644 --- a/src/agent/multitype_queue/include/multitype_queue.hpp +++ b/src/agent/multitype_queue/include/multitype_queue.hpp @@ -27,12 +27,10 @@ namespace const std::string COMMAND_TABLE_NAME = "COMMAND"; } // namespace -/** - * @brief MultiTypeQueue implementation that handles multiple types of messages. - * - * This class implements the IMultiTypeQueue interface to provide a queue - * that can handle different message types such as STATELESS, STATEFUL, and COMMAND. - */ +/// @brief MultiTypeQueue implementation that handles multiple types of messages. +/// +/// This class implements the IMultiTypeQueue interface to provide a queue +/// that can handle different message types such as STATELESS, STATEFUL, and COMMAND. class MultiTypeQueue : public IMultiTypeQueue { private: @@ -63,10 +61,8 @@ class MultiTypeQueue : public IMultiTypeQueue std::time_t m_batchInterval = config::agent::DEFAULT_BATCH_INTERVAL; public: - /** - * @brief Constructor. - * @param getConfigValue Function to retrieve configuration values - */ + /// @brief Constructor. + /// @param getConfigValue Function to retrieve configuration values template MultiTypeQueue(const ConfigGetter& getConfigValue) : m_timeout(config::agent::QUEUE_STATUS_REFRESH_TIMER) @@ -104,95 +100,61 @@ class MultiTypeQueue : public IMultiTypeQueue } } - /** - * @brief Delete copy constructor - */ + /// @brief Delete copy constructor MultiTypeQueue(const MultiTypeQueue&) = delete; - /** - * @brief Delete copy assignment operator - */ + /// @brief Delete copy assignment operator MultiTypeQueue& operator=(const MultiTypeQueue&) = delete; - /** - * @brief Delete move constructor - */ + /// @brief Delete move constructor MultiTypeQueue(MultiTypeQueue&&) = delete; - /** - * @brief Delete move assignment operator - */ + /// @brief Delete move assignment operator MultiTypeQueue& operator=(MultiTypeQueue&&) = delete; - /** - * @brief Destructor. - */ + /// @brief Destructor ~MultiTypeQueue() override = default; - /** - * @copydoc IMultiTypeQueue::push(Message, bool) - */ + /// @copydoc IMultiTypeQueue::push(Message, bool) int push(Message message, bool shouldWait = false) override; - /** - * @copydoc IMultiTypeQueue::pushAwaitable(Message) - */ + /// @copydoc IMultiTypeQueue::pushAwaitable(Message) boost::asio::awaitable pushAwaitable(Message message) override; - /** - * @copydoc IMultiTypeQueue::push(std::vector) - */ + /// @copydoc IMultiTypeQueue::push(std::vector) int push(std::vector messages) override; - /** - * @copydoc IMultiTypeQueue::getNext(MessageType, const std::string, const std::string) - */ + /// @copydoc IMultiTypeQueue::getNext(MessageType, const std::string, const std::string) Message getNext(MessageType type, const std::string moduleName = "", const std::string moduleType = "") override; - /** - * @copydoc IMultiTypeQueue::getNextBytesAwaitable(MessageType type, const size_t - * messageQuantity, const std::string moduleName, const std::string moduleType) - */ + /// @copydoc IMultiTypeQueue::getNextBytesAwaitable(MessageType type, const size_t + /// messageQuantity, const std::string moduleName, const std::string moduleType) boost::asio::awaitable> getNextBytesAwaitable(MessageType type, const size_t messageQuantity, const std::string moduleName = "", const std::string moduleType = "") override; - /** - * @copydoc IMultiTypeQueue::getNextBytes(MessageType, size_t, const std::string, const std::string) - */ + /// @copydoc IMultiTypeQueue::getNextBytes(MessageType, size_t, const std::string, const std::string) std::vector getNextBytes(MessageType type, const size_t messageQuantity, const std::string moduleName = "", const std::string moduleType = "") override; - /** - * @copydoc IMultiTypeQueue::pop(MessageType, const std::string) - */ + /// @copydoc IMultiTypeQueue::pop(MessageType, const std::string) bool pop(MessageType type, const std::string moduleName = "") override; - /** - * @copydoc IMultiTypeQueue::popN(MessageType, int, const std::string) - */ + /// @copydoc IMultiTypeQueue::popN(MessageType, int, const std::string) int popN(MessageType type, int messageQuantity, const std::string moduleName = "") override; - /** - * @copydoc IMultiTypeQueue::isEmpty(MessageType, const std::string) - */ + /// @copydoc IMultiTypeQueue::isEmpty(MessageType, const std::string) bool isEmpty(MessageType type, const std::string moduleName = "") override; - /** - * @copydoc IMultiTypeQueue::isFull(MessageType, const std::string) - */ + /// @copydoc IMultiTypeQueue::isFull(MessageType, const std::string) bool isFull(MessageType type, const std::string moduleName = "") override; - /** - * @copydoc IMultiTypeQueue::storedItems(MessageType, const std::string) - */ + /// @copydoc IMultiTypeQueue::storedItems(MessageType, const std::string) int storedItems(MessageType type, const std::string moduleName = "") override; - /** - * @copydoc IMultiTypeQueue::sizePerType(MessageType type) - */ + /// @copydoc IMultiTypeQueue::sizePerType(MessageType type) size_t sizePerType(MessageType type) override; }; diff --git a/src/agent/multitype_queue/src/storage.hpp b/src/agent/multitype_queue/src/storage.hpp index ce38e3d3b7..6c653d868e 100644 --- a/src/agent/multitype_queue/src/storage.hpp +++ b/src/agent/multitype_queue/src/storage.hpp @@ -8,143 +8,105 @@ class Persistence; -/** - * @brief Storage class. - * - * This class provides methods to store, retrieve, and remove JSON messages - * in a database. - */ +/// @brief Storage class. +/// +/// This class provides methods to store, retrieve, and remove JSON messages +/// in a database. class Storage { public: - /** - * @brief Constructor. - * - * @param dbFilePath The path to the database. - * @param tableNames A vector of table names. - */ + /// @brief Constructor + /// @param dbFilePath The path to the database + /// @param tableNames A vector of table names Storage(const std::string& dbFilePath, const std::vector& tableNames); - /** - * @brief Delete copy constructor - */ + /// @brief Delete copy constructor Storage(const Storage&) = delete; - /** - * @brief Delete copy assignment operator - */ + /// @brief Delete copy assignment operator Storage& operator=(const Storage&) = delete; - /** - * @brief Delete move constructor - */ + /// @brief Delete move constructor Storage(Storage&&) = delete; - /** - * @brief Delete move assignment operator - */ + /// @brief Delete move assignment operator Storage& operator=(Storage&&) = delete; - /** - * @brief Destructor. - */ + /// @brief Destructor ~Storage(); - /** - * @brief Store a JSON message in the storage. - * - * @param message The JSON message to store. - * @param tableName The name of the table to store the message in. - * @param moduleName The name of the module that created the message. - * @param moduleType The type of the module that created the message. - * @param metadata The metadata message to store. - * @return The number of stored elements. - */ + /// @brief Store a JSON message in the storage. + /// @param message The JSON message to store. + /// @param tableName The name of the table to store the message in. + /// @param moduleName The name of the module that created the message. + /// @param moduleType The type of the module that created the message. + /// @param metadata The metadata message to store. + /// @return The number of stored elements. int Store(const nlohmann::json& message, const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = "", const std::string& metadata = ""); - /** - * @brief Remove multiple JSON messages. - * - * @param n The number of messages to remove. - * @param tableName The name of the table to remove the message from. - * @param moduleName The name of the module that created the message. - * @param moduleType The module type that created the message. - * @return The number of removed elements. - */ + /// @brief Remove multiple JSON messages. + /// @param n The number of messages to remove. + /// @param tableName The name of the table to remove the message from. + /// @param moduleName The name of the module that created the message. + /// @param moduleType The module type that created the message. + /// @return The number of removed elements. int RemoveMultiple(int n, const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = ""); - /** - * @brief Retrieve multiple JSON messages. - * - * @param n The number of messages to retrieve. - * @param tableName The name of the table to retrieve the message from. - * @param moduleName The name of the module that created the message. - * @param moduleType The module type that created the message. - * @return A vector of retrieved JSON messages. - */ + /// @brief Retrieve multiple JSON messages. + /// @param n The number of messages to retrieve. + /// @param tableName The name of the table to retrieve the message from. + /// @param moduleName The name of the module that created the message. + /// @param moduleType The module type that created the message. + /// @return A vector of retrieved JSON messages. nlohmann::json RetrieveMultiple(int n, const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = ""); - /** - * @brief Retrieve multiple JSON messages based on size from the specified queue. - * - * @param n size occupied by the messages to be retrieved. - * @param tableName The name of the table to retrieve the message from. - * @param moduleName The name of the module. - * @param moduleType The type of the module. - * @return nlohmann::json The retrieved JSON messages. - */ + /// @brief Retrieve multiple JSON messages based on size from the specified queue. + /// @param n size occupied by the messages to be retrieved. + /// @param tableName The name of the table to retrieve the message from. + /// @param moduleName The name of the module. + /// @param moduleType The type of the module. + /// @return nlohmann::json The retrieved JSON messages. nlohmann::json RetrieveBySize(size_t n, const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = ""); - /** - * @brief Get the number of elements in the table. - * @param tableName The name of the table to retrieve the message from. - * @param moduleName The name of the module that created the message. - * @param moduleType The module type that created the message. - * @return The number of elements in the table. - */ + /// @brief Get the number of elements in the table. + /// @param tableName The name of the table to retrieve the message from. + /// @param moduleName The name of the module that created the message. + /// @param moduleType The module type that created the message. + /// @return The number of elements in the table. int GetElementCount(const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = ""); - /** - * @brief Get the bytes occupied by elements stored in the specified queue. - * - * @param tableName The name of the table. - * @param moduleName The name of the module. - * @param moduleType The type of the module. - * @return size_t The bytes occupied by elements stored in the specified queue. - */ + /// @brief Get the bytes occupied by elements stored in the specified queue. + /// @param tableName The name of the table. + /// @param moduleName The name of the module. + /// @param moduleType The type of the module. + /// @return size_t The bytes occupied by elements stored in the specified queue. size_t GetElementsStoredSize(const std::string& tableName, const std::string& moduleName = "", const std::string& moduleType = ""); private: - /** - * @brief Create a table in the database. - * @param tableName The name of the table to create. - */ + /// @brief Create a table in the database. + /// @param tableName The name of the table to create. void CreateTable(const std::string& tableName); - /** - * @brief Pointer to the database connection. - */ + /// @brief Pointer to the database connection. std::unique_ptr m_db; - /** - * @brief Mutex to ensure thread-safe operations. - */ + /// @brief Mutex to ensure thread-safe operations. std::mutex m_mutex; }; From f6a37658c36b21c555bf122af8b7ec87dcd485cf Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Fri, 10 Jan 2025 21:25:20 +0000 Subject: [PATCH 13/18] feat: add module type to multitype_queue functions --- .../include/imultitype_queue.hpp | 18 +++++++++---- .../include/multitype_queue.hpp | 23 +++++++++------- .../multitype_queue/src/multitype_queue.cpp | 26 +++++++++++-------- src/agent/tests/message_queue_utils_test.cpp | 10 +++---- 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/agent/multitype_queue/include/imultitype_queue.hpp b/src/agent/multitype_queue/include/imultitype_queue.hpp index f87fa5ecf8..5eb310aeaf 100644 --- a/src/agent/multitype_queue/include/imultitype_queue.hpp +++ b/src/agent/multitype_queue/include/imultitype_queue.hpp @@ -66,36 +66,44 @@ class IMultiTypeQueue /// @brief Deletes a message from the queue. /// @param type The type of the queue from which to pop the message. /// @param moduleName The name of the module requesting the pop. + /// @param moduleType The type of the module requesting the pop. /// @return true If the message was popped successfully. /// @return false If the message could not be popped. - virtual bool pop(MessageType type, const std::string moduleName = "") = 0; + virtual bool pop(MessageType type, const std::string moduleName = "", const std::string moduleType = "") = 0; /// @brief Deletes N messages from the queue. /// @param type The type of the queue from which to pop the messages. /// @param messageQuantity The quantity of messages to pop. /// @param moduleName The name of the module requesting the pop. + /// @param moduleType The type of the module requesting the pop. /// @return int The number of messages deleted. - virtual int popN(MessageType type, int messageQuantity, const std::string moduleName = "") = 0; + virtual int popN(MessageType type, + int messageQuantity, + const std::string moduleName = "", + const std::string moduleType = "") = 0; /// @brief Checks if a queue is empty. /// @param type The type of the queue. /// @param moduleName The name of the module requesting the check. + /// @param moduleType The type of the module requesting the check. /// @return true If the queue is empty. /// @return false If the queue is not empty. - virtual bool isEmpty(MessageType type, const std::string moduleName = "") = 0; + virtual bool isEmpty(MessageType type, const std::string moduleName = "", const std::string moduleType = "") = 0; /// @brief Checks if a queue is full /// @param type The type of the queue. /// @param moduleName The name of the module requesting the check. + /// @param moduleType The type of the module requesting the check. /// @return true If the queue is full. /// @return false If the queue is not full. - virtual bool isFull(MessageType type, const std::string moduleName = "") = 0; + virtual bool isFull(MessageType type, const std::string moduleName = "", const std::string moduleType = "") = 0; /// @brief Returns the number of items stored in the queue. /// @param type The type of the queue. /// @param moduleName The name of the module requesting the count. + /// @param moduleType The type of the module requesting the count. /// @return int The number of items in the queue. - virtual int storedItems(MessageType type, const std::string moduleName = "") = 0; + virtual int storedItems(MessageType type, const std::string moduleName = "", const std::string moduleType = "") = 0; /// @brief Returns the size of the queue per type /// @param type The type of the queue. diff --git a/src/agent/multitype_queue/include/multitype_queue.hpp b/src/agent/multitype_queue/include/multitype_queue.hpp index feda44dfbc..bb65c9fb90 100644 --- a/src/agent/multitype_queue/include/multitype_queue.hpp +++ b/src/agent/multitype_queue/include/multitype_queue.hpp @@ -140,20 +140,23 @@ class MultiTypeQueue : public IMultiTypeQueue const std::string moduleName = "", const std::string moduleType = "") override; - /// @copydoc IMultiTypeQueue::pop(MessageType, const std::string) - bool pop(MessageType type, const std::string moduleName = "") override; + /// @copydoc IMultiTypeQueue::pop(MessageType, const std::string, const std::string) + bool pop(MessageType type, const std::string moduleName = "", const std::string moduleType = "") override; - /// @copydoc IMultiTypeQueue::popN(MessageType, int, const std::string) - int popN(MessageType type, int messageQuantity, const std::string moduleName = "") override; + /// @copydoc IMultiTypeQueue::popN(MessageType, int, const std::string, const std::string) + int popN(MessageType type, + int messageQuantity, + const std::string moduleName = "", + const std::string moduleType = "") override; - /// @copydoc IMultiTypeQueue::isEmpty(MessageType, const std::string) - bool isEmpty(MessageType type, const std::string moduleName = "") override; + /// @copydoc IMultiTypeQueue::isEmpty(MessageType, const std::string, const std::string) + bool isEmpty(MessageType type, const std::string moduleName = "", const std::string moduleType = "") override; - /// @copydoc IMultiTypeQueue::isFull(MessageType, const std::string) - bool isFull(MessageType type, const std::string moduleName = "") override; + /// @copydoc IMultiTypeQueue::isFull(MessageType, const std::string, const std::string) + bool isFull(MessageType type, const std::string moduleName = "", const std::string moduleType = "") override; - /// @copydoc IMultiTypeQueue::storedItems(MessageType, const std::string) - int storedItems(MessageType type, const std::string moduleName = "") override; + /// @copydoc IMultiTypeQueue::storedItems(MessageType, const std::string, const std::string) + int storedItems(MessageType type, const std::string moduleName = "", const std::string moduleType = "") override; /// @copydoc IMultiTypeQueue::sizePerType(MessageType type) size_t sizePerType(MessageType type) override; diff --git a/src/agent/multitype_queue/src/multitype_queue.cpp b/src/agent/multitype_queue/src/multitype_queue.cpp index 77e21cc8ce..c398eaa391 100644 --- a/src/agent/multitype_queue/src/multitype_queue.cpp +++ b/src/agent/multitype_queue/src/multitype_queue.cpp @@ -202,12 +202,12 @@ std::vector MultiTypeQueue::getNextBytes(MessageType type, return result; } -bool MultiTypeQueue::pop(MessageType type, const std::string moduleName) +bool MultiTypeQueue::pop(MessageType type, const std::string moduleName, const std::string moduleType) { bool result = false; if (m_mapMessageTypeName.contains(type)) { - result = m_persistenceDest->RemoveMultiple(1, m_mapMessageTypeName.at(type), moduleName); + result = m_persistenceDest->RemoveMultiple(1, m_mapMessageTypeName.at(type), moduleName, moduleType); } else { @@ -216,12 +216,16 @@ bool MultiTypeQueue::pop(MessageType type, const std::string moduleName) return result; } -int MultiTypeQueue::popN(MessageType type, int messageQuantity, const std::string moduleName) +int MultiTypeQueue::popN(MessageType type, + int messageQuantity, + const std::string moduleName, + const std::string moduleType) { int result = 0; if (m_mapMessageTypeName.contains(type)) { - result = m_persistenceDest->RemoveMultiple(messageQuantity, m_mapMessageTypeName.at(type), moduleName); + result = + m_persistenceDest->RemoveMultiple(messageQuantity, m_mapMessageTypeName.at(type), moduleName, moduleType); } else { @@ -230,11 +234,11 @@ int MultiTypeQueue::popN(MessageType type, int messageQuantity, const std::strin return result; } -bool MultiTypeQueue::isEmpty(MessageType type, const std::string moduleName) +bool MultiTypeQueue::isEmpty(MessageType type, const std::string moduleName, const std::string moduleType) { if (m_mapMessageTypeName.contains(type)) { - return m_persistenceDest->GetElementCount(m_mapMessageTypeName.at(type), moduleName) == 0; + return m_persistenceDest->GetElementCount(m_mapMessageTypeName.at(type), moduleName, moduleType) == 0; } else { @@ -243,12 +247,12 @@ bool MultiTypeQueue::isEmpty(MessageType type, const std::string moduleName) return false; } -bool MultiTypeQueue::isFull(MessageType type, const std::string moduleName) +bool MultiTypeQueue::isFull(MessageType type, const std::string moduleName, const std::string moduleType) { if (m_mapMessageTypeName.contains(type)) { - return static_cast(m_persistenceDest->GetElementCount(m_mapMessageTypeName.at(type), moduleName)) == - m_maxItems; + return static_cast(m_persistenceDest->GetElementCount( + m_mapMessageTypeName.at(type), moduleName, moduleType)) == m_maxItems; } else { @@ -257,11 +261,11 @@ bool MultiTypeQueue::isFull(MessageType type, const std::string moduleName) return false; } -int MultiTypeQueue::storedItems(MessageType type, const std::string moduleName) +int MultiTypeQueue::storedItems(MessageType type, const std::string moduleName, const std::string moduleType) { if (m_mapMessageTypeName.contains(type)) { - return m_persistenceDest->GetElementCount(m_mapMessageTypeName.at(type), moduleName); + return m_persistenceDest->GetElementCount(m_mapMessageTypeName.at(type), moduleName, moduleType); } else { diff --git a/src/agent/tests/message_queue_utils_test.cpp b/src/agent/tests/message_queue_utils_test.cpp index 680a7c1ba1..69a06379c0 100644 --- a/src/agent/tests/message_queue_utils_test.cpp +++ b/src/agent/tests/message_queue_utils_test.cpp @@ -29,10 +29,10 @@ class MockMultiTypeQueue : public MultiTypeQueue getNextBytesAwaitable, (MessageType, const size_t, const std::string, const std::string), (override)); - MOCK_METHOD(int, popN, (MessageType, int, const std::string), (override)); + MOCK_METHOD(int, popN, (MessageType, int, const std::string, const std::string), (override)); MOCK_METHOD(int, push, (Message, bool), (override)); MOCK_METHOD(int, push, (std::vector), (override)); - MOCK_METHOD(bool, isEmpty, (MessageType, const std::string), (override)); + MOCK_METHOD(bool, isEmpty, (MessageType, const std::string, const std::string), (override)); MOCK_METHOD(Message, getNext, (MessageType, const std::string, const std::string), (override)); }; @@ -157,7 +157,7 @@ TEST_F(MessageQueueUtilsTest, GetEmptyMessagesFromQueueTest) TEST_F(MessageQueueUtilsTest, PopMessagesFromQueueTest) { - EXPECT_CALL(*mockQueue, popN(MessageType::STATEFUL, 1, "")).Times(1); + EXPECT_CALL(*mockQueue, popN(MessageType::STATEFUL, 1, "", "")).Times(1); PopMessagesFromQueue(mockQueue, MessageType::STATEFUL, 1); } @@ -189,7 +189,7 @@ TEST_F(MessageQueueUtilsTest, NoCommandsToPushTest) TEST_F(MessageQueueUtilsTest, GetCommandFromQueueEmptyTest) { - EXPECT_CALL(*mockQueue, isEmpty(MessageType::COMMAND, "")).WillOnce(testing::Return(true)); + EXPECT_CALL(*mockQueue, isEmpty(MessageType::COMMAND, "", "")).WillOnce(testing::Return(true)); ASSERT_EQ(std::nullopt, GetCommandFromQueue(mockQueue)); } @@ -198,7 +198,7 @@ TEST_F(MessageQueueUtilsTest, GetCommandFromQueueTest) { Message testMessage {MessageType::COMMAND, BASE_DATA_CONTENT}; - EXPECT_CALL(*mockQueue, isEmpty(MessageType::COMMAND, "")).WillOnce(testing::Return(false)); + EXPECT_CALL(*mockQueue, isEmpty(MessageType::COMMAND, "", "")).WillOnce(testing::Return(false)); EXPECT_CALL(*mockQueue, getNext(MessageType::COMMAND, "", "")).WillOnce(testing::Return(testMessage)); From 27a26bcc3faa3ded86f92f40598cf192df57e472 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Mon, 13 Jan 2025 18:04:41 +0000 Subject: [PATCH 14/18] fix: propagate exception in case of create table failure --- src/agent/agent_info/src/agent_info_persistance.cpp | 3 +++ src/agent/command_store/src/command_store.cpp | 1 + src/agent/multitype_queue/src/storage.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 8fee4455bb..9fe0955203 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -81,6 +81,7 @@ void AgentInfoPersistance::CreateAgentInfoTable() catch (const std::exception& e) { LogError("Error creating table: {}.", e.what()); + throw; } } @@ -96,6 +97,7 @@ void AgentInfoPersistance::CreateAgentGroupTable() catch (const std::exception& e) { LogError("Error creating table: {}.", e.what()); + throw; } } @@ -117,6 +119,7 @@ void AgentInfoPersistance::InsertDefaultAgentInfo() catch (const std::exception& e) { LogError("Error inserting default agent info: {}.", e.what()); + throw; } } diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index 21f007b2e7..c7a046a370 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -70,6 +70,7 @@ namespace command_store catch (std::exception& e) { LogError("CreateTable operation failed: {}.", e.what()); + throw; } } } diff --git a/src/agent/multitype_queue/src/storage.cpp b/src/agent/multitype_queue/src/storage.cpp index bd8eb2d6b1..858afc20fa 100644 --- a/src/agent/multitype_queue/src/storage.cpp +++ b/src/agent/multitype_queue/src/storage.cpp @@ -103,6 +103,7 @@ void Storage::CreateTable(const std::string& tableName) catch (const std::exception& e) { LogError("Error creating table: {}.", e.what()); + throw; } } From 79a5fe6d5510534f6ba2632a16a65f767c73754b Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Mon, 13 Jan 2025 20:26:14 +0000 Subject: [PATCH 15/18] feat: replace booleans with flags in columns --- .../agent_info/src/agent_info_persistance.cpp | 11 +++--- src/agent/command_store/src/command_store.cpp | 14 ++++---- src/agent/multitype_queue/src/storage.cpp | 8 ++--- src/agent/persistence/include/column.hpp | 30 ++++++++-------- src/agent/persistence/src/sqlite_manager.cpp | 8 ++--- .../persistence/tests/sqlite_manager_test.cpp | 36 +++++++++---------- 6 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index 9fe0955203..d69265a839 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -72,9 +72,9 @@ void AgentInfoPersistance::CreateAgentInfoTable() { try { - const Keys columns = {ColumnKey(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, true, false), - ColumnKey(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, true, false), - ColumnKey(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, true, false, true)}; + const Keys columns = {ColumnKey(AGENT_INFO_NAME_COLUMN_NAME, ColumnType::TEXT, NOT_NULL), + ColumnKey(AGENT_INFO_KEY_COLUMN_NAME, ColumnType::TEXT, NOT_NULL), + ColumnKey(AGENT_INFO_UUID_COLUMN_NAME, ColumnType::TEXT, NOT_NULL | PRIMARY_KEY)}; m_db->CreateTable(AGENT_INFO_TABLE_NAME, columns); } @@ -89,8 +89,9 @@ void AgentInfoPersistance::CreateAgentGroupTable() { try { - const Keys columns = {ColumnKey(AGENT_GROUP_ID_COLUMN_NAME, ColumnType::INTEGER, true, true, true), - ColumnKey(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, true, false)}; + const Keys columns = { + ColumnKey(AGENT_GROUP_ID_COLUMN_NAME, ColumnType::INTEGER, NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT), + ColumnKey(AGENT_GROUP_NAME_COLUMN_NAME, ColumnType::TEXT, NOT_NULL)}; m_db->CreateTable(AGENT_GROUP_TABLE_NAME, columns); } diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index c7a046a370..6d20f98910 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -55,13 +55,13 @@ namespace command_store if (!m_dataBase->TableExists(COMMAND_STORE_TABLE_NAME)) { Keys columns; - columns.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, true, false, true); - columns.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, true, false, false); - columns.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, true, false, false); - columns.emplace_back(COMMAND_STORE_PARAMETERS_COLUMN_NAME, ColumnType::TEXT, true, false, false); - columns.emplace_back(COMMAND_STORE_RESULT_COLUMN_NAME, ColumnType::TEXT, true, false, false); - columns.emplace_back(COMMAND_STORE_STATUS_COLUMN_NAME, ColumnType::INTEGER, true, false, false); - columns.emplace_back(COMMAND_STORE_TIME_COLUMN_NAME, ColumnType::REAL, true, false, false); + columns.emplace_back(COMMAND_STORE_ID_COLUMN_NAME, ColumnType::TEXT, NOT_NULL | PRIMARY_KEY); + columns.emplace_back(COMMAND_STORE_MODULE_COLUMN_NAME, ColumnType::TEXT, NOT_NULL); + columns.emplace_back(COMMAND_STORE_COMMAND_COLUMN_NAME, ColumnType::TEXT, NOT_NULL); + columns.emplace_back(COMMAND_STORE_PARAMETERS_COLUMN_NAME, ColumnType::TEXT, NOT_NULL); + columns.emplace_back(COMMAND_STORE_RESULT_COLUMN_NAME, ColumnType::TEXT, NOT_NULL); + columns.emplace_back(COMMAND_STORE_STATUS_COLUMN_NAME, ColumnType::INTEGER, NOT_NULL); + columns.emplace_back(COMMAND_STORE_TIME_COLUMN_NAME, ColumnType::REAL, NOT_NULL); try { diff --git a/src/agent/multitype_queue/src/storage.cpp b/src/agent/multitype_queue/src/storage.cpp index 858afc20fa..7f761a5c51 100644 --- a/src/agent/multitype_queue/src/storage.cpp +++ b/src/agent/multitype_queue/src/storage.cpp @@ -93,10 +93,10 @@ void Storage::CreateTable(const std::string& tableName) try { Keys columns; - columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT, false, false); - columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT, false, false); - columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT, false, false); - columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT, true, false); + columns.emplace_back(MODULE_NAME_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MODULE_TYPE_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(METADATA_COLUMN_NAME, ColumnType::TEXT); + columns.emplace_back(MESSAGE_COLUMN_NAME, ColumnType::TEXT, NOT_NULL); m_db->CreateTable(tableName, columns); } diff --git a/src/agent/persistence/include/column.hpp b/src/agent/persistence/include/column.hpp index b795cf3138..43dedfafd9 100644 --- a/src/agent/persistence/include/column.hpp +++ b/src/agent/persistence/include/column.hpp @@ -25,6 +25,15 @@ enum class ColumnType REAL }; +/// @brief Supported column attributes for tables. +enum +{ + NONE = 0, + NOT_NULL = 1 << 0, + PRIMARY_KEY = 1 << 1, + AUTO_INCREMENT = 1 << 2 +}; + /// @brief Represents a database column. class ColumnName { @@ -52,26 +61,15 @@ class ColumnKey : public ColumnName /// @brief Constructor for defining a table column with attributes. /// @param name The name of the column. /// @param type The data type of the column (INTEGER, TEXT, or REAL). - /// @param notNull Whether the column has a NOT NULL constraint. - /// @param autoIncr Whether the column is AUTOINCREMENT (relevant for primary keys). - /// @param primary Whether the column is part of the primary key. - ColumnKey( - std::string name, const ColumnType type, const bool notNull, const bool autoIncr, const bool primary = false) + /// @param attributes The attributes of the column (NOT_NULL, PRIMARY_KEY, AUTO_INCREMENT). + ColumnKey(std::string name, const ColumnType type, const int attributes = NONE) : ColumnName(std::move(name), type) - , NotNull(notNull) - , AutoIncrement(autoIncr) - , PrimaryKey(primary) + , Attributes(attributes) { } - /// @brief Whether the column can contain NULL values - bool NotNull; - - /// @brief Whether the column is an auto-incrementing primary key - bool AutoIncrement; - - /// @brief Whether the column is a primary key - bool PrimaryKey; + /// @brief The attributes of the column + int Attributes; }; /// @brief Represents a database column with data. diff --git a/src/agent/persistence/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp index 1ae9349be9..bf08397afd 100644 --- a/src/agent/persistence/src/sqlite_manager.cpp +++ b/src/agent/persistence/src/sqlite_manager.cpp @@ -53,11 +53,11 @@ void SQLiteManager::CreateTable(const std::string& tableName, const Keys& cols) std::vector fields; for (const auto& col : cols) { - std::string field = - fmt::format("{} {}{}", col.Name, MAP_COL_TYPE_STRING.at(col.Type), (col.NotNull) ? " NOT NULL" : ""); - if (col.PrimaryKey) + std::string field = fmt::format( + "{} {}{}", col.Name, MAP_COL_TYPE_STRING.at(col.Type), (col.Attributes & NOT_NULL) ? " NOT NULL" : ""); + if (col.Attributes & PRIMARY_KEY) { - pk.push_back(col.AutoIncrement ? fmt::format("{} AUTOINCREMENT", col.Name) : col.Name); + pk.push_back((col.Attributes & AUTO_INCREMENT) ? fmt::format("{} AUTOINCREMENT", col.Name) : col.Name); } fields.push_back(field); } diff --git a/src/agent/persistence/tests/sqlite_manager_test.cpp b/src/agent/persistence/tests/sqlite_manager_test.cpp index 494ce610ba..cce4c5512a 100644 --- a/src/agent/persistence/tests/sqlite_manager_test.cpp +++ b/src/agent/persistence/tests/sqlite_manager_test.cpp @@ -54,22 +54,22 @@ class SQLiteManagerTest : public ::testing::Test TEST_F(SQLiteManagerTest, CreateTableTest) { - ColumnKey col1 {"Id", ColumnType::INTEGER, true, true, true}; - ColumnKey col2 {"Name", ColumnType::TEXT, true, false, false}; - ColumnKey col3 {"Status", ColumnType::TEXT, true, false}; - ColumnKey col4 {"Module", ColumnType::TEXT, false, false}; - ColumnKey col5 {"Orden", ColumnType::INTEGER, false, false, false}; - ColumnKey col6 {"Amount", ColumnType::REAL, false, false, false}; + ColumnKey col1 {"Id", ColumnType::INTEGER, NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT}; + ColumnKey col2 {"Name", ColumnType::TEXT, NOT_NULL}; + ColumnKey col3 {"Status", ColumnType::TEXT, NOT_NULL}; + ColumnKey col4 {"Module", ColumnType::TEXT}; + ColumnKey col5 {"Orden", ColumnType::INTEGER}; + ColumnKey col6 {"Amount", ColumnType::REAL}; EXPECT_NO_THROW(m_db->CreateTable(m_tableName, {col1, col2, col3, col4, col5, col6})); EXPECT_TRUE(m_db->TableExists(m_tableName)); - ColumnKey col21 {"Id", ColumnType::INTEGER, true, false, true}; - ColumnKey col212 {"Id2", ColumnType::INTEGER, true, false, true}; - ColumnKey col22 {"Name", ColumnType::TEXT, true, false, true}; - ColumnKey col23 {"Status", ColumnType::TEXT, true, false}; - ColumnKey col24 {"Module", ColumnType::TEXT, false, false}; - ColumnKey col25 {"Orden", ColumnType::INTEGER, false, false, false}; - ColumnKey col26 {"Amount", ColumnType::REAL, false, false, false}; + ColumnKey col21 {"Id", ColumnType::INTEGER, NOT_NULL | PRIMARY_KEY}; + ColumnKey col212 {"Id2", ColumnType::INTEGER, NOT_NULL | PRIMARY_KEY}; + ColumnKey col22 {"Name", ColumnType::TEXT, NOT_NULL | PRIMARY_KEY}; + ColumnKey col23 {"Status", ColumnType::TEXT, NOT_NULL}; + ColumnKey col24 {"Module", ColumnType::TEXT}; + ColumnKey col25 {"Orden", ColumnType::INTEGER}; + ColumnKey col26 {"Amount", ColumnType::REAL}; EXPECT_NO_THROW(m_db->CreateTable("TableTest2", {col21, col212, col22, col23, col24, col25, col26})); EXPECT_TRUE(m_db->TableExists("TableTest2")); } @@ -409,11 +409,11 @@ TEST_F(SQLiteManagerTest, TransactionTest) TEST_F(SQLiteManagerTest, DropTableTest) { - ColumnKey col1 {"Id", ColumnType::INTEGER, true, true, true}; - ColumnKey col2 {"Name", ColumnType::TEXT, true, false}; - ColumnKey col3 {"Status", ColumnType::TEXT, true, false}; - ColumnKey col4 {"Module", ColumnType::TEXT, false, false}; - ColumnKey col5 {"Orden", ColumnType::INTEGER, false, false, false}; + ColumnKey col1 {"Id", ColumnType::INTEGER, NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT}; + ColumnKey col2 {"Name", ColumnType::TEXT, NOT_NULL}; + ColumnKey col3 {"Status", ColumnType::TEXT, NOT_NULL}; + ColumnKey col4 {"Module", ColumnType::TEXT}; + ColumnKey col5 {"Orden", ColumnType::INTEGER}; EXPECT_NO_THROW(m_db->CreateTable("DropMe", {col1, col2, col3, col4, col5})); EXPECT_TRUE(m_db->TableExists("DropMe")); From 3385228b914e723a0d89acf3d994b8646e1efcb4 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Tue, 14 Jan 2025 17:56:48 +0000 Subject: [PATCH 16/18] fix: escape single quotes in sqlite manager --- src/agent/persistence/src/sqlite_manager.cpp | 48 +++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/agent/persistence/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp index bf08397afd..1536797fa0 100644 --- a/src/agent/persistence/src/sqlite_manager.cpp +++ b/src/agent/persistence/src/sqlite_manager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include const std::map MAP_COL_TYPE_STRING { {ColumnType::INTEGER, "INTEGER"}, {ColumnType::TEXT, "TEXT"}, {ColumnType::REAL, "REAL"}}; @@ -14,6 +15,18 @@ const std::map MAP_ORDER_STRING {{OrderType::ASC, "ASC"} SQLiteManager::~SQLiteManager() = default; +namespace +{ + const std::string& TO_SEARCH = "'"; + const std::string& TO_REPLACE = "''"; + + /// @brief Escapes single quotes in a string. + std::string EscapeSingleQuotes(const std::string& str) + { + return std::regex_replace(str, std::regex(TO_SEARCH), TO_REPLACE); + } +} // namespace + ColumnType SQLiteManager::ColumnTypeFromSQLiteType(const int type) const { if (type == SQLite::INTEGER) @@ -79,10 +92,13 @@ void SQLiteManager::Insert(const std::string& tableName, const Row& cols) names.push_back(col.Name); if (col.Type == ColumnType::TEXT) { - values.push_back(fmt::format("'{}'", col.Value)); + auto escapedValue = EscapeSingleQuotes(col.Value); + values.push_back(fmt::format("'{}'", escapedValue)); } else + { values.push_back(col.Value); + } } std::string queryString = @@ -107,7 +123,8 @@ void SQLiteManager::Update(const std::string& tableName, { if (col.Type == ColumnType::TEXT) { - setFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + auto escapedValue = EscapeSingleQuotes(col.Value); + setFields.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); } else { @@ -124,7 +141,8 @@ void SQLiteManager::Update(const std::string& tableName, { if (col.Type == ColumnType::TEXT) { - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + auto escapedValue = EscapeSingleQuotes(col.Value); + conditions.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); } else { @@ -149,7 +167,8 @@ void SQLiteManager::Remove(const std::string& tableName, const Criteria& selCrit { if (col.Type == ColumnType::TEXT) { - critFields.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + auto escapedValue = EscapeSingleQuotes(col.Value); + critFields.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); } else { @@ -217,9 +236,14 @@ std::vector SQLiteManager::Select(const std::string& tableName, for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + { + auto escapedValue = EscapeSingleQuotes(col.Value); + conditions.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); + } else + { conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); + } } condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } @@ -280,9 +304,14 @@ int SQLiteManager::GetCount(const std::string& tableName, const Criteria& selCri for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + { + auto escapedValue = EscapeSingleQuotes(col.Value); + conditions.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); + } else + { conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); + } } condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } @@ -340,9 +369,14 @@ size_t SQLiteManager::GetSize(const std::string& tableName, for (const auto& col : selCriteria) { if (col.Type == ColumnType::TEXT) - conditions.push_back(fmt::format("{}='{}'", col.Name, col.Value)); + { + auto escapedValue = EscapeSingleQuotes(col.Value); + conditions.push_back(fmt::format("{}='{}'", col.Name, escapedValue)); + } else + { conditions.push_back(fmt::format("{}={}", col.Name, col.Value)); + } } condition = fmt::format("WHERE {}", fmt::join(conditions, fmt::format(" {} ", MAP_LOGOP_STRING.at(logOp)))); } From ac5d8d9b96493c40d26f63412f4942140ce58696 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Tue, 14 Jan 2025 20:22:42 +0000 Subject: [PATCH 17/18] feat: create namespace column to enclose everything related and avoid names confict --- .../agent_info/src/agent_info_persistance.cpp | 2 + src/agent/command_store/src/command_store.cpp | 2 + src/agent/multitype_queue/src/storage.cpp | 2 + src/agent/persistence/include/column.hpp | 155 +++++++++--------- src/agent/persistence/include/persistence.hpp | 38 ++--- src/agent/persistence/src/sqlite_manager.cpp | 2 + src/agent/persistence/src/sqlite_manager.hpp | 40 ++--- .../persistence/tests/sqlite_manager_test.cpp | 2 + 8 files changed, 128 insertions(+), 115 deletions(-) diff --git a/src/agent/agent_info/src/agent_info_persistance.cpp b/src/agent/agent_info/src/agent_info_persistance.cpp index d69265a839..478b0438cc 100644 --- a/src/agent/agent_info/src/agent_info_persistance.cpp +++ b/src/agent/agent_info/src/agent_info_persistance.cpp @@ -6,6 +6,8 @@ #include #include +using namespace column; + namespace { // database diff --git a/src/agent/command_store/src/command_store.cpp b/src/agent/command_store/src/command_store.cpp index 6d20f98910..e1f4bb1d85 100644 --- a/src/agent/command_store/src/command_store.cpp +++ b/src/agent/command_store/src/command_store.cpp @@ -11,6 +11,8 @@ #include #include +using namespace column; + namespace { // database diff --git a/src/agent/multitype_queue/src/storage.cpp b/src/agent/multitype_queue/src/storage.cpp index 7f761a5c51..3b7bfa2276 100644 --- a/src/agent/multitype_queue/src/storage.cpp +++ b/src/agent/multitype_queue/src/storage.cpp @@ -6,6 +6,8 @@ #include #include +using namespace column; + namespace { // column names diff --git a/src/agent/persistence/include/column.hpp b/src/agent/persistence/include/column.hpp index 43dedfafd9..2bd3e2a6a8 100644 --- a/src/agent/persistence/include/column.hpp +++ b/src/agent/persistence/include/column.hpp @@ -3,94 +3,97 @@ #include #include -/// @brief Logical operators for combining selection criteria in queries. -enum class LogicalOperator +namespace column { - AND, - OR -}; + /// @brief Logical operators for combining selection criteria in queries. + enum class LogicalOperator + { + AND, + OR + }; -/// @brief Supported order types for sorting results. -enum class OrderType -{ - ASC, - DESC -}; + /// @brief Supported order types for sorting results. + enum class OrderType + { + ASC, + DESC + }; -/// @brief Supported column data types for tables. -enum class ColumnType -{ - INTEGER, - TEXT, - REAL -}; + /// @brief Supported column data types for tables. + enum class ColumnType + { + INTEGER, + TEXT, + REAL + }; -/// @brief Supported column attributes for tables. -enum -{ - NONE = 0, - NOT_NULL = 1 << 0, - PRIMARY_KEY = 1 << 1, - AUTO_INCREMENT = 1 << 2 -}; + /// @brief Supported column attributes for tables. + enum + { + NONE = 0, + NOT_NULL = 1 << 0, + PRIMARY_KEY = 1 << 1, + AUTO_INCREMENT = 1 << 2 + }; -/// @brief Represents a database column. -class ColumnName -{ -public: - /// @brief Constructor for defining a table column. - /// @param name The name of the column. - /// @param type The data type of the column (INTEGER, TEXT, or REAL). - ColumnName(std::string name, const ColumnType type) - : Name(std::move(name)) - , Type(type) + /// @brief Represents a database column. + class ColumnName { - } + public: + /// @brief Constructor for defining a table column. + /// @param name The name of the column. + /// @param type The data type of the column (INTEGER, TEXT, or REAL). + ColumnName(std::string name, const ColumnType type) + : Name(std::move(name)) + , Type(type) + { + } - /// @brief The name of the column - std::string Name; + /// @brief The name of the column + std::string Name; - /// @brief The type of the column - ColumnType Type; -}; + /// @brief The type of the column + ColumnType Type; + }; -/// @brief Represents a database column with attributes. -class ColumnKey : public ColumnName -{ -public: - /// @brief Constructor for defining a table column with attributes. - /// @param name The name of the column. - /// @param type The data type of the column (INTEGER, TEXT, or REAL). - /// @param attributes The attributes of the column (NOT_NULL, PRIMARY_KEY, AUTO_INCREMENT). - ColumnKey(std::string name, const ColumnType type, const int attributes = NONE) - : ColumnName(std::move(name), type) - , Attributes(attributes) + /// @brief Represents a database column with attributes. + class ColumnKey : public ColumnName { - } + public: + /// @brief Constructor for defining a table column with attributes. + /// @param name The name of the column. + /// @param type The data type of the column (INTEGER, TEXT, or REAL). + /// @param attributes The attributes of the column (NOT_NULL, PRIMARY_KEY, AUTO_INCREMENT). + ColumnKey(std::string name, const ColumnType type, const int attributes = NONE) + : ColumnName(std::move(name), type) + , Attributes(attributes) + { + } - /// @brief The attributes of the column - int Attributes; -}; + /// @brief The attributes of the column + int Attributes; + }; -/// @brief Represents a database column with data. -class ColumnValue : public ColumnName -{ -public: - /// @brief Constructor for defining a column with a specific value. - /// @param name The name of the column. - /// @param type The data type of the column. - /// @param value The value of the column. - ColumnValue(std::string name, const ColumnType type, std::string value) - : ColumnName(std::move(name), type) - , Value(std::move(value)) + /// @brief Represents a database column with data. + class ColumnValue : public ColumnName { - } + public: + /// @brief Constructor for defining a column with a specific value. + /// @param name The name of the column. + /// @param type The data type of the column. + /// @param value The value of the column. + ColumnValue(std::string name, const ColumnType type, std::string value) + : ColumnName(std::move(name), type) + , Value(std::move(value)) + { + } - /// @brief The value of the column as a string - std::string Value; -}; + /// @brief The value of the column as a string + std::string Value; + }; -using Names = std::vector; -using Keys = std::vector; -using Row = std::vector; -using Criteria = std::vector; + using Names = std::vector; + using Keys = std::vector; + using Row = std::vector; + using Criteria = std::vector; +} // namespace column diff --git a/src/agent/persistence/include/persistence.hpp b/src/agent/persistence/include/persistence.hpp index f21fa021a8..da8a64e98a 100644 --- a/src/agent/persistence/include/persistence.hpp +++ b/src/agent/persistence/include/persistence.hpp @@ -22,12 +22,12 @@ class Persistence /// @brief Creates a new table with specified keys if it doesn't already exist. /// @param tableName The name of the table to create. /// @param cols Keys specifying the table schema. - virtual void CreateTable(const std::string& tableName, const Keys& cols) = 0; + virtual void CreateTable(const std::string& tableName, const column::Keys& cols) = 0; /// @brief Inserts data into a specified table. /// @param tableName The name of the table where data is inserted. /// @param cols Row with values to insert. - virtual void Insert(const std::string& tableName, const Row& cols) = 0; + virtual void Insert(const std::string& tableName, const column::Row& cols) = 0; /// @brief Updates rows in a specified table with optional criteria. /// @param tableName The name of the table to update. @@ -35,17 +35,17 @@ class Persistence /// @param selCriteria Optional criteria to filter rows to update. /// @param logOp Logical operator to combine selection criteria. virtual void Update(const std::string& tableName, - const Row& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) = 0; + const column::Row& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) = 0; /// @brief Removes rows from a specified table with optional criteria. /// @param tableName The name of the table to delete from. /// @param selCriteria Optional criteria to filter rows to delete. /// @param logOp Logical operator to combine selection criteria. virtual void Remove(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) = 0; + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) = 0; /// @brief Drops a specified table from the database. /// @param tableName The name of the table to drop. @@ -60,13 +60,13 @@ class Persistence /// @param orderType The order type (ASC or DESC). /// @param limit The maximum number of rows to retrieve. /// @return A vector of rows matching the criteria. - virtual std::vector Select(const std::string& tableName, - const Names& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND, - const Names& orderBy = {}, - OrderType orderType = OrderType::ASC, - int limit = 0) = 0; + virtual std::vector Select(const std::string& tableName, + const column::Names& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND, + const column::Names& orderBy = {}, + column::OrderType orderType = column::OrderType::ASC, + int limit = 0) = 0; /// @brief Retrieves the number of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -74,8 +74,8 @@ class Persistence /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The number of rows in the table. virtual int GetCount(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) = 0; + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) = 0; /// @brief Retrieves the size in bytes of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -84,9 +84,9 @@ class Persistence /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The size in bytes of the rows in the table. virtual size_t GetSize(const std::string& tableName, - const Names& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) = 0; + const column::Names& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) = 0; /// @brief Begins a transaction in the database. /// @return The transaction ID. diff --git a/src/agent/persistence/src/sqlite_manager.cpp b/src/agent/persistence/src/sqlite_manager.cpp index 1536797fa0..2c97eb15a5 100644 --- a/src/agent/persistence/src/sqlite_manager.cpp +++ b/src/agent/persistence/src/sqlite_manager.cpp @@ -7,6 +7,8 @@ #include #include +using namespace column; + const std::map MAP_COL_TYPE_STRING { {ColumnType::INTEGER, "INTEGER"}, {ColumnType::TEXT, "TEXT"}, {ColumnType::REAL, "REAL"}}; const std::map MAP_LOGOP_STRING {{LogicalOperator::AND, "AND"}, diff --git a/src/agent/persistence/src/sqlite_manager.hpp b/src/agent/persistence/src/sqlite_manager.hpp index e722dc6fe9..18b981e7dc 100644 --- a/src/agent/persistence/src/sqlite_manager.hpp +++ b/src/agent/persistence/src/sqlite_manager.hpp @@ -47,12 +47,12 @@ class SQLiteManager : public Persistence /// @brief Creates a new table with specified keys if it doesn't already exist. /// @param tableName The name of the table to create. /// @param cols Keys specifying the table schema. - void CreateTable(const std::string& tableName, const Keys& cols) override; + void CreateTable(const std::string& tableName, const column::Keys& cols) override; /// @brief Inserts data into a specified table. /// @param tableName The name of the table where data is inserted. /// @param cols Row with values to insert. - void Insert(const std::string& tableName, const Row& cols) override; + void Insert(const std::string& tableName, const column::Row& cols) override; /// @brief Updates rows in a specified table with optional criteria. /// @param tableName The name of the table to update. @@ -60,17 +60,17 @@ class SQLiteManager : public Persistence /// @param selCriteria Optional criteria to filter rows to update. /// @param logOp Logical operator to combine selection criteria. void Update(const std::string& tableName, - const Row& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) override; + const column::Row& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) override; /// @brief Removes rows from a specified table with optional criteria. /// @param tableName The name of the table to delete from. /// @param selCriteria Optional criteria to filter rows to delete. /// @param logOp Logical operator to combine selection criteria. void Remove(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) override; + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) override; /// @brief Drops a specified table from the database. /// @param tableName The name of the table to drop. @@ -85,13 +85,13 @@ class SQLiteManager : public Persistence /// @param orderType The order type (ASC or DESC). /// @param limit The maximum number of rows to retrieve. /// @return A vector of rows matching the criteria. - std::vector Select(const std::string& tableName, - const Names& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND, - const Names& orderBy = {}, - OrderType orderType = OrderType::ASC, - int limit = 0) override; + std::vector Select(const std::string& tableName, + const column::Names& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND, + const column::Names& orderBy = {}, + column::OrderType orderType = column::OrderType::ASC, + int limit = 0) override; /// @brief Retrieves the number of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -99,8 +99,8 @@ class SQLiteManager : public Persistence /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The number of rows in the table. int GetCount(const std::string& tableName, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) override; + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) override; /// @brief Retrieves the size in bytes of rows in a specified table. /// @param tableName The name of the table to count rows in. @@ -109,9 +109,9 @@ class SQLiteManager : public Persistence /// @param logOp Logical operator to combine selection criteria (AND/OR). /// @return The size in bytes of the rows in the table. size_t GetSize(const std::string& tableName, - const Names& fields, - const Criteria& selCriteria = {}, - LogicalOperator logOp = LogicalOperator::AND) override; + const column::Names& fields, + const column::Criteria& selCriteria = {}, + column::LogicalOperator logOp = column::LogicalOperator::AND) override; /// @brief Begins a transaction in the SQLite database. /// @return The transaction ID. @@ -129,7 +129,7 @@ class SQLiteManager : public Persistence /// @brief Converts SQLite data types to ColumnType enums. /// @param type SQLite data type integer code. /// @return Corresponding ColumnType enum. - ColumnType ColumnTypeFromSQLiteType(const int type) const; + column::ColumnType ColumnTypeFromSQLiteType(const int type) const; /// @brief Executes a raw SQL query on the database. /// @param query The SQL query string to execute. diff --git a/src/agent/persistence/tests/sqlite_manager_test.cpp b/src/agent/persistence/tests/sqlite_manager_test.cpp index cce4c5512a..a542bdd175 100644 --- a/src/agent/persistence/tests/sqlite_manager_test.cpp +++ b/src/agent/persistence/tests/sqlite_manager_test.cpp @@ -6,6 +6,8 @@ #include #include +using namespace column; + class SQLiteManagerTest : public ::testing::Test { protected: From bd221982acd209bb9dfdcc5c7cec379868663d50 Mon Sep 17 00:00:00 2001 From: Tomas Turina Date: Wed, 15 Jan 2025 15:35:46 +0000 Subject: [PATCH 18/18] fix: remove unnecesary cout usages in agent tests --- .../tests/multitype_queue_test.cpp | 1 - .../multitype_queue/tests/storage_test.cpp | 1 - .../persistence/tests/sqlite_manager_test.cpp | 30 ------------------- 3 files changed, 32 deletions(-) diff --git a/src/agent/multitype_queue/tests/multitype_queue_test.cpp b/src/agent/multitype_queue/tests/multitype_queue_test.cpp index f582ed8015..2142d8f898 100644 --- a/src/agent/multitype_queue/tests/multitype_queue_test.cpp +++ b/src/agent/multitype_queue/tests/multitype_queue_test.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/src/agent/multitype_queue/tests/storage_test.cpp b/src/agent/multitype_queue/tests/storage_test.cpp index 1d9bff7de6..5f59558615 100644 --- a/src/agent/multitype_queue/tests/storage_test.cpp +++ b/src/agent/multitype_queue/tests/storage_test.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/agent/persistence/tests/sqlite_manager_test.cpp b/src/agent/persistence/tests/sqlite_manager_test.cpp index a542bdd175..754d17d1ff 100644 --- a/src/agent/persistence/tests/sqlite_manager_test.cpp +++ b/src/agent/persistence/tests/sqlite_manager_test.cpp @@ -143,19 +143,6 @@ TEST_F(SQLiteManagerTest, GetSizeTest) EXPECT_EQ(size, 20); } -static void DumpResults(std::vector& ret) -{ - std::cout << "---------- " << ret.size() << " rows returned. ----------" << '\n'; - for (const auto& row : ret) - { - for (const auto& field : row) - { - std::cout << "[" << field.Name << ": " << field.Value << "]"; - } - std::cout << '\n'; - } -} - TEST_F(SQLiteManagerTest, SelectTest) { AddTestData(); @@ -165,7 +152,6 @@ TEST_F(SQLiteManagerTest, SelectTest) // all fields, no selection criteria std::vector ret = m_db->Select(m_tableName, cols); - DumpResults(ret); EXPECT_NE(ret.size(), 0); // all fields with default selection criteria @@ -174,7 +160,6 @@ TEST_F(SQLiteManagerTest, SelectTest) cols, {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Status", ColumnType::TEXT, "MyTestValue")}); - DumpResults(ret); EXPECT_NE(ret.size(), 0); // all fields with 'OR' selection criteria @@ -184,7 +169,6 @@ TEST_F(SQLiteManagerTest, SelectTest) {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Module", ColumnType::TEXT, "ItemModule5")}, LogicalOperator::OR); - DumpResults(ret); EXPECT_EQ(ret.size(), 2); // only Name field no selection criteria @@ -193,7 +177,6 @@ TEST_F(SQLiteManagerTest, SelectTest) ret.clear(); ret = m_db->Select(m_tableName, cols); - DumpResults(ret); EXPECT_NE(ret.size(), 0); // only Name field with default selection criteria @@ -205,7 +188,6 @@ TEST_F(SQLiteManagerTest, SelectTest) cols, {ColumnValue("Name", ColumnType::TEXT, "MyTestName"), ColumnValue("Status", ColumnType::TEXT, "MyTestValue")}); - DumpResults(ret); EXPECT_NE(ret.size(), 0); // only Name field with single selection criteria @@ -214,7 +196,6 @@ TEST_F(SQLiteManagerTest, SelectTest) ret.clear(); ret = m_db->Select(m_tableName, cols, {ColumnValue("Amount", ColumnType::REAL, "3.5")}); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); // only Name and Amount fields with single selection criteria @@ -224,7 +205,6 @@ TEST_F(SQLiteManagerTest, SelectTest) ret.clear(); ret = m_db->Select(m_tableName, cols, {ColumnValue("Amount", ColumnType::REAL, "2.8")}); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); // only Name field with ordered criteria @@ -234,7 +214,6 @@ TEST_F(SQLiteManagerTest, SelectTest) ret = m_db->Select( m_tableName, cols, {}, LogicalOperator::AND, {ColumnName("Name", ColumnType::TEXT)}, OrderType::DESC); - DumpResults(ret); EXPECT_EQ(ret.size(), 6); EXPECT_EQ(ret[0][0].Value, "MyTestName"); EXPECT_EQ(ret[1][0].Value, "ItemName5"); @@ -255,7 +234,6 @@ TEST_F(SQLiteManagerTest, SelectTest) {ColumnName("Amount", ColumnType::REAL)}, OrderType::DESC); - DumpResults(ret); EXPECT_EQ(ret.size(), 2); EXPECT_EQ(ret[0][0].Value, "ItemName5"); EXPECT_EQ(ret[0][1].Value, "3.5"); @@ -268,7 +246,6 @@ TEST_F(SQLiteManagerTest, SelectTest) ret.clear(); ret = m_db->Select(m_tableName, cols, {}, LogicalOperator::AND, {}, OrderType::ASC, 3); - DumpResults(ret); EXPECT_EQ(ret.size(), 3); // only Name ans Amount fields with selection criteria and limit criteria @@ -283,7 +260,6 @@ TEST_F(SQLiteManagerTest, SelectTest) OrderType::ASC, 1); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); // only Name ans Amount fields with selection criteria, ordered criteria and limit criteria @@ -299,7 +275,6 @@ TEST_F(SQLiteManagerTest, SelectTest) OrderType::DESC, 1); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); EXPECT_EQ(ret[0][0].Value, "ItemName5"); EXPECT_EQ(ret[0][1].Value, "3.5"); @@ -333,7 +308,6 @@ TEST_F(SQLiteManagerTest, UpdateTest) {ColumnValue("Name", ColumnType::TEXT, "MyTestName")})); auto ret = m_db->Select(m_tableName, {}, {ColumnValue("Name", ColumnType::TEXT, "Updated name")}); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); EXPECT_NO_THROW(m_db->Update(m_tableName, @@ -343,7 +317,6 @@ TEST_F(SQLiteManagerTest, UpdateTest) ColumnValue("Status", ColumnType::TEXT, "Updated status")})); ret = m_db->Select(m_tableName, {}, {ColumnValue("Name", ColumnType::TEXT, "Updated name2")}); - DumpResults(ret); EXPECT_EQ(ret.size(), 1); EXPECT_NO_THROW(m_db->Update(m_tableName, @@ -354,7 +327,6 @@ TEST_F(SQLiteManagerTest, UpdateTest) LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); - DumpResults(ret); EXPECT_NO_THROW(m_db->Update(m_tableName, {ColumnValue("Amount", ColumnType::REAL, "2.0")}, @@ -362,12 +334,10 @@ TEST_F(SQLiteManagerTest, UpdateTest) LogicalOperator::OR)); ret = m_db->Select(m_tableName, {}, {}); - DumpResults(ret); EXPECT_NO_THROW(m_db->Update(m_tableName, {ColumnValue("Amount", ColumnType::REAL, "2.0")}, {})); ret = m_db->Select(m_tableName, {}, {}); - DumpResults(ret); } TEST_F(SQLiteManagerTest, TransactionTest)