Skip to content

Commit

Permalink
Merge pull request #130 from Jacyking/master
Browse files Browse the repository at this point in the history
add query tuple & optional ut
  • Loading branch information
Jacyking authored Dec 13, 2023
2 parents 9f4d00c + 4093045 commit 899f2e6
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 6 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,37 @@ ormpp是modern c++(c++11/14/17)开发的ORM库,目前支持了三种数据库

你通过ormpp可以很容易地实现数据库的各种操作了,大部情况下甚至都不需要写sql语句。ormpp是基于编译期反射的,会帮你实现自动化的实体映射,你再也不用写对象到数据表相互赋值的繁琐易出错的代码了,更酷的是你可以很方便地切换数据库,如果需要从mysql切换到postgresql或sqlite只需要修改一下数据库类型就可以了,无需修改其他代码。

## 自增主键

使用REGISTER_AUTO_KEY注册自增主键

```C++
struct person {
std::string name;
int age;
int id;
};
REGISTER_AUTO_KEY(person, id)
REFLECTION(person, id, name, age)
```
## 冲突主键
使用REGISTER_CONFLICT_KEY注册冲突主键来进行update,如果未注册冲突主键则会采用自增主键
```C++
struct student {
int code;
std::string name;
char sex;
int age;
double dm;
std::string classroom;
};
REGISTER_CONFLICT_KEY(student, code)
REFLECTION(student, code, name, sex, age, dm, classroom)
```

## 快速示例

这个例子展示如何使用ormpp实现数据库的增删改查之类的操作,无需写sql语句。
Expand Down
32 changes: 32 additions & 0 deletions include/mysql.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,38 @@ class mysql {
},
std::make_index_sequence<SIZE>{});

for (auto &p : mp) {
p.second.assign(p.second.size(), 0);
}

index = 0;
iguana::for_each(
tp,
[&index, nulls, &tp](auto &t, auto /*i*/) {
using U = std::remove_reference_t<decltype(t)>;
if constexpr (iguana::is_reflection_v<U>) {
iguana::for_each(t, [&index, nulls, &t](auto ele, auto /*i*/) {
if (nulls.at(index++)) {
using W =
std::remove_reference_t<decltype(std::declval<U>().*ele)>;
if constexpr (is_optional_v<W>::value ||
std::is_arithmetic_v<W>) {
t.*ele = {};
}
}
});
}
else {
if (nulls.at(index++)) {
if constexpr (is_optional_v<U>::value ||
std::is_arithmetic_v<U>) {
t = {};
}
}
}
},
std::make_index_sequence<SIZE>{});

v.push_back(std::move(tp));
}

Expand Down
6 changes: 4 additions & 2 deletions include/postgresql.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class postgresql {
[this, i, &index](auto &item, auto I) {
if constexpr (iguana::is_reflection_v<decltype(item)>) {
std::remove_reference_t<decltype(item)> t = {};
iguana::for_each(t, [this, &index, &t](auto ele, auto i) {
iguana::for_each(t, [this, &index, &t, i](auto ele, auto /*i*/) {
assign(t.*ele, (int)i, index++);
});
item = std::move(t);
Expand All @@ -173,7 +173,9 @@ class postgresql {
}
},
std::make_index_sequence<SIZE>{});
v.push_back(std::move(tp));

if (index > 0)
v.push_back(std::move(tp));
}

return v;
Expand Down
2 changes: 0 additions & 2 deletions include/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ inline auto is_auto_key(std::string_view key, std::string_view value) {
inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = \
add_auto_key_field(#STRUCT_NAME, #KEY);

#ifdef ORMPP_ENABLE_PG
inline std::unordered_map<std::string_view, std::string_view>
g_ormpp_conflict_key_map;

Expand All @@ -50,7 +49,6 @@ inline auto get_conflict_key(std::string_view key) {
#define REGISTER_CONFLICT_KEY(STRUCT_NAME, ...) \
inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = \
add_conflict_key_field(#STRUCT_NAME, {MAKE_NAMES(__VA_ARGS__)});
#endif

template <typename T>
struct is_optional_v : std::false_type {};
Expand Down
100 changes: 98 additions & 2 deletions tests/test_ormpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ struct student {
double dm;
std::string classroom;
};
#ifdef ORMPP_ENABLE_PG
REGISTER_CONFLICT_KEY(student, code)
#endif
REFLECTION(student, code, name, sex, age, dm, classroom)

struct simple {
Expand Down Expand Up @@ -1113,6 +1111,104 @@ TEST_CASE("delete records") {
#endif
}

struct tuple_optional_t {
std::optional<std::string> name;
std::optional<int> age;
int id;
};
REGISTER_AUTO_KEY(tuple_optional_t, id)
REFLECTION(tuple_optional_t, id, name, age)

TEST_CASE("query tuple_optional_t") {
#ifdef ORMPP_ENABLE_MYSQL
dbng<mysql> mysql;
if (mysql.connect(ip, username, password, db)) {
mysql.create_datatable<tuple_optional_t>(ormpp_auto_key{"id"});
mysql.insert<tuple_optional_t>({"purecpp", 6});
mysql.insert<tuple_optional_t>({std::nullopt});
auto vec =
mysql.query<std::tuple<tuple_optional_t, std::optional<std::string>,
std::optional<int>>>(
"select id,name,age,name,age from tuple_optional_t;");
CHECK(vec.size() == 2);
auto tp1 = vec.front();
auto tp2 = vec.back();
auto p1 = std::get<0>(tp1);
auto p2 = std::get<0>(tp2);
auto n1 = std::get<1>(tp1);
auto n2 = std::get<1>(tp2);
auto a1 = std::get<2>(tp1);
auto a2 = std::get<2>(tp2);
CHECK(p1.name.value() == "purecpp");
CHECK(p1.age.value() == 6);
CHECK(p2.name.has_value() == false);
CHECK(p2.age.has_value() == false);
CHECK(n1.value() == "purecpp");
CHECK(n2.has_value() == false);
CHECK(a1.value() == 6);
CHECK(a2.has_value() == false);
}
#endif
#ifdef ORMPP_ENABLE_PG
dbng<postgresql> postgres;
if (postgres.connect(ip, username, password, db)) {
postgres.create_datatable<tuple_optional_t>(ormpp_auto_key{"id"});
postgres.insert<tuple_optional_t>({"purecpp", 6});
postgres.insert<tuple_optional_t>({std::nullopt});
auto vec =
postgres.query<std::tuple<tuple_optional_t, std::optional<std::string>,
std::optional<int>>>(
"select id,name,age,name,age from tuple_optional_t;");
CHECK(vec.size() == 2);
auto tp1 = vec.front();
auto tp2 = vec.back();
auto p1 = std::get<0>(tp1);
auto p2 = std::get<0>(tp2);
auto n1 = std::get<1>(tp1);
auto n2 = std::get<1>(tp2);
auto a1 = std::get<2>(tp1);
auto a2 = std::get<2>(tp2);
CHECK(p1.name.value() == "purecpp");
CHECK(p1.age.value() == 6);
CHECK(p2.name.has_value() == false);
CHECK(p2.age.has_value() == false);
CHECK(n1.value() == "purecpp");
CHECK(n2.has_value() == false);
CHECK(a1.value() == 6);
CHECK(a2.has_value() == false);
}
#endif
#ifdef ORMPP_ENABLE_SQLITE3
dbng<sqlite> sqlite;
if (sqlite.connect(db)) {
sqlite.create_datatable<tuple_optional_t>(ormpp_auto_key{"id"});
sqlite.insert<tuple_optional_t>({"purecpp", 6});
sqlite.insert<tuple_optional_t>({std::nullopt});
auto vec =
sqlite.query<std::tuple<tuple_optional_t, std::optional<std::string>,
std::optional<int>>>(
"select id,name,age,name,age from tuple_optional_t;");
CHECK(vec.size() == 2);
auto tp1 = vec.front();
auto tp2 = vec.back();
auto p1 = std::get<0>(tp1);
auto p2 = std::get<0>(tp2);
auto n1 = std::get<1>(tp1);
auto n2 = std::get<1>(tp2);
auto a1 = std::get<2>(tp1);
auto a2 = std::get<2>(tp2);
CHECK(p1.name.value() == "purecpp");
CHECK(p1.age.value() == 6);
CHECK(p2.name.has_value() == false);
CHECK(p2.age.has_value() == false);
CHECK(n1.value() == "purecpp");
CHECK(n2.has_value() == false);
CHECK(a1.value() == 6);
CHECK(a2.has_value() == false);
}
#endif
}

struct alias {
std::string name;
int id;
Expand Down

0 comments on commit 899f2e6

Please sign in to comment.