Skip to content

Ladyia/ORM-Lite

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ORM Lite

ORM Lite is a C++ Object Relation Mapping (ORM) for SQLite3, written in Modern C++ style.

Features

  • Easy to Use
  • Light Weight
  • Compile-time Overhead
  • Strong Typed
  • Fluent Interface

Usage

Including ORM Lite

Before we start, Include src into your Project:

  • ORMLite.h
  • sqlite3.h and sqlite3.c
#include "ORMLite.h" using namespace BOT_ORM; using namespace BOT_ORM::Expression; struct UserModel { int user_id; std::string user_name; double credit_count; Nullable<int> age; Nullable<double> salary; Nullable<std::string> title; // Inject ORM-Lite into this Class :-) ORMAP ("UserModel", user_id, user_name, credit_count, age, salary, title); };

Nullable<T> helps us construct Nullable Value in C++, which is described in the Document 😁

In this Sample, ORMAP ("UserModel", ...) do that:

  • Class UserModel will be mapped into TABLE UserModel;
  • NOT Nullable members will be mapped as NOT NULL;
  • int, double, std::string will be mapped into INT, REAL, TEXT respectively;
  • The first entry id will be set as the Primary Key of the Table;

Create or Drop a Table for the Class

// Open a Connection with *test.db* ORMapper mapper ("test.db"); // Create a table for "UserModel" mapper.CreateTbl (UserModel {}); // Drop the table "UserModel" mapper.DropTbl (UserModel {});
user_id user_name credit_count age salary title
0 John 0.2 21 null null
1 Jack 0.4 null 3.14 null
2 Jess 0.6 null null Dr.
... ... ... ... ... ...

Working on Database with ORMapper

Basic Usage

std::vector<UserModel> initObjs = { { 0, "John", 0.2, 21, nullptr, nullptr }, { 1, "Jack", 0.4, nullptr, 3.14, nullptr }, { 2, "Jess", 0.6, nullptr, nullptr, std::string ("Dr.") } }; // Insert Values into the table for (const auto &obj : initObjs) mapper.Insert (obj); initObjs[1].salary = nullptr; initObjs[1].title = "St."; // Update Entity by Primary Key (WHERE UserModel.id = 1) mapper.Update (initObjs[1]); // Delete Entity by Primary Key (WHERE UserModel.id = 2) mapper.Delete (initObjs[2]); // Transactional Statements try { mapper.Transaction ([&] () { mapper.Delete (initObjs[0]); // OK mapper.Insert (UserModel { 1, "Joke", 0 }); // Failed }); } catch (const std::exception &ex) { // If any statement Failed, throw an exception // "SQL error: UNIQUE constraint failed: UserModel.id" // Remarks: // mapper.Delete (initObjs[0]); will not applied :-) } // Select All to List auto result1 = mapper.Query (UserModel {}).ToList (); // result1 = [{ 0, 0.2, "John", 21, null, null }, // { 1, 0.4, "Jack", null, null, "St." }]

Batch Operations

std::vector<UserModel> dataToSeed; for (int i = 50; i < 100; i++) dataToSeed.emplace_back ( UserModel { i, "July_" + std::to_string (i), i * 0.2 }); // Insert by Batch Insert mapper.Transaction ([&] () { mapper.InsertRange (dataToSeed); }); for (size_t i = 0; i < 20; i++) { dataToSeed[i + 30].age = 30 + (int) i / 2; dataToSeed[i + 20].title = "Mr. " + std::to_string (i); } // Update by Batch Update mapper.Transaction ([&] () { mapper.UpdateRange (dataToSeed); });

Composite Query

// Define a Query Helper Object and its Field Extractor UserModel helper; FieldExtractor field { helper }; // Select by Query auto result2 = mapper.Query (UserModel {}) .Where ( field (helper.user_name) & std::string ("July%") && (field (helper.age) >= 32 && field (helper.title) != nullptr) ) .OrderByDescending (field (helper.age)) .OrderBy (field (helper.user_id)) .Take (3) .Skip (1) .ToVector (); // Remarks: // sql = SELECT * FROM UserModel // WHERE (user_name LIKE 'July%' AND // (age>=32 AND title IS NOT NULL)) // ORDER BY age DESC // ORDER BY id // LIMIT 3 OFFSET 1 // result2 = [{ 89, 17.8, "July_89", 34, null, "Mr. 19" }, // { 86, 17.2, "July_86", 33, null, "Mr. 16" }, // { 87, 17.4, "July_87", 33, null, "Mr. 17" }] // Calculate Aggregate Function by Query auto avg = mapper.Query (UserModel {}) .Where (field (helper.user_name) & std::string ("July%")) .Select (Avg (field (helper.credit_count))); // Remarks: // sql = SELECT AVG (credit_count) FROM UserModel // WHERE (user_name LIKE 'July%') // avg = 14.9 auto count = mapper.Query (UserModel {}) .Where (field (helper.user_name) | std::string ("July%")) .Select (Count ()); // Remarks: // sql = SELECT COUNT (*) FROM UserModel // WHERE (user_name NOT LIKE 'July%') // count = 2 // Update by Condition mapper.Update ( UserModel {}, (field (helper.age) = 10) && (field (helper.credit_count) = 1.0), field (helper.user_name) == std::string ("July")); // Remarks: // sql = UPDATE UserModel SET age=10,credit_count=1.0 // WHERE (user_name='July') // Delete by Condition mapper.Delete (UserModel {}, field (helper.user_id) >= 90); // Remarks: // sql = DELETE FROM UserModel WHERE (id>=90)

Multi-Table Query

// Define more Query Helper Objects and their Field Extractor UserModel user; SellerModel seller; OrderModel order; field = FieldExtractor { user, seller, order }; // Insert Values into the table // mapper.Insert (..., false) means Insert without Primary Key for (size_t i = 0; i < 50; i++) mapper.Insert ( OrderModel { 0, (int) i / 2 + 50, (int) i / 4 + 50, "Item " + std::to_string (i), i * 0.5 }, false); // Join Tables for Query auto joinedQuery = mapper.Query (UserModel {}) .Join (OrderModel {}, field (user.user_id) == field (order.user_id)) .LeftJoin (SellerModel {}, field (seller.seller_id) == field (order.seller_id)) .Where (field (user.user_id) >= 65); // Get Result to List // Results are Nullable-Tuples auto result3 = joinedQuery.ToList (); // Remarks: // sql = SELECT * FROM UserModel // JOIN OrderModel // ON UserModel.user_id=OrderModel.user_id // LEFT JOIN SellerModel // ON SellerModel.seller_id=OrderModel.seller_id // WHERE (UserModel.user_id>=65) // result3 = [(65, "July_65", 13, null, null, null, // 31, 65, 57, "Item 30", 15, // null, null, null), // (65, "July_65", 13, null, null, null, // 32, 65, 57, "Item 31", 15.5, // null, null, null), // ... ] // Group & Having ~ // Results are Nullable-Tuples auto result4 = joinedQuery .Select (field (order.user_id), field (user.user_name), Avg (field (order.fee))) .GroupBy (field (user.user_name)) .Having (Sum (field (order.fee)) >= 40.5) .Skip (3) .ToList (); // Remarks: // sql = SELECT OrderModel.user_id, // UserModel.user_name, // AVG (OrderModel.fee) // FROM UserModel // JOIN OrderModel // ON UserModel.user_id=OrderModel.user_id // LEFT JOIN SellerModel // ON SellerModel.seller_id=OrderModel.seller_id // WHERE (UserModel.user_id>=65) // GROUP BY UserModel.user_name // HAVING SUM (OrderModel.fee)>=40.5 // LIMIT ~0 OFFSET 3 // result4 = [(73, "July_73", 23.25), // (74, "July_74", 24.25)] // Compound Select // Results are Nullable-Tuples auto result5 = mapper.Query (OrderModel {}) .Select (field (order.product_name), field (order.user_id)) .Where (field (order.user_id) == 50) .Union ( joinedQuery .Select (field (user.user_name), field (order.order_id)) ) .Take (4) .ToList (); // sql = SELECT OrderModel.product_name, // OrderModel.user_id // FROM OrderModel // WHERE (OrderModel.user_id==50) // UNION // SELECT UserModel.user_name, // OrderModel.order_id // FROM UserModel // JOIN OrderModel // ON UserModel.user_id=OrderModel.user_id // LEFT JOIN SellerModel // ON SellerModel.seller_id=OrderModel.seller_id // WHERE (UserModel.user_id>=65) // LIMIT 4; // result5 = [("Item 0", 50), // ("Item 1", 50), // ("July_65", 31), // ("July_65", 32)]

Planned Features

  • Blob / DateTime Types
  • Subquery
  • Constraints on Creating Table

Implementation Details (实现细节)

Posts in Chinese only:

About

An ORM for SQLite in Modern C++ and Template

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 99.8%
  • Shell 0.2%