Warning, /libraries/futuresql/README.md is written in an unsupported language. File is not indexed.
0001 <!-- 0002 SPDX-FileCopyrightText: 2022 Jonah Brüchert <jbb@kaidan.im 0003 0004 SPDX-License-Identifier: BSD-2-Clause 0005 --> 0006 0007 # FutureSQL 0008 0009 A non-blocking database framework for Qt. 0010 0011 FutureSQL was in part inspired by Diesel, and provides a higher level of abstraction than QtSql. 0012 Its features include non-blocking database access by default, relatively boilderplate-free queries, 0013 automatic database migrations and simple mapping to objects. 0014 0015 In order to make FutureSQL's use of templates less confusing, FutureSQL uses C++20 concepts, 0016 and requires a C++20 compiler. 0017 0018 Warning: The API is not finalized yet. 0019 0020 ## Usage 0021 0022 The following example demonstrates the usage of FutureSQL in conjunction with QCoro: 0023 ```cpp 0024 // Qt 0025 #include <QCoreApplication> 0026 #include <QTimer> 0027 0028 // QCoro 0029 #include <QCoro/QCoroTask> 0030 #include <QCoro/QCoroFuture> 0031 0032 // FutureSQL 0033 #include <ThreadedDatabase> 0034 0035 // STL 0036 #include <tuple> 0037 0038 0039 // A data structure that represents data from the "test" table 0040 struct HelloWorld { 0041 // Types that the database columns can be converted to. The types must be convertible from QVariant. 0042 using ColumnTypes = std::tuple<int, QString>; 0043 0044 // This function gets a row from the database as a tuple, and puts it into the HelloWorld structs. 0045 // If the ColumnTypes already match the types and order of the attributes in the struct, you don't need to implement it. 0046 // 0047 // Try to comment it out, the example should still compile and work. 0048 static HelloWorld fromSql(ColumnTypes &&tuple) { 0049 auto [id, data] = tuple; 0050 return HelloWorld { id, data }; 0051 } 0052 0053 // attributes 0054 int id; 0055 QString data; 0056 }; 0057 0058 QCoro::Task<> databaseExample() { 0059 // This object contains the database configuration, 0060 // in this case just the path to the SQLite file, and the database type (SQLite). 0061 DatabaseConfiguration config; 0062 config.setDatabaseName("database.sqlite"); 0063 config.setType(DatabaseType::SQLite); 0064 0065 // Here we open the database file, and get a handle to the database. 0066 auto database = ThreadedDatabase::establishConnection(config); 0067 0068 // Execute some queries. 0069 co_await database->execute("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT)"); 0070 0071 // Query parameters are bound by position in the query. The execute function is variadic and you can add as many parameters as you need. 0072 co_await database->execute("INSERT INTO test (data) VALUES (?)", QStringLiteral("Hello World")); 0073 0074 // Retrieve some data from the database. 0075 // The data is directly returned as our HelloWorld struct. 0076 auto results = co_await database->getResults<HelloWorld>("SELECT * FROM test"); 0077 0078 // Print out the data in the result list 0079 for (const auto &result : results) { 0080 qDebug() << result.id << result.data; 0081 } 0082 0083 // Quit the event loop as we are done 0084 QCoreApplication::instance()->quit(); 0085 } 0086 0087 // Just a minimal main function for QCoro, to start the Qt event loop. 0088 int main(int argc, char *argv[]) { 0089 QCoreApplication app(argc, argv); 0090 QTimer::singleShot(0, databaseExample); 0091 return app.exec(); 0092 } 0093 ``` 0094 0095 In code were coroutines don't make sense, you can use `QCoro::connect` of QCoro > v0.8.0, 0096 or `QFuture<T>::then()` on Qt6, to run a callback once a database query finished. 0097 0098 ## Migrations 0099 0100 FutureSQL can manage database migrations in a way that is mostly compatible with diesel. 0101 You just need to pass it a directory (preferably in QRC) that contains migrations in the following format: 0102 0103 ``` 0104 ├── 2022-05-20-194850_init 0105 │ └── up.sql 0106 └── 2022-05-25-212054_playlists 0107 └── up.sql 0108 ``` 0109 0110 Naming the migration directories after dates is a good practice, as the migrations are run in sorted order. 0111 Naming them for example by a counting number would break once the numbers get to large. 0112 For example, if you don't use leading zeros and only one digit, you'd only have up to 10 migrations. 0113 0114 The migration directory structure can be generated by the `diesel` command line tool. You can install it using cargo as follows: 0115 ```bash 0116 cargo install diesel_cli --features sqlite --no-default-features 0117 ``` 0118 0119 Finally, you can run the migrations from your C++ code: 0120 ```cpp 0121 database->runMigrations(":/migrations/"); 0122 ```