Klemens Morgenstern wrote:
I've written a boost.sqlite library last year mainly to experiment, but it has been a feature-complete C++ wrapper for a while.
Hence I'd like to gauge interest to see if it's worth proposing for boost.
It has more features than most C++ sqlite wrappers and uses boost-isms such as system.result, tag_invoke and boost.json.
Code: https://github.com/klemens-morgenstern/sqlite Docs: https://klemens.dev/sqlite/
That's interesting. I have also written an sqlite wrapper - as I bet lots of others have. What do you do about multi-threaded usage? FYI here is the readme for my wrapper. // Wrapper for SQLite. // // Usage: // // Open the database file: // sqlite::Database db("/path/to/sqlite/file"); // // Set a busy polling interval: // db.set_busy_timeout(1.0); // // * If no busy timeout is set, an attempt to access the database (for reading or // writing) can fail because another process has it locked for writing. If a busy // timeout has been set with this method, the process will sleep briefly when it // finds the database is locked and then retry, until it succeeds or the total time // (in seconds) has elapsed. // // Load an extension: // db.load_extension("/path/to/extension.so"); // // Create a prepared query. ?s are placeholders for paramters: // sqlite::Query q1(db, "insert into t values (?,?)"); // // Execute the query, substituting the parameters: // q1("hello","world"); // // * SQLite is dynamically typed; the types are INTEGER, REAL, TEXT, BLOB and NULL; // its API further distinguishes between int and int64. NULL is not currently // supported here. std::string_view is used for TEXT. float is promoted // to double for REAL. // // Execute a select query which returns results: // sqlite::Query q2(db, "select a from t where b=?"); // { // auto r = q2("hello"); // ... // } // // * IMPORTANT: note that the scope of the result object r must be limited. // Execution of the query occurs stepwise, with only the first step performed // in the invokation of q2(); subsequent steps occur as result data is read // from r, and the execution is "reset" in r's dtor. Each prepared query // can only have a single execution in progress at any time, so r must have // been destroyed before q2 is invoked again. // // Getting result data: // sqlite::Query q3(db, "select a,b,c from t where b=?"); // { // auto r = q3("hello"); // r.foreach_row( [&](std::string a, std::string b, int c) { // ... // }); // } // // * forach_row takes a callable, e.g. a lambda, and invokes it for each row of // the query results. The callable's parameter types can be std::string // (FIXME should that be string_view?), int, int64 or double, and they are // passed the corresponding column values; SQLite will cast them if necessary. // Alternatively if the callable accepts a single std::arraystd::string,N // (with suitable N) or std::vectorstd::string then the columns are all // extracted as strings into the container. // Note that a lambda with auto parameters cannot be used. // Note that foreach_row() can only be invoked once on a result. // // Simplified syntax that avoids the result scope issue: // sqlite::Query q3(db, "select a,b,c from t where b=?"); // q3("hello").foreach_row( [&](std::string a, std::string b, int c) { // ... // }); // // The result object also has an n_columns() method. // // It's also possible to execute miscellaneous SQL using the exec method: // db.exec("pragma foreign_key = on"); // // No results are returned from this method. Multiple statements can be passed in // a single call, separated by semicolons. // // It is possible to run queries inside transactions scoped: // { // sqlite::Transaction t // q(...); // t.commit(); // } // // If the transaction's dtor is reached without commit() having been invoked, because // q() has thrown an exception for example, the transaction is rolled back. // // Errors are indicated by throwing sqlite::Exception. Regards, Phil.