Hiberlite
Hiberliteは「C++向けのSQLite ORM」として開発された、信頼性の高いデータストレージとACIDトランザクション、シンプルなランダムアクセスを必要とし、SQL でのコーディングを好まない開発者のためのライブラリです。従来のSQLシリアライザーとは異なり、HiberliteでマップされたC++オブジェクトはActive Recordパターンのように振る舞い、「全データを読み取り/一部を変更/全てを書き戻し」という制約から解放されます。Boost.SerializationにインスパイアされたAPIにより、学習するAPIがほとんどなく直感的な使用が可能です。
GitHub概要
トピックス
スター履歴
ライブラリ
Hiberlite
概要
Hiberliteは「C++向けのSQLite ORM」として開発された、信頼性の高いデータストレージとACIDトランザクション、シンプルなランダムアクセスを必要とし、SQL でのコーディングを好まない開発者のためのライブラリです。従来のSQLシリアライザーとは異なり、HiberliteでマップされたC++オブジェクトはActive Recordパターンのように振る舞い、「全データを読み取り/一部を変更/全てを書き戻し」という制約から解放されます。Boost.SerializationにインスパイアされたAPIにより、学習するAPIがほとんどなく直感的な使用が可能です。
詳細
Hiberlite 2025年版はC++ SQLite ORMの軽量ソリューションとして、自動スキーマ生成、スマートポインタ管理、内部主キー自動生成など現代的なC++開発に必要な機能を提供しています。データベーススキーマは単純にデータベースに格納されるクラスのセットとして定義され、Hiberliteが必要なテーブルとカラムを決定します。bean_ptrスマートポインタはboost::shared_ptrにインスパイアされ、参照されなくなったオブジェクトの自動保存を保証します。Active Recordパターンによりオブジェクト操作が直感的で、複雑なリレーションシップ処理も簡素化されています。
主な特徴
- Active Recordパターン: オブジェクトがデータベース操作を直接実行
- 自動スキーマ生成: クラス定義からテーブル構造を自動推論
- スマートポインタ: bean_ptrによる自動メモリ・永続化管理
- 内部主キー自動生成: 各オブジェクトに対する透明な主キー管理
- SQLシリアライゼーション: Boost.SerializationライクなシンプルなAPI
- 依存関係フリー: サードパーティライブラリに依存しない軽量設計
メリット・デメリット
メリット
- 学習コストが非常に低く、APIがシンプルで直感的
- Boost.Serializationに馴染みがある開発者には習得が容易
- Active Recordパターンによりオブジェクト指向的な操作が可能
- 設定ファイルやXMLが不要で、アノテーションも最小限
- 軽量でサードパーティ依存関係がない
- 自動スキーマ管理によりDDL操作が不要
デメリット
- 大規模なプロジェクトではスケーラビリティに制約がある
- データのサブセット取得方法が不明瞭で、標準的でない可能性
- 完全に成熟していない可能性があり、プロダクションレディか要検証
- 複雑なクエリやパフォーマンス最適化には制限がある
- コミュニティとドキュメントが限定的
- 現代的なC++機能(C++14以降)への対応が不明
参考ページ
書き方の例
セットアップ
# GitHubからクローン
git clone https://github.com/paulftw/hiberlite.git
# プロジェクトに統合(src/以下の全ファイルをコンパイル・リンク)
# CMakeLists.txt例
add_subdirectory(hiberlite)
target_link_libraries(your_project hiberlite sqlite3)
// 基本インクルード
#include "hiberlite.h"
基本的な使い方
// クラスの準備
class MyClass {
friend class hiberlite::access;
template<class Archive>
void hibernate(Archive & ar) {
ar & HIBERLITE_NVP(a);
ar & HIBERLITE_NVP(b);
ar & HIBERLITE_NVP(vs);
}
public:
int a;
double b;
std::vector<std::string> vs;
MyClass() : a(0), b(0.0) {}
MyClass(int a_val, double b_val) : a(a_val), b(b_val) {}
};
// クラスのエクスポート(必須)
HIBERLITE_EXPORT_CLASS(MyClass)
// より複雑なクラス例
class Person {
friend class hiberlite::access;
template<class Archive>
void hibernate(Archive & ar) {
ar & HIBERLITE_NVP(name);
ar & HIBERLITE_NVP(age);
ar & HIBERLITE_NVP(email);
ar & HIBERLITE_NVP(addresses);
}
public:
std::string name;
int age;
std::string email;
std::vector<std::string> addresses;
Person() : age(0) {}
Person(const std::string& n, int a, const std::string& e)
: name(n), age(a), email(e) {}
};
HIBERLITE_EXPORT_CLASS(Person)
クエリ実行
#include <iostream>
// データベースの初期化と使用
void demonstrateBasicUsage() {
// データベース初期化
hiberlite::Database db("example.db");
db.registerBeanClass<MyClass>();
db.registerBeanClass<Person>();
// オブジェクトの作成と保存(方法1: copyBean)
MyClass x;
x.a = 42;
x.b = 3.14159;
x.vs.push_back("hello");
x.vs.push_back("world");
hiberlite::bean_ptr<MyClass> p1 = db.copyBean(x);
std::cout << "Saved MyClass with ID: " << p1.get_id() << std::endl;
// オブジェクトの作成と保存(方法2: createBean)
hiberlite::bean_ptr<Person> person = db.createBean<Person>();
person->name = "田中太郎";
person->age = 30;
person->email = "[email protected]";
person->addresses.push_back("東京都渋谷区");
person->addresses.push_back("大阪府大阪市");
std::cout << "Saved Person with ID: " << person.get_id() << std::endl;
}
// より複雑な使用例
void demonstrateAdvancedUsage() {
hiberlite::Database db("advanced.db");
db.registerBeanClass<Person>();
// 複数オブジェクトの作成
std::vector<hiberlite::bean_ptr<Person>> people;
for (int i = 0; i < 5; ++i) {
hiberlite::bean_ptr<Person> p = db.createBean<Person>();
p->name = "Person" + std::to_string(i);
p->age = 20 + i * 5;
p->email = "person" + std::to_string(i) + "@example.com";
p->addresses.push_back("Address " + std::to_string(i));
people.push_back(p);
}
std::cout << "Created " << people.size() << " people" << std::endl;
// オブジェクトの変更(自動保存)
people[0]->age = 99;
people[0]->email = "[email protected]";
// bean_ptrのスコープから外れると自動的にデータベースに保存される
}
データ操作
// 複雑なデータ構造の例
class UserAccount {
friend class hiberlite::access;
template<class Archive>
void hibernate(Archive & ar) {
ar & HIBERLITE_NVP(username);
ar & HIBERLITE_NVP(password_hash);
ar & HIBERLITE_NVP(profile);
ar & HIBERLITE_NVP(settings);
ar & HIBERLITE_NVP(friends);
}
public:
std::string username;
std::string password_hash;
std::map<std::string, std::string> profile;
std::map<std::string, bool> settings;
std::vector<std::string> friends;
UserAccount() {}
UserAccount(const std::string& user) : username(user) {}
};
HIBERLITE_EXPORT_CLASS(UserAccount)
// 使用例
void demonstrateComplexData() {
hiberlite::Database db("users.db");
db.registerBeanClass<UserAccount>();
// ユーザーアカウントの作成
hiberlite::bean_ptr<UserAccount> user = db.createBean<UserAccount>();
user->username = "testuser";
user->password_hash = "hashed_password_123";
// プロフィール情報の設定
user->profile["first_name"] = "太郎";
user->profile["last_name"] = "田中";
user->profile["bio"] = "ソフトウェア開発者";
user->profile["location"] = "東京";
// 設定の管理
user->settings["email_notifications"] = true;
user->settings["dark_mode"] = false;
user->settings["auto_save"] = true;
// フレンドリストの管理
user->friends.push_back("friend1");
user->friends.push_back("friend2");
user->friends.push_back("friend3");
std::cout << "User " << user->username << " created with "
<< user->friends.size() << " friends" << std::endl;
}
設定とカスタマイズ
// 高度なクラス設計の例
class BlogPost {
friend class hiberlite::access;
template<class Archive>
void hibernate(Archive & ar) {
ar & HIBERLITE_NVP(title);
ar & HIBERLITE_NVP(content);
ar & HIBERLITE_NVP(author);
ar & HIBERLITE_NVP(tags);
ar & HIBERLITE_NVP(created_at);
ar & HIBERLITE_NVP(updated_at);
ar & HIBERLITE_NVP(published);
ar & HIBERLITE_NVP(view_count);
}
public:
std::string title;
std::string content;
std::string author;
std::vector<std::string> tags;
std::string created_at; // 簡易的にstring使用
std::string updated_at;
bool published;
int view_count;
BlogPost() : published(false), view_count(0) {
// 現在時刻を設定(簡易版)
created_at = "2025-01-01 00:00:00";
updated_at = created_at;
}
void updateContent(const std::string& new_content) {
content = new_content;
updated_at = "2025-01-01 12:00:00"; // 実際は現在時刻
}
void addTag(const std::string& tag) {
tags.push_back(tag);
}
void publish() {
published = true;
updated_at = "2025-01-01 15:00:00";
}
void incrementView() {
view_count++;
}
};
HIBERLITE_EXPORT_CLASS(BlogPost)
// ブログシステムの実装例
class BlogManager {
private:
hiberlite::Database db;
public:
BlogManager(const std::string& db_path) : db(db_path) {
db.registerBeanClass<BlogPost>();
db.registerBeanClass<UserAccount>();
}
hiberlite::bean_ptr<BlogPost> createPost(const std::string& title,
const std::string& content,
const std::string& author) {
hiberlite::bean_ptr<BlogPost> post = db.createBean<BlogPost>();
post->title = title;
post->content = content;
post->author = author;
return post;
}
void publishPost(hiberlite::bean_ptr<BlogPost> post) {
post->publish();
// bean_ptrによる自動保存
}
void viewPost(hiberlite::bean_ptr<BlogPost> post) {
post->incrementView();
// 変更は自動的に保存される
}
};
エラーハンドリング
#include <stdexcept>
// エラーハンドリングの例
class SafeDatabaseManager {
private:
std::unique_ptr<hiberlite::Database> db;
bool initialized;
public:
SafeDatabaseManager() : initialized(false) {}
bool initialize(const std::string& db_path) {
try {
db = std::make_unique<hiberlite::Database>(db_path);
db->registerBeanClass<Person>();
db->registerBeanClass<BlogPost>();
initialized = true;
return true;
} catch (const std::exception& e) {
std::cerr << "Database initialization failed: " << e.what() << std::endl;
initialized = false;
return false;
}
}
template<typename T>
hiberlite::bean_ptr<T> safeCreateBean() {
if (!initialized) {
throw std::runtime_error("Database not initialized");
}
try {
return db->createBean<T>();
} catch (const std::exception& e) {
std::cerr << "Failed to create bean: " << e.what() << std::endl;
throw;
}
}
template<typename T>
hiberlite::bean_ptr<T> safeCopyBean(const T& object) {
if (!initialized) {
throw std::runtime_error("Database not initialized");
}
try {
return db->copyBean(object);
} catch (const std::exception& e) {
std::cerr << "Failed to copy bean: " << e.what() << std::endl;
throw;
}
}
bool isInitialized() const {
return initialized;
}
};
// 安全な使用例
void safeDatabaseUsage() {
SafeDatabaseManager manager;
if (!manager.initialize("safe_example.db")) {
std::cerr << "Failed to initialize database" << std::endl;
return;
}
try {
// 安全なオブジェクト作成
auto person = manager.safeCreateBean<Person>();
person->name = "Safe User";
person->age = 25;
person->email = "[email protected]";
std::cout << "Safely created person with ID: " << person.get_id() << std::endl;
// 複製による保存
Person temp_person("Copy User", 35, "[email protected]");
auto copied_person = manager.safeCopyBean(temp_person);
std::cout << "Safely copied person with ID: " << copied_person.get_id() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Operation failed: " << e.what() << std::endl;
}
}