sqlite_orm v1.9.1 Release Notes
Release Date: 2025-02-03 // over 1 year ago-
⭐ drop_table_if_exists, drop_index_if_exists, drop_trigger_if_exists
storage.drop_table_if_exists("users"); storage.drop_index_if_exists("id\_index"); storage.drop_trigger_if_exists("update\_everything");The main difference from existing
drop_XAPIs is that existing APIs don't sendIF EXISTSstring part to SQLite statement. So if you have to callDROP ... IF EXISTSnow you have your functions.⭐ PRAGMA locking_mode
locking_mode value = storage.pragma.locking_mode(); storage.pragma.locking_mode(locking_mode::EXCLUSIVE);// orstorage.pragma.locking_mode(locking_mode::NORMAL);⭐ PRAGMA max_page_count API (thanks to @akrisfx)
autovalue = storage.pragma.max_page_count();// PRAGMA max\_page\_count;value +=2; storage.pragma.max_page_count(value);// PRAGMA max\_page\_count = value⭐ Additional FOREIGN KEY API for inheritance
If you have a superclass for mapped classes and you have foreign key which references inherited class field you can use new API
foreign_key(&ReferencingClass::fieldA).references<Subclass>(&Subclass::fieldB)structPerson{intid; std::string name;intage; };// Define derived class StudentstructStudent:publicPerson{ std::string school_name;Student(intid, std::string name,intage, std::string school_name) : Person{id,std::move(name), age}, school_name(std::move(school_name)) {} };// Define derived class TeacherstructTeacher:publicPerson{ std::string subject;doublesalary;Teacher(intid, std::string name,intage, std::string subject,doublesalary) : Person{id,std::move(name), age}, subject(subject), salary(salary) {} };// Define Classroom class referencing Teacher and StudentstructClassroom{intid;intteacher_id;// Foreign key referencing Teacherintstudent_id;// Foreign key referencing Studentstd::string room_name; };autostorage =make\_storage("",// Define the Person table as a base, though it is not used directlymake_table<Person>("persons",make\_column("id", &Person::id, primary_key().autoincrement()), make_column("name", &Person::name), make_column("age", &Person::age)),// Define the Student table with foreign key inheritancemake_table<Student>("students",make\_column("id", &Student::id, primary_key()), make_column("name", &Student::name), make_column("age", &Student::age), make_column("school\_name", &Student::school_name)),// Define the Teacher table with foreign key inheritancemake_table<Teacher>("teachers",make\_column("id", &Teacher::id, primary_key()), make_column("name", &Teacher::name), make_column("age", &Teacher::age), make_column("subject", &Teacher::subject), make_column("salary", &Teacher::salary)),// Define the Classroom table with foreign keys to Teacher and Studentmake_table<Classroom>("classrooms",make\_column("id", &Classroom::id, primary_key().autoincrement()), make_column("teacher\_id", &Classroom::teacher_id), make_column("student\_id", &Classroom::student_id), make_column("room\_name", &Classroom::room_name), foreign_key(&Classroom::teacher_id).references<Teacher>(&Teacher::id),// \<=== here it isforeign_key(&Classroom::student_id).references<Student>(&Student::id)));// \<=== here it is- ⭐ Common Table Expressions for CRUD operations.
- ⭐ Added C++ operator equivalents for bitwise operator expressions.
- ⭐ Added the possibility of using unary minus expressions.
⚙️ Brand new std::any binding example
🚀 This new example shows you how powerful SQLite with
sqlite_ormcan be.⚙️ VSCode integration
Now you can use VSCode tasks to make your developer experience easier when you contribute to
sqlite_orm.
When you havesqlite_ormfolder opened in VSCode hit Ctrl/CMD+Shift+P to show actions palette, select 'Run task' and selectRun amalgamate scriptto call amalgamate script without interacting with terminal,Run clang-formatto format all the repo andRun unit_teststo rununit_testsbinary if you have at already compiled (expected that you've already configured and built the project usingcmake)- ⚙️ Improved serializing logical and bitwise "not" expressions - less parentheses.
- ⚙️ Placed constexpr strings used for serialization into the read-only segment, which makes resulting executable binaries smaller.
🛠 🐞List of bug fixes
- #1353 (thanks to @uuiid)
- #1354
- Corrected serializing result set deduplicators DISTINCT and ALL.
- ⚡️ Build script: Updated UCM CMake macros, got rid of a CMake deprecation warning. [https://github.com/[/issues/1266](https://github.com/fnc12/sqlite_orm/issues/1266)]
📝Regressions from v1.9:
- The possibility to use rowset deduplication with struct was missing. [https://github.com/[/issues/1341](https://github.com/fnc12/sqlite_orm/issues/1341)]
- Circumvented Clang's buggy pack indexing expression evaluation. [https://github.com/[/issues/1358](https://github.com/fnc12/sqlite_orm/issues/1358)]
- 🛠 Fixed regression of iterating mapped objects [Cudos to @stevenwdv]. [https://github.com/[/issues/1346](https://github.com/fnc12/sqlite_orm/issues/1346)]
Previous changes from v1.9
-
⭐ Common table expressions
There is a keyword
WITHin SQLite which allows making unreal queries like Mandelbrot Set (Apfelmaennchen in German):WITH RECURSIVE xaxis(x)AS(VALUES(-2.0)UNION ALLSELECTx+0.05FROMxaxisWHEREx\<1.2), yaxis(y)AS(VALUES(-1.0)UNION ALLSELECTy+0.1FROMyaxisWHEREy\<1.0), m(iter, cx, cy, x, y)AS(SELECT0, x, y,0.0,0.0FROMxaxis, yaxisUNION ALLSELECTiter+1, cx, cy, x\*x-y\*y+cx,2.0\*x\*y+cyFROMmWHERE(x\*x+y\*y)\<4.0ANDiter\<28), m2(iter, cx, cy)AS(SELECTmax(iter), cx, cyFROMmGROUP BYcx, cy ), a(t)AS(SELECTgroup_concat( substr(' .+\*#',1+min(iter/7,4),1),'')FROMm2GROUP BYcy )SELECTgroup_concat(rtrim(t),x'0a')FROMa;which produces
....# ..#*.. ..+####+. .......+####.... + ..##+*##########+.++++ .+.##################+. .............+###################+.+ ..++..#.....*#####################+. ...+#######++#######################. ....+*################################. #############################################... ....+*################################. ...+#######++#######################. ..++..#.....*#####################+. .............+###################+.+ .+.##################+. ..##+*##########+.++++ .......+####.... + ..+####+. ..#*.. ....# +.or Sudoku solver. Actually those exampled can be inspected here. Long story short from this release you can create all those common table expressions right with
sqlite_orm. E.g. Mandelbrot Set's code in C++ looks like this:constexprorm_cte_monikerautoxaxis ="xaxis"_cte;constexprorm_cte_monikerautoyaxis ="yaxis"_cte;constexprorm_cte_monikerautom ="m"_cte;constexprorm_cte_monikerautom2 ="m2"_cte;constexprorm_cte_monikerautoa ="string"_cte;constexprorm_column_aliasautox ="x"_col;constexprorm_column_aliasautoy ="y"_col;constexprorm_column_aliasautoiter ="iter"_col;constexprorm_column_aliasautocx ="cx"_col;constexprorm_column_aliasautocy ="cy"_col;constexprorm_column_aliasautot ="t"_col;autoast = with_recursive(make\_tuple(xaxis(x).as(union_all(select(-2.0), select(xaxis->*x +0.05, where(xaxis->*x <1.2)))), yaxis(y).as(union_all(select(-1.0), select(yaxis->*y +0.10, where(yaxis->*y <1.0)))), m(iter, cx, cy, x, y) .as(union_all(select(columns(0, xaxis->*x, yaxis->*y,0.0,0.0)), select(columns(m->*iter +1, m->*cx, m->*cy, m->*x * m->*x - m->*y * m->*y + m->*cx,2.0* m->*x * m->*y + m->*cy), where((m->*x * m->*x + m->*y * m->*y) < 4.0 && m->*iter < 28)))), m2(iter, cx, cy).as(select(columns(max<>(m->*iter), m->*cx, m->*cy), group_by(m->*cx, m->*cy))), a(t).as(select(group_concat(substr(" .+\*#",1+ min<>(m2->*iter /7.0,4.0), 1), ""), group_by(m2->*cy)))), select(group_concat(rtrim(a->*t), "\n")));for C++20 or
usingcte_xaxis =decltype(1_ctealias);usingcte_yaxis =decltype(2_ctealias);usingcte_m =decltype(3_ctealias);usingcte_m2 =decltype(4_ctealias);usingcte_a =decltype(5_ctealias);constexprautox = colalias_a{};constexprautoy = colalias_b{};constexprautoiter = colalias_c{};constexprautocx = colalias_d{};constexprautocy = colalias_e{};constexprautot = colalias_f{};autoast = with_recursive(make\_tuple( cte<cte_xaxis>("x").as(union\_all(select(-2.0>>= x), select(column<cte_xaxis>(x) + 0.05, where(column<cte_xaxis>(x) < 1.2)))), cte<cte_yaxis>("y").as(union\_all(select(-1.0>>= y), select(column<cte_yaxis>(y) + 0.10, where(column<cte_yaxis>(y) < 1.0)))), cte<cte_m>("iter","cx","cy","x","y") .as(union_all(select(columns(0>>= iter, column<cte_xaxis>(x) >>= cx, column<cte_yaxis>(y) >>= cy, 0.0 >>= x, 0.0 >>= y)), select(columns(column<cte_m>(iter) + 1, column<cte_m>(cx), column<cte_m>(cy), column<cte_m>(x) * column<cte_m>(x) - column<cte_m>(y) * column<cte_m>(y) + column<cte_m>(cx), 2.0 * column<cte_m>(x) * column<cte_m>(y) + column<cte_m>(cy)), where((column<cte_m>(x) * column<cte_m>(x) + column<cte_m>(y) * column<cte_m>(y)) < 4.0 && column<cte_m>(iter) < 28)))), cte<cte_m2>("iter","cx","cy") .as(select(columns(max<>(column<cte_m>(iter)) >>= iter, column<cte_m>(cx), column<cte_m>(cy)), group_by(column<cte_m>(cx), column<cte_m>(cy)))), cte<cte_a>("t").as(select(group_concat(substr(" .+\*#",1+ min<>(column<cte_m2>(iter) / 7.0, 4.0), 1), "") >>= t, group_by(column<cte_m2>(cy))))), select(group_concat(rtrim(column<cte_a>(t)), "\n")));for the older C++ versions. And then just run
autostmt = storage.prepare(ast);autoresults = storage.execute(stmt); cout <<"Apfelmaennchen (Mandelbrot set):\n";for(conststring& rowString: results) { cout << rowString <<'\n'; } cout << endl;In case this example is too complex let's use the very simple example:
WITH RECURSIVE cnt(x)AS(VALUES(1)UNION ALLSELECTx+1FROMcntWHEREx\<1000000)SELECTxFROMcnt;which can be represented in C++ as
constexprorm_cte_monikerautocnt ="cnt"_cte;autoast = with_recursive(cnt().as(union_all(select(from), select(cnt->*1_colalias +1, where(cnt->*1_colalias < end)))), select(cnt->*1_colalias));in C++20 and as
usingcnt =decltype(1_ctealias);autoast = with_recursive( cte<cnt>().as(union\_all(select(from), select(column<cnt>(1_colalias) + 1, where(column<cnt>(1_colalias) < end)))), select(column<cnt>(1_colalias)));in the older C++ versions.
There are a lot of exampleы of CTE (common table expressions) available in our examples folder here.
Thanks to @trueqbit for such a brilliant feature!
👍 ⭐ FTS5 extension support
Example:
structPost{ std::string title; std::string body; };autostorage = make_storage("",make\_virtual\_table("posts",using\_fts5(make_column("title", &Post::title), make_column("body", &Post::body))));which is equivalent of
CREATE VIRTUAL TABLE posts USING FTS5(title, body);Postclass is mapped to virtual tableposts. You can operate with it like a regular table just like you do with FTS5 virtual table.
🆕 New AST nodes:match<T>(expression)function which representsMATCHSQLite operator. Can be used like any other function within FTS5 queriesrank()function which representsRANKkeyword. One can writeorder_by(rank())to getORDER BY rankor plainrank()withoutorder_byto getRANKkeyword in your queryis_equaloverload for table comparison:is_equal<User>("Tom Gregory")serializes to"users" = 'Tom Gregory'highlight<T>(a, b, c)function which representsHIGHLIGHT(table, a, b, c)SQL functionunindexed()forUNINDEXEDcolumn constraintprefix(auto)forprefix=xcolumn constrainttokenize(auto)fortokenize = x. E.g.tokenize("porter ascii")producestokenize = 'porter ascii'content(auto)forcontent=x. E.g.content("")producescontent=''content<T>()forcontent="table_name_for_T". E.g.content<T>()producescontent="users"
⭐ pragma.module_list
module_listis a get-only pragma which returnsstd::vector<std::string>:autostorage = make_storage(...);constautomoduleList = storage.pragma.module_list();// decltype(moduleList) is std::vector\<std::string\>⭐ Explicit NULL and NOT NULL column constraints
For a long time
sqlite_ormdid not havenull()andnot_null()explicit column constraints functions cause nullability has being computed from mapped member pointer field type. E.g.std::optional,std::unique_ptrandstd::shared_ptrare treated as nullables by default. And if you create a class with a field of one of these types and callsync_schemafor empty database the columns will be created as nullables and you may store SQLite'sNULLthere usingnullptrvalue in C++. Also you can create your own nullable types usingsqlite_orm::type_is_nullabletrait specialization. All other types are not nullable by default. E.g. if your column is mapped to a field ofstd::stringth...