diff --git a/README.md b/README.md index c9e3984..89dcba6 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,13 @@ struct ObjectModel // other way to define id column - will be over writen by using id_columns // int id; - // defining table_name is optional + // defining table_name is optional, adding it will overwrite default table name inline static const std::string table_name = "object_model"; + + // defining columns_names is optional, adding it will overwrite default columns names + // not all columns have to be defined, others will get default names + inline static const std::map columns_names = {{"field1", "some_field1_name"}, + {"field2", "some_field2_name"}}; }; int main() diff --git a/examples/main.cpp b/examples/main.cpp index d052065..17b1055 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -16,8 +16,13 @@ struct ObjectModel // other way to define id column - will be over writen by using id_columns // int id; - // defining table_name is optional + // defining table_name is optional, adding it will overwrite default table name inline static const std::string table_name = "object_model"; + + // defining columns_names is optional, adding it will overwrite default columns names + // not all columns have to be defined, others will get default names + inline static const std::map columns_names = {{"field1", "some_field1_name"}, + {"field2", "some_field2_name"}}; }; int main() diff --git a/include/orm-cxx/model/ColumnInfo.hpp b/include/orm-cxx/model/ColumnInfo.hpp index c390fa0..6119f73 100644 --- a/include/orm-cxx/model/ColumnInfo.hpp +++ b/include/orm-cxx/model/ColumnInfo.hpp @@ -7,6 +7,7 @@ #include #include "ColumnType.hpp" +#include "NameMapping.hpp" namespace orm::model { @@ -31,13 +32,13 @@ auto getColumnsInfo(const std::unordered_set& ids = {}) -> std::vec { ColumnInfo columnInfo{}; - columnInfo.name = field.name(); + columnInfo.name = getColumnName(field.name()); auto [type, isNotNull] = toColumnType(field.type()); columnInfo.type = type; columnInfo.isNotNull = isNotNull; - if (ids.contains(field.name())) + if (ids.contains(columnInfo.name)) { columnInfo.isPrimaryKey = true; } diff --git a/include/orm-cxx/model/IdInfo.hpp b/include/orm-cxx/model/IdInfo.hpp index 3bdf25f..784c86c 100644 --- a/include/orm-cxx/model/IdInfo.hpp +++ b/include/orm-cxx/model/IdInfo.hpp @@ -3,6 +3,8 @@ #include #include +#include "NameMapping.hpp" + namespace orm::model { template @@ -10,11 +12,18 @@ auto getIdColumnsNames() -> std::unordered_set { if constexpr (requires { T::id_columns; }) { - return {T::id_columns.begin(), T::id_columns.end()}; + std::unordered_set ids{}; + + for (const auto& id : T::id_columns) + { + ids.insert(getColumnName(id)); + } + + return ids; } else if constexpr (requires(T t) { t.id; }) { - return {"id"}; + return {getColumnName("id")}; } else { diff --git a/include/orm-cxx/model/NameMapping.hpp b/include/orm-cxx/model/NameMapping.hpp new file mode 100644 index 0000000..e30b0ca --- /dev/null +++ b/include/orm-cxx/model/NameMapping.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +namespace orm::model +{ +template +auto getColumnsNamesMapping() -> std::unordered_map +{ + if constexpr (requires { + T::columns_names; + T::columns_names.contains(std::string{}); + T::columns_names.at(std::string{}); + }) + { + return {T::columns_names.begin(), T::columns_names.end()}; + } + else + { + return {}; + } +} + +template +auto getColumnName(const std::string& name) -> const std::string& +{ + static auto mapping = getColumnsNamesMapping(); + + if (mapping.contains(name)) + { + return mapping.at(name); + } + + return name; +} +} \ No newline at end of file diff --git a/tests/DatabaseTest.cpp b/tests/DatabaseTest.cpp index 1e26967..daad50d 100644 --- a/tests/DatabaseTest.cpp +++ b/tests/DatabaseTest.cpp @@ -49,6 +49,15 @@ struct ModelWithOverwrittenId inline static const std::vector id_columns = {"field1", "field2"}; }; +struct ModelWithIdAndNamesMapping +{ + int id; + int field1; + std::string field2; + + inline static const std::map columns_names = { + {"field1", "some_field1_name"}, {"field2", "some_field2_name"}, {"id", "some_id_name"}}; +}; template auto generateSomeDataModels(int count) -> std::vector @@ -204,3 +213,21 @@ TEST_F(DatabaseTest, shouldCreateTableWithOverwrittenIdColumn) database.deleteTable(); } + +TEST_F(DatabaseTest, shouldExecuteInsertQueryAndSelectQueryWithNamesMapping_valuesShouldBeSame) +{ + database.connect(connectionString); + database.createTable(); + auto models = std::vector{{1, 1, "test"}, {2, 2, "test2"}}; + database.insertObjects(models); + orm::Query queryForNamesMapping; + auto returnedModels = database.executeQuery(queryForNamesMapping); + + for (std::size_t i = 0; i < models.size(); i++) + { + EXPECT_EQ(models[i].field1, returnedModels[i].field1); + EXPECT_EQ(models[i].field2, returnedModels[i].field2); + } + + database.deleteTable(); +} \ No newline at end of file diff --git a/tests/ModelTest.cpp b/tests/ModelTest.cpp index c93cea6..92147f7 100644 --- a/tests/ModelTest.cpp +++ b/tests/ModelTest.cpp @@ -38,6 +38,25 @@ struct StructWithIdColumns int field2; }; +struct StructWithNamesMapping +{ + int field1; + int field2; + + inline static const std::map columns_names = {{"field1", "some_field1_name"}, + {"field2", "some_field2_name"}}; +}; + +struct StructWithIdAndNamesMapping +{ + int id; + int field1; + int field2; + + inline static const std::map columns_names = { + {"field1", "some_field1_name"}, {"field2", "some_field2_name"}, {"id", "some_id_name"}}; +}; + TEST(ModelTest, OneFieldStruct_shouldHaveOneColumn) { orm::Model model; @@ -102,4 +121,28 @@ TEST(ModelTest, StructWithIdColumns_shouldHaveTwoIdColumns) EXPECT_EQ(model.getModelInfo().columnsInfo[3].isPrimaryKey, false); EXPECT_TRUE(model.getModelInfo().idColumnsNames.contains("id1")); EXPECT_TRUE(model.getModelInfo().idColumnsNames.contains("id2")); +} + +TEST(ModelTest, StructWithNamesMapping_shouldHaveTwoColumnsWithNamesFromMapping) +{ + orm::Model model; + + EXPECT_EQ(model.getModelInfo().columnsInfo.size(), 2); + EXPECT_EQ(model.getModelInfo().columnsInfo[0].name, "some_field1_name"); + EXPECT_EQ(model.getModelInfo().columnsInfo[1].name, "some_field2_name"); + EXPECT_TRUE(model.getModelInfo().idColumnsNames.empty()); +} + +TEST(ModelTest, StructWithIdAndNamesMapping_shouldHaveTwoColumnsWithNamesFromMappingAndOneIdColumn) +{ + orm::Model model; + + EXPECT_EQ(model.getModelInfo().columnsInfo.size(), 3); + EXPECT_EQ(model.getModelInfo().columnsInfo[0].name, "some_id_name"); + EXPECT_EQ(model.getModelInfo().columnsInfo[0].isPrimaryKey, true); + EXPECT_EQ(model.getModelInfo().columnsInfo[1].name, "some_field1_name"); + EXPECT_EQ(model.getModelInfo().columnsInfo[1].isPrimaryKey, false); + EXPECT_EQ(model.getModelInfo().columnsInfo[2].name, "some_field2_name"); + EXPECT_EQ(model.getModelInfo().columnsInfo[2].isPrimaryKey, false); + EXPECT_TRUE(model.getModelInfo().idColumnsNames.contains("some_id_name")); } \ No newline at end of file