Hiberlite
Hiberlite is "a C++ ORM for SQLite" developed for developers who need reliable data storage, ACID transactions, simple random access to their data files, and don't like coding in SQL. Unlike traditional serialization libraries with SQL serializers, C++ objects mapped with Hiberlite behave similar to the Active Record pattern, freeing you from the "read all your data/modify some small part/write everything back" constraint. With an API inspired by Boost.Serialization, there's almost no API to learn, making it intuitive to use.
GitHub Overview
Topics
Star History
Library
Hiberlite
Overview
Hiberlite is "a C++ ORM for SQLite" developed for developers who need reliable data storage, ACID transactions, simple random access to their data files, and don't like coding in SQL. Unlike traditional serialization libraries with SQL serializers, C++ objects mapped with Hiberlite behave similar to the Active Record pattern, freeing you from the "read all your data/modify some small part/write everything back" constraint. With an API inspired by Boost.Serialization, there's almost no API to learn, making it intuitive to use.
Details
Hiberlite 2025 edition provides necessary features for modern C++ development as a lightweight solution for C++ SQLite ORM, including automatic schema generation, smart pointer management, and automatic internal primary key generation. Database schemas are simply defined as a set of classes stored in the database, with Hiberlite determining the needed tables and their columns. The bean_ptr smart pointer is inspired by boost::shared_ptr and guarantees that referenced objects will be automatically saved to the database when no longer needed. The Active Record pattern makes object manipulation intuitive and simplifies complex relationship handling.
Key Features
- Active Record Pattern: Objects directly execute database operations
- Automatic Schema Generation: Automatic inference of table structure from class definitions
- Smart Pointers: Automatic memory and persistence management through bean_ptr
- Automatic Internal Primary Key Generation: Transparent primary key management for each object
- SQL Serialization: Simple API similar to Boost.Serialization
- Dependency-Free: Lightweight design with no third-party library dependencies
Pros and Cons
Pros
- Very low learning cost with simple and intuitive API
- Easy to learn for developers familiar with Boost.Serialization
- Object-oriented operations possible through Active Record pattern
- No configuration files or XML required, minimal annotations
- Lightweight with no third-party dependencies
- No DDL operations needed due to automatic schema management
Cons
- Scalability constraints in large projects
- Unclear method for retrieving data subsets, potentially non-standard
- May not be fully mature, production readiness requires verification
- Limited complex queries and performance optimization capabilities
- Limited community and documentation
- Unclear support for modern C++ features (C++14 and later)
Reference Pages
Code Examples
Setup
# Clone from GitHub
git clone https://github.com/paulftw/hiberlite.git
# Integrate into project (compile and link all files under src/)
# CMakeLists.txt example
add_subdirectory(hiberlite)
target_link_libraries(your_project hiberlite sqlite3)
// Basic include
#include "hiberlite.h"
Basic Usage
// Class preparation
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) {}
};
// Class export (required)
HIBERLITE_EXPORT_CLASS(MyClass)
// More complex class example
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)
Query Execution
#include <iostream>
// Database initialization and usage
void demonstrateBasicUsage() {
// Database initialization
hiberlite::Database db("example.db");
db.registerBeanClass<MyClass>();
db.registerBeanClass<Person>();
// Object creation and saving (Method 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;
// Object creation and saving (Method 2: createBean)
hiberlite::bean_ptr<Person> person = db.createBean<Person>();
person->name = "John Doe";
person->age = 30;
person->email = "[email protected]";
person->addresses.push_back("Tokyo, Japan");
person->addresses.push_back("Osaka, Japan");
std::cout << "Saved Person with ID: " << person.get_id() << std::endl;
}
// More complex usage example
void demonstrateAdvancedUsage() {
hiberlite::Database db("advanced.db");
db.registerBeanClass<Person>();
// Multiple object creation
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;
// Object modification (automatic saving)
people[0]->age = 99;
people[0]->email = "[email protected]";
// Automatically saved to database when bean_ptr goes out of scope
}
Data Operations
// Complex data structure example
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)
// Usage example
void demonstrateComplexData() {
hiberlite::Database db("users.db");
db.registerBeanClass<UserAccount>();
// User account creation
hiberlite::bean_ptr<UserAccount> user = db.createBean<UserAccount>();
user->username = "testuser";
user->password_hash = "hashed_password_123";
// Profile information setup
user->profile["first_name"] = "John";
user->profile["last_name"] = "Doe";
user->profile["bio"] = "Software Developer";
user->profile["location"] = "Tokyo";
// Settings management
user->settings["email_notifications"] = true;
user->settings["dark_mode"] = false;
user->settings["auto_save"] = true;
// Friend list management
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;
}
Configuration and Customization
// Advanced class design example
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; // Using string for simplicity
std::string updated_at;
bool published;
int view_count;
BlogPost() : published(false), view_count(0) {
// Set current time (simplified version)
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"; // Should be current time
}
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)
// Blog system implementation example
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();
// Automatic saving through bean_ptr
}
void viewPost(hiberlite::bean_ptr<BlogPost> post) {
post->incrementView();
// Changes are automatically saved
}
};
Error Handling
#include <stdexcept>
// Error handling example
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;
}
};
// Safe usage example
void safeDatabaseUsage() {
SafeDatabaseManager manager;
if (!manager.initialize("safe_example.db")) {
std::cerr << "Failed to initialize database" << std::endl;
return;
}
try {
// Safe object creation
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;
// Saving through copying
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;
}
}