Ormpp
modern C++ ORM, C++17, support mysql, postgresql,sqlite
Install / Use
/learn @qicosmos/OrmppREADME
<p align="center">
<a href="https://github.com/qicosmos/ormpp/actions/workflows/ci-sqlite.yml">
<img alt="ci-sqlite" src="https://github.com/qicosmos/ormpp/actions/workflows/ci-sqlite.yml/badge.svg?branch=master">
</a>
<a href="https://github.com/qicosmos/ormpp/actions/workflows/ci-mysql.yml">
<img alt="ci-mysql" src="https://github.com/qicosmos/ormpp/actions/workflows/ci-mysql.yml/badge.svg?branch=master">
</a>
<a href="https://github.com/qicosmos/ormpp/actions/workflows/ci-pgsql.yml">
<img alt="ci-pgsql" src="https://github.com/qicosmos/ormpp/actions/workflows/ci-pgsql.yml/badge.svg?branch=master">
</a>
<a href="https://codecov.io/gh/qicosmos/ormpp">
<img alt="codecov" src="https://codecov.io/gh/qicosmos/ormpp/branch/master/graph/badge.svg">
</a>
<img alt="language" src="https://img.shields.io/github/languages/top/qicosmos/ormpp?style=flat-square">
<img alt="last commit" src="https://img.shields.io/github/last-commit/qicosmos/ormpp?style=flat-square">
</p>
<p align="center">
<a href="https://github.com/qicosmos/ormpp/tree/master/lang/english/README.md">English</a> | <span>中文</span>
</p>
一个很酷的Modern C++ ORM库----ormpp
iguana版本1.0.9 https://github.com/qicosmos/iguana.git
谁在用ormpp, 也希望ormpp用户帮助编辑用户列表,也是为了让更多用户把ormpp用起来,也是对ormpp 最大的支持,用户列表的用户问题会优先处理。
目录
ormpp的目标
ormpp最重要的目标就是让c++中的数据库编程变得简单,为用户提供统一的接口,支持多种数据库,降低用户使用数据库的难度。
ormpp的特点
ormpp是modern c++(c++11/14/17)开发的ORM库,目前支持了三种数据库:mysql, postgresql和sqlite,ormpp主要有以下几个特点:
- header only
- cross platform
- unified interface
- easy to use
- easy to change database
- 支持安全的链式调用
你通过ormpp可以很容易地实现数据库的各种操作了,大部情况下甚至都不需要写sql语句。ormpp是基于编译期反射的,会帮你实现自动化的实体映射,你再也不用写对象到数据表相互赋值的繁琐易出错的代码了,更酷的是你可以很方便地切换数据库,如果需要从mysql切换到postgresql或sqlite只需要修改一下数据库类型就可以了,无需修改其他代码。
自增主键
使用REGISTER_AUTO_KEY注册自增主键
struct person {
std::string name;
int age;
int id;
};
REGISTER_AUTO_KEY(person, id)
冲突主键
使用REGISTER_CONFLICT_KEY注册冲突主键来进行update,如果未注册冲突主键则会采用自增主键
struct student {
int code;
std::string name;
char sex;
int age;
double dm;
std::string classroom;
};
REGISTER_CONFLICT_KEY(student, code)
快速示例
链式调用
简单查询
auto l = sqlite.select(all).from<test_optional>().collect();
auto l1 =
sqlite.select(col(&test_optional::id), col(&test_optional::name))
.from<test_optional>()
.collect();
auto l2 = sqlite.select(all)
.from<test_optional>()
.where(col(&test_optional::id).in(1, 2))
.order_by(col(&test_optional::id).desc(),
col(&test_optional::name).desc())
.limit(5)
.offset(0)
.collect();
绑定参数
// 调用param() 意味着它是一个占位符'?', 调用collect(2) 意味着绑定对应的参数
auto l0 = sqlite.select(all)
.from<test_optional>()
.where(col(&test_optional::id).param())
.collect(2);
auto l = sqlite.select(all)
.from<test_optional>()
.where(col(&test_optional::name).param())
.collect(std::string("test"));
CHECK(l0.size() == 1);
CHECK(l.size() == 1);
简单聚合查询
auto l = sqlite.select(count()).from<test_optional>().collect();
auto l2 = sqlite.select(count(col(&test_optional::id)))
.from<test_optional>()
.collect();
auto l3 = sqlite.select(count_distinct(col(&test_optional::id)))
.from<test_optional>()
.collect();
CHECK(l == 2);
CHECK(l2 == 2);
CHECK(l3 == 2);
auto l4 = sqlite.select(sum(col(&test_optional::id)))
.from<test_optional>()
.collect();
auto l5 = sqlite.select(avg(col(&test_optional::id)))
.from<test_optional>()
.collect();
auto l6 = sqlite.select(min(col(&test_optional::id)))
.from<test_optional>()
.collect();
auto l7 = sqlite.select(max(col(&test_optional::id)))
.from<test_optional>()
.collect();
聚合加group by查询
auto l =
sqlite.select(count(col(&test_optional::id)), col(&test_optional::id))
.from<test_optional>()
.group_by(col(&test_optional::id))
.collect();
auto l1 =
sqlite.select(sum(col(&test_optional::id)), col(&test_optional::id))
.from<test_optional>()
.group_by(col(&test_optional::id))
.collect();
auto l2 =
sqlite.select(sum(col(&test_optional::id)), col(&test_optional::id))
.from<test_optional>()
.group_by(col(&test_optional::id))
.collect();
auto l3 =
sqlite.select(sum(col(&test_optional::id)), col(&test_optional::id))
.from<test_optional>()
.where(col(&test_optional::id) > 0)
.group_by(col(&test_optional::id))
.collect();
auto l4 =
sqlite.select(sum(col(&test_optional::age)), col(&test_optional::id))
.from<test_optional>()
.where(col(&test_optional::id) > 0)
.group_by(col(&test_optional::id))
.having(sum(col(&test_optional::age)) > 0 && count() > 0)
.collect();
join 查询
auto l2 = sqlite.select(col(&test_optional::name), col(&person::name))
.from<test_optional>()
.inner_join(col(&test_optional::id), col(&person::id))
.where(col(&person::id) > 0 || col(&person::id) == 1)
.collect();
/*
std::string sql =
"select a.title, a.content, u.user_name as author_name, t.name as "
"tag_name, a.created_at, a.updated_at, a.views_count, a.comments_count "
"from articles a INNER JOIN users u ON a.author_id = u.id INNER JOIN "
"tags t ON a.tag_id = t.tag_id WHERE a.slug = ? and a.is_deleted=0;";
*/
auto results =
conn->select(col(&articles_t::title), col(&articles_t::content),
col(&users_t::user_name), col(&tags_t::name),
col(&articles_t::created_at), col(&articles_t::updated_at),
col(&articles_t::views_count),
col(&articles_t::comments_count))
.from<articles_t>()
.inner_join(col(&articles_t::author_id), col(&users_t::id))
.inner_join(col(&articles_t::tag_id), col(&tags_t::tag_id))
.where(col(&articles_t::slug) == slug &&
col(&articles_t::is_deleted) == 0).collect();
这个例子展示如何使用ormpp实现数据库的增删改查之类的操作,无需写sql语句。
#include "dbng.hpp"
#include "mysql.hpp"//注意,使用什么数据库时就需要include对应的hpp文件,里面是对相关函数的反射封装
//#include "sqlite.hpp" //例如使用sqlite时,则包含sqlite.hpp
using namespace ormpp;
struct person {
std::optional<int> age; // 可以插入null值
std::string name;
int id;
static constexpr auto get_alias_field_names(alias *) {
return std::array{ylt::reflection::field_alias_t{"person_id", 0},
ylt::reflection::field_alias_t{"person_name", 1},
ylt::reflection::field_alias_t{"person_age", 2}}; // 注意: 这里需与YLT_REFL的注册顺序一致
}
static constexpr std::string_view get_alias_struct_name(student *) {
return "CUSTOM_TABLE_NAME"; // 表名默认结构体名字(person), 这里可以修改表名
}
};
REGISTER_AUTO_KEY(person, id)
REGISTER_CONFLICT_KEY(person, name)
// REGISTER_CONFLICT_KEY(person, name, age) // 如果是多个
int main() {
person p = {"test1", 2};
person p1 = {"test2", 3};
person p2 = {"test3", 4};
std::vector<person> v{p1, p2};
dbng<mysql> mysql;
mysql.connect("127.0.0.1", "dbuser", "yourpwd", "testdb");
mysql.create_datatable<person>(ormpp_auto_key{"id"});
// 插入数据
mysql.insert(p);
mysql.insert(v);
// 查询数据(id=1)
auto result = mysql.query_s<person>("id=?", 1);
// 获取插入后的自增id
auto id1 = mysql.get_insert_id_after_insert<person>(p);
auto id2 = mysql.get_insert_id_after_insert<person>(v);
// 更新数据
mysql.update(p);
mysql.update(v);
mysql.update(p, "id=1");
// 替换数据
mysql.replace(p);
mysql.replace(v);
// 更新指定字段
// mysql.update_some<&person::name, &person::age>(p);
// mysql.update_some<&person::name, &person::age>(v);
auto result = mysql.query_s<person>();
for (auto &person : result) {
std::cout << person.id << " " << person.name << " " << person.age
<< std::endl;
}
mysql.delete_records<person>();
// transaction
mysql.begin();
for (int i = 0; i < 10; ++i) {
person s = {"tom", 19};
if (!mysql.insert(s)) {
mysql.rollback();
return -1;
}
}
mysql.commit();
return 0;
}
enum class Color { BLUE = 10, RED = 15 };
enum Fruit { APPLE, BANANA };
struct test_enum_t {
Color color;
Fruit fruit;
int id;
};
REGISTER_AUTO_KEY(test_enum_t, id)
int main() {
dbng<sqlite> sqlite;
sqlite.connect(db);//或者开启sqcipher后sqlite.connect(db, password);
sqlite.execute("drop table if exists test_enum_t");
sqlite.create_datatable<test_enum_t>(ormpp_auto_key{"id"});
sqlite.insert<test_enum_t>({Color::BLUE});
auto vec1 = sqlite.query<test_enum_t>();
vec1.front().color = Color::RED;
sqlite.update(vec1.front());
auto vec2 = sqlite.query<test_enum_t>();
sqlite.update<test_enum_t>({Color::BLUE, BANANA, 1}, "id=1");
auto vec3 = sqlite.query<test_enum_t>();
vec3.front().color = Color::RED;
sqlite.replace(vec3.front());
auto vec4 = sqlite.query<test_enum_t>();
sqlite.delete_records<test_enum_t>();
auto vec5 = sqlite.query<test_enum_t>();
return 0;
}
新增了4个链式调用接口
新增接口:
- create_table<T>()
- update<T>()
- remove<T>()
- alter_table<T>()
例子:
struct builder_person {
std::string name;
int age;
int id;
int score;
};
sqlite.create_table<builder_person>()
.auto_increment(col(&builder_person::id))
.not_null(col(&builder_person::name), col(&builder_person::age))
