{"id":13418800,"url":"https://github.com/SqliteModernCpp/sqlite_modern_cpp","last_synced_at":"2025-03-15T04:30:42.965Z","repository":{"id":16908974,"uuid":"19670038","full_name":"SqliteModernCpp/sqlite_modern_cpp","owner":"SqliteModernCpp","description":"The C++14 wrapper around sqlite library","archived":false,"fork":false,"pushed_at":"2024-07-23T15:29:30.000Z","size":2790,"stargazers_count":914,"open_issues_count":43,"forks_count":160,"subscribers_count":59,"default_branch":"dev","last_synced_at":"2025-03-14T03:02:21.570Z","etag":null,"topics":["cpp14","sqlite-orm"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SqliteModernCpp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-05-11T15:41:45.000Z","updated_at":"2025-03-07T05:36:09.000Z","dependencies_parsed_at":"2023-12-03T19:28:36.582Z","dependency_job_id":"dec89d0b-1f8e-4719-a16a-a30d9a3a242c","html_url":"https://github.com/SqliteModernCpp/sqlite_modern_cpp","commit_stats":{"total_commits":277,"total_committers":33,"mean_commits":8.393939393939394,"dds":0.628158844765343,"last_synced_commit":"6e3009973025e0016d5573529067714201338c80"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SqliteModernCpp%2Fsqlite_modern_cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SqliteModernCpp%2Fsqlite_modern_cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SqliteModernCpp%2Fsqlite_modern_cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SqliteModernCpp%2Fsqlite_modern_cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SqliteModernCpp","download_url":"https://codeload.github.com/SqliteModernCpp/sqlite_modern_cpp/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243685505,"owners_count":20330980,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp14","sqlite-orm"],"created_at":"2024-07-30T22:01:07.286Z","updated_at":"2025-03-15T04:30:42.957Z","avatar_url":"https://github.com/SqliteModernCpp.png","language":"C++","readme":"[![Build Status](https://drone.io/github.com/aminroosta/sqlite_modern_cpp/status.png)](https://drone.io/github.com/aminroosta/sqlite_modern_cpp/latest)\n\nsqlite modern cpp wrapper\n====\n\nThis library is a lightweight modern wrapper around sqlite C api .\n\n```c++\n#include\u003ciostream\u003e\n#include \u003csqlite_modern_cpp.h\u003e\nusing namespace  sqlite;\nusing namespace std;\n\nint main() {\n\n   try {\n      // creates a database file 'dbfile.db' if it does not exists.\n      database db(\"dbfile.db\");\n\n      // executes the query and creates a 'user' table\n      db \u003c\u003c\n         \"create table if not exists user (\"\n         \"   _id integer primary key autoincrement not null,\"\n         \"   age int,\"\n         \"   name text,\"\n         \"   weight real\"\n         \");\";\n\n      // inserts a new user record.\n      // binds the fields to '?' .\n      // note that only types allowed for bindings are :\n      //      int ,long, long long, float, double\n      //      string, u16string\n      // sqlite3 only supports utf8 and utf16 strings, you should use std::string for utf8 and std::u16string for utf16.\n      // If you're using C++17, `std::string_view` and `std::u16string_view` can be used as string types.\n      // note that u\"my text\" is a utf16 string literal of type char16_t * .\n      db \u003c\u003c \"insert into user (age,name,weight) values (?,?,?);\"\n         \u003c\u003c 20\n         \u003c\u003c u\"bob\"\n         \u003c\u003c 83.25;\n\n      int age = 21;\n      float weight = 68.5;\n      string name = \"jack\";\n      db \u003c\u003c u\"insert into user (age,name,weight) values (?,?,?);\" // utf16 query string\n         \u003c\u003c age\n         \u003c\u003c name\n         \u003c\u003c weight;\n\n      cout \u003c\u003c \"The new record got assigned id \" \u003c\u003c db.last_insert_rowid() \u003c\u003c endl;\n\n      // selects from user table on a condition ( age \u003e 18 ) and executes\n      // the lambda for each row returned .\n      db \u003c\u003c \"select age,name,weight from user where age \u003e ? ;\"\n         \u003c\u003c 18\n         \u003e\u003e [\u0026](int age, string name, double weight) {\n            cout \u003c\u003c age \u003c\u003c ' ' \u003c\u003c name \u003c\u003c ' ' \u003c\u003c weight \u003c\u003c endl;\n         };\n\n      // a for loop can be used too:\n      // with named variables\n      for(auto \u0026\u0026row : db \u003c\u003c \"select age,name,weight from user where age \u003e ? ;\" \u003c\u003c 18) {\n         int age; string name; double weight;\n         row \u003e\u003e age \u003e\u003e name \u003e\u003e weight;\n         cout \u003c\u003c age \u003c\u003c ' ' \u003c\u003c name \u003c\u003c ' ' \u003c\u003c weight \u003c\u003c endl;\n      }\n      // or with a tuple\n      for(tuple\u003cint, string, double\u003e row : db \u003c\u003c \"select age,name,weight from user where age \u003e ? ;\" \u003c\u003c 18) {\n         cout \u003c\u003c get\u003c0\u003e(row) \u003c\u003c ' ' \u003c\u003c get\u003c1\u003e(row) \u003c\u003c ' ' \u003c\u003c get\u003c2\u003e(row) \u003c\u003c endl;\n      }\n\n      // selects the count(*) from user table\n      // note that you can extract a single column single row result only to : int,long,long long,float,double,string,u16string\n      int count = 0;\n      db \u003c\u003c \"select count(*) from user\" \u003e\u003e count;\n      cout \u003c\u003c \"cout : \" \u003c\u003c count \u003c\u003c endl;\n\n      // you can also extract multiple column rows\n      db \u003c\u003c \"select age, name from user where _id=1;\" \u003e\u003e tie(age, name);\n      cout \u003c\u003c \"Age = \" \u003c\u003c age \u003c\u003c \", name = \" \u003c\u003c name \u003c\u003c endl;\n\n      // this also works and the returned value will be automatically converted to string\n      string str_count;\n      db \u003c\u003c \"select count(*) from user\" \u003e\u003e str_count;\n      cout \u003c\u003c \"scount : \" \u003c\u003c str_count \u003c\u003c endl;\n   }\n   catch (const exception\u0026 e) {\n      cout \u003c\u003c e.what() \u003c\u003c endl;\n   }\n}\n```\n\nYou can not execute multiple statements separated by semicolons in one go.\n\nAdditional flags\n----\nYou can pass additional open flags to SQLite by using a config object:\n\n```c++\nsqlite_config config;\nconfig.flags = OpenFlags::READONLY\ndatabase db(\"some_db\", config);\nint a;\n// Now you can only read from db\nauto ps = db \u003c\u003c \"select a from table where something = ? and anotherthing = ?\" \u003e\u003e a;\nconfig.flags = OpenFlags::READWRITE | OpenFlags::CREATE; // This is the default\nconfig.encoding = Encoding::UTF16; // The encoding is respected only if you create a new database\ndatabase db2(\"some_db2\", config);\n// If some_db2 didn't exists before, it will be created with UTF-16 encoding.\n```\n\nPrepared Statements\n----\nIt is possible to retain and reuse statments this will keep the query plan and in case of an complex query or many uses might increase the performance significantly.\n\n```c++\ndatabase db(\":memory:\");\n\n// if you use \u003c\u003c on a sqlite::database you get a prepared statment back\n// this will not be executed till it gets destroyed or you execute it explicitly\nauto ps = db \u003c\u003c \"select a,b from table where something = ? and anotherthing = ?\"; // get a prepared parsed and ready statment\n\n// first if needed bind values to it\nps \u003c\u003c 5;\nint tmp = 8;\nps \u003c\u003c tmp;\n\n// now you can execute it with `operator\u003e\u003e` or `execute()`.\n// If the statement was executed once it will not be executed again when it goes out of scope.\n// But beware that it will execute on destruction if it wasn't executed!\nps \u003e\u003e [\u0026](int a,int b){ ... };\n\n// after a successfull execution the statment can be executed again, but the bound values are resetted.\n// If you dont need the returned values you can execute it like this\nps.execute();\n// or like this\nps++;\n\n// To disable the execution of a statment when it goes out of scope and wasn't used\nps.used(true); // or false if you want it to execute even if it was used\n\n// Usage Example:\n\nauto ps = db \u003c\u003c \"insert into complex_table_with_lots_of_indices values (?,?,?)\";\nint i = 0;\nwhile( i \u003c 100000 ){\n   ps \u003c\u003c long_list[i++] \u003c\u003c long_list[i++] \u003c\u003c long_list[i++];\n   ps++;\n}\n```\n\nShared Connections\n----\nIf you need the handle to the database connection to execute sqlite3 commands directly you can get a managed shared_ptr to it, so it will not close as long as you have a referenc to it.\n\nTake this example on how to deal with a database backup using SQLITEs own functions in a safe and modern way.\n```c++\ntry {\n   database backup(\"backup\");\t\t//Open the database file we want to backup to\n\n   auto con = db.connection();   // get a handle to the DB we want to backup in our scope\n                                 // this way we are sure the DB is open and ok while we backup\n\n   // Init Backup and make sure its freed on exit or exceptions!\n   auto state =\n      std::unique_ptr\u003csqlite3_backup,decltype(\u0026sqlite3_backup_finish)\u003e(\n      sqlite3_backup_init(backup.connection().get(), \"main\", con.get(), \"main\"),\n      sqlite3_backup_finish\n      );\n\n   if(state) {\n      int rc;\n      // Each iteration of this loop copies 500 database pages from database db to the backup database.\n      do {\n         rc = sqlite3_backup_step(state.get(), 500);\n         std::cout \u003c\u003c \"Remaining \" \u003c\u003c sqlite3_backup_remaining(state.get()) \u003c\u003c \"/\" \u003c\u003c sqlite3_backup_pagecount(state.get()) \u003c\u003c \"\\n\";\n      } while(rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);\n   }\n} // Release allocated resources.\n```\n\nTransactions\n----\nYou can use transactions with `begin;`, `commit;` and `rollback;` commands.\n\n```c++\ndb \u003c\u003c \"begin;\"; // begin a transaction ...   \ndb \u003c\u003c \"insert into user (age,name,weight) values (?,?,?);\"\n   \u003c\u003c 20\n   \u003c\u003c u\"bob\"\n   \u003c\u003c 83.25f;\ndb \u003c\u003c \"insert into user (age,name,weight) values (?,?,?);\" // utf16 string\n   \u003c\u003c 21\n   \u003c\u003c u\"jack\"\n   \u003c\u003c 68.5;\ndb \u003c\u003c \"commit;\"; // commit all the changes.\n\ndb \u003c\u003c \"begin;\"; // begin another transaction ....\ndb \u003c\u003c \"insert into user (age,name,weight) values (?,?,?);\" // utf16 string\n   \u003c\u003c 19\n   \u003c\u003c u\"chirs\"\n   \u003c\u003c 82.7;\ndb \u003c\u003c \"rollback;\"; // cancel this transaction ...\n\n```\n\nBlob\n----\nUse `std::vector\u003cT\u003e` to store and retrieve blob data.  \n`T` could be `char,short,int,long,long long, float or double`.\n\n```c++\ndb \u003c\u003c \"CREATE TABLE person (name TEXT, numbers BLOB);\";\ndb \u003c\u003c \"INSERT INTO person VALUES (?, ?)\" \u003c\u003c \"bob\" \u003c\u003c vector\u003cint\u003e { 1, 2, 3, 4};\ndb \u003c\u003c \"INSERT INTO person VALUES (?, ?)\" \u003c\u003c \"sara\" \u003c\u003c vector\u003cdouble\u003e { 1.0, 2.0, 3.0, 4.0};\n\nvector\u003cint\u003e numbers_bob;\ndb \u003c\u003c \"SELECT numbers from person where name = ?;\" \u003c\u003c \"bob\" \u003e\u003e numbers_bob;\n\ndb \u003c\u003c \"SELECT numbers from person where name = ?;\" \u003c\u003c \"sara\" \u003e\u003e [](vector\u003cdouble\u003e numbers_sara){\n    for(auto e : numbers_sara) cout \u003c\u003c e \u003c\u003c ' '; cout \u003c\u003c endl;\n};\n```\n\nNULL values\n----\nIf you have databases where some rows may be null, you can use `std::unique_ptr\u003cT\u003e` to retain the NULL values between C++ variables and the database.\n\n```c++\ndb \u003c\u003c \"CREATE TABLE tbl (id integer,age integer, name string, img blob);\";\ndb \u003c\u003c \"INSERT INTO tbl VALUES (?, ?, ?, ?);\" \u003c\u003c 1 \u003c\u003c 24 \u003c\u003c \"bob\" \u003c\u003c vector\u003cint\u003e { 1, 2 , 3};\nunique_ptr\u003cstring\u003e ptr_null; // you can even bind empty unique_ptr\u003cT\u003e\ndb \u003c\u003c \"INSERT INTO tbl VALUES (?, ?, ?, ?);\" \u003c\u003c 2 \u003c\u003c nullptr \u003c\u003c ptr_null \u003c\u003c nullptr;\n\ndb \u003c\u003c \"select age,name,img from tbl where id = 1\"\n\t\t\u003e\u003e [](unique_ptr\u003cint\u003e age_p, unique_ptr\u003cstring\u003e name_p, unique_ptr\u003cvector\u003cint\u003e\u003e img_p) {\n\t\t\tif(age_p == nullptr || name_p == nullptr || img_p == nullptr) {\n\t\t\t\tcerr \u003c\u003c \"ERROR: values should not be null\" \u003c\u003c std::endl;\n\t\t\t}\n\n\t\t\tcout \u003c\u003c \"age:\" \u003c\u003c *age_p \u003c\u003c \" name:\" \u003c\u003c *name_p \u003c\u003c \" img:\";\n\t\t\tfor(auto i : *img_p) cout \u003c\u003c i \u003c\u003c \",\"; cout \u003c\u003c endl;\n\t\t};\n\ndb \u003c\u003c \"select age,name,img from tbl where id = 2\"\n\t\t\u003e\u003e [](unique_ptr\u003cint\u003e age_p, unique_ptr\u003cstring\u003e name_p, unique_ptr\u003cvector\u003cint\u003e\u003e img_p) {\n\t\t\tif(age_p != nullptr || name_p != nullptr || img_p != nullptr) {\n\t\t\t\tcerr \u003c\u003c \"ERROR: values should be nullptr\" \u003c\u003c std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\n\t\t\tcout \u003c\u003c \"OK all three values are nullptr\" \u003c\u003c endl;\n\t\t};\n```\n\nSQLCipher\n----\n\nWe have native support for [SQLCipher](https://www.zetetic.net/sqlcipher/).\nIf you want to use encrypted databases, include the `sqlite_moder_cpp/sqlcipher.h` header.\nThen create a `sqlcipher_database` instead.\n\n```c++\n#include\u003ciostream\u003e\n#include \u003csqlite_modern_cpp/sqlcipher.h\u003e\nusing namespace sqlite;\nusing namespace std;\n\nint main() {\n   try {\n      // creates a database file 'dbfile.db' if it does not exists with password 'secret'\n      sqlcipher_config config;\n      config.key = secret;\n      sqlcipher_database db(\"dbfile.db\", config);\n\n      // executes the query and creates a 'user' table\n      db \u003c\u003c\n         \"create table if not exists user (\"\n         \"   _id integer primary key autoincrement not null,\"\n         \"   age int,\"\n         \"   name text,\"\n         \"   weight real\"\n         \");\";\n\n      // More queries ...\n      db.rekey(\"new_secret\"); // Change the password of the already encrypted database.\n\n      // Even more queries ..\n   }\n   catch (const exception\u0026 e) { cout \u003c\u003c e.what() \u003c\u003c endl; }\n}\n```\n\nNULL values (C++17)\n----\nYou can use `std::optional\u003cT\u003e` as an alternative for `std::unique_ptr\u003cT\u003e` to work with NULL values.\n\n```c++\n#include \u003csqlite_modern_cpp.h\u003e\n\nstruct User {\n   long long _id;\n   std::optional\u003cint\u003e age;\n   std::optional\u003cstring\u003e name;\n   std::optional\u003creal\u003e weight;\n};\n\nint main() {\n   User user;\n   user.name = \"bob\";\n\n   // Same database as above\n   database db(\"dbfile.db\");\n\n   // Here, age and weight will be inserted as NULL in the database.\n   db \u003c\u003c \"insert into user (age,name,weight) values (?,?,?);\"\n      \u003c\u003c user.age\n      \u003c\u003c user.name\n      \u003c\u003c user.weight;\n   user._id = db.last_insert_rowid();\n\n   // Here, the User instance will retain the NULL value(s) from the database.\n   db \u003c\u003c \"select _id,age,name,weight from user where age \u003e ? ;\"\n      \u003c\u003c 18\n      \u003e\u003e [\u0026](long long id,\n         std::optional\u003cint\u003e age,\n         std::optional\u003cstring\u003e name\n         std::optional\u003creal\u003e weight) {\n\n      cout \u003c\u003c \"id=\" \u003c\u003c _id\n         \u003c\u003c \" age = \" \u003c\u003c (age ? to_string(*age) ? string(\"NULL\"))\n         \u003c\u003c \" name = \" \u003c\u003c (name ? *name : string(\"NULL\"))\n         \u003c\u003c \" weight = \" \u003c\u003c (weight ? to_string(*weight) : string(NULL))\n         \u003c\u003c endl;\n   };\n}\n```\nIf the optional library is not available, the experimental/optional one will be used instead.\n\nVariant type support (C++17)\n----\nIf your columns may have flexible types, you can use C++17's `std::variant` to extract the value.\n\n```c++\ndb \u003c\u003c \"CREATE TABLE tbl (id integer, data);\";\ndb \u003c\u003c \"INSERT INTO tbl VALUES (?, ?);\" \u003c\u003c 1 \u003c\u003c vector\u003cint\u003e { 1, 2, 3};\ndb \u003c\u003c \"INSERT INTO tbl VALUES (?, ?);\" \u003c\u003c 2 \u003c\u003c 2.5;\n\ndb \u003c\u003c \"select data from tbl where id = 1\"\n\t\t\u003e\u003e [](std::variant\u003cvector\u003cint\u003e, double\u003e data) {\n\t\t\tif(data.index() != 1) {\n\t\t\t\tcerr \u003c\u003c \"ERROR: we expected a blob\" \u003c\u003c std::endl;\n\t\t\t}\n\n\t\t\tfor(auto i : get\u003cvector\u003cint\u003e\u003e(data)) cout \u003c\u003c i \u003c\u003c \",\"; cout \u003c\u003c endl;\n\t\t};\n\ndb \u003c\u003c \"select data from tbl where id = 2\"\n\t\t\u003e\u003e [](std::variant\u003cvector\u003cint\u003e, double\u003e data) {\n\t\t\tif(data.index() != 2) {\n\t\t\t\tcerr \u003c\u003c \"ERROR: we expected a real number\" \u003c\u003c std::endl;\n\t\t\t}\n\n\t\t\tcout \u003c\u003c get\u003cdouble\u003e(data) \u003c\u003c endl;\n\t\t};\n```\n\nIf you read a specific type and this type does not match the actual type in the SQlite database, yor data will be converted.\nThis does not happen if you use a `variant`.\nIf the `variant` does an alternative of the same value type, an `mismatch` exception will be thrown.\nThe value types are NULL, integer, real number, text and BLOB.\nTo support all possible values, you can use `variant\u003cnullptr_t, sqlite_int64, double, string, vector\u003cchar\u003e`.\nIt is also possible to use a variant with `std::monostate` in order to catch null values.\n\nErrors\n----\n\nOn error, the library throws an error class indicating the type of error. The error classes are derived from the SQLITE3 error names, so if the error code is SQLITE_CONSTRAINT, the error class thrown is sqlite::errors::constraint. SQLite3 extended error names are supported too. So there is e.g. a class sqlite::errors::constraint_primarykey derived from sqlite::errors::constraint. Note that all errors are derived from sqlite::sqlite_exception and that itself is derived from std::runtime_exception.\nsqlite::sqlite_exception has a `get_code()` member function to get the SQLITE3 error code or `get_extended_code()` to get the extended error code.\nAdditionally you can use `get_sql()` to see the SQL statement leading to the error.\n\n```c++\ndatabase db(\":memory:\");\ndb \u003c\u003c \"create table person (id integer primary key not null, name text);\";\n\ntry {\n   db \u003c\u003c \"insert into person (id, name) values (?,?)\" \u003c\u003c 1 \u003c\u003c \"jack\";\n   // inserting again to produce error\n   db \u003c\u003c \"insert into person (id, name) values (?,?)\" \u003c\u003c 1 \u003c\u003c \"jack\";\n}\n/* if you are trying to catch all sqlite related exceptions\n * make sure to catch them by reference */\ncatch (const sqlite_exception\u0026 e) {\n   cerr  \u003c\u003c e.get_code() \u003c\u003c \": \" \u003c\u003c e.what() \u003c\u003c \" during \"\n         \u003c\u003c e.get_sql() \u003c\u003c endl;\n}\n/* you can catch specific exceptions as well,\n   catch(const sqlite::errors::constraint \u0026e) {  } */\n/* and even more specific exceptions\n   catch(const sqlite::errors::constraint_primarykey \u0026e) {  } */\n```\n\nYou can also register a error logging function with `sqlite::error_log`.\nThe `\u003csqlite_modern_cpp/log.h\u003e` header has to be included to make this function available.\nThe call to `sqlite::error_log` has to be the first call to any `sqlite_modern_cpp` function by your program.\n\n```c++\nerror_log(\n   [\u0026](sqlite_exception\u0026 e) {\n      cerr  \u003c\u003c e.get_code() \u003c\u003c \": \" \u003c\u003c e.what() \u003c\u003c endl;\n   },\n   [\u0026](errors::misuse\u0026 e) {\n      /* You can behave differently to specific errors */\n   }\n);\ndatabase db(\":memory:\");\ndb \u003c\u003c \"create table person (id integer primary key not null, name text);\";\n\ntry {\n   db \u003c\u003c \"insert into person (id, name) values (?,?)\" \u003c\u003c 1 \u003c\u003c \"jack\";\n   // inserting again to produce error\n   db \u003c\u003c \"insert into person (id, name) values (?,?)\" \u003c\u003c 1 \u003c\u003c \"jack\";\n}\ncatch (const sqlite_exception\u0026 e) {}\n```\n\nCustom SQL functions\n----\n\nTo extend SQLite with custom functions, you just implement them in C++:\n\n```c++\ndatabase db(\":memory:\");\ndb.define(\"tgamma\", [](double i) {return std::tgamma(i);});\ndb \u003c\u003c \"CREATE TABLE numbers (number INTEGER);\";\n\nfor(auto i=0; i!=10; ++i)\n   db \u003c\u003c \"INSERT INTO numbers VALUES (?);\" \u003c\u003c i;\n\ndb \u003c\u003c \"SELECT number, tgamma(number+1) FROM numbers;\" \u003e\u003e [](double number, double factorial) {\n   cout \u003c\u003c number \u003c\u003c \"! = \" \u003c\u003c factorial \u003c\u003c '\\n';\n};\n```\n\nNDK support\n----\nJust Make sure you are using the full path of your database file :\n`sqlite::database db(\"/data/data/com.your.package/dbfile.db\")`.\n\nInstallation\n----\nThe project is header only.  \nSimply point your compiler at the hdr/ directory.  \n\nContributing\n----\nInstall cmake and build the project.  \nDependencies will be installed automatically (using hunter).  \n\n```bash\nmkdir build\ncd ./build\ncmake ..\nmake\n```\n\nBreaking Changes\n----\nSee breaking changes documented in each [Release](https://github.com/aminroosta/sqlite_modern_cpp/releases).\n\nPackage managers\n----\nPull requests are welcome :wink:\n- [AUR](https://aur.archlinux.org/packages/sqlite_modern_cpp/) Arch Linux\n  - maintainer [Nissar Chababy](https://github.com/funilrys)\n- Nuget (TODO [nuget.org](https://www.nuget.org/))\n- Conan (TODO [conan.io](https://conan.io/))\n- [vcpkg](https://github.com/Microsoft/vcpkg)\n\n## License\n\nMIT license - [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)\n","funding_links":[],"categories":["TODO scan for Android support in followings","Database","wrapper/ORM"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSqliteModernCpp%2Fsqlite_modern_cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSqliteModernCpp%2Fsqlite_modern_cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSqliteModernCpp%2Fsqlite_modern_cpp/lists"}