Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add query tuple & optional ut #130

Merged
merged 4 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading