SkillAgentSearch skills...

Ormpp

modern C++ ORM, C++17, support mysql, postgresql,sqlite

Install / Use

/learn @qicosmos/Ormpp
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<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主要有以下几个特点:

  1. header only
  2. cross platform
  3. unified interface
  4. easy to use
  5. easy to change database
  6. 支持安全的链式调用

你通过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))
      
View on GitHub
GitHub Stars1.5k
CategoryData
Updated2d ago
Forks296

Languages

C++

Security Score

95/100

Audited on Mar 26, 2026

No findings