Futuresql

threadeddatabase.h
1// SPDX-FileCopyrightText: 2022 Jonah BrĂ¼chert <jbb@kaidan.im>
2//
3// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
4
5#pragma once
6
7class QUrl;
8class QSqlDatabase;
9
10#include <QString>
11#include <QObject>
12#include <QFuture>
13#include <QSharedDataPointer>
14
15#include <memory>
16#include <optional>
17#include <tuple>
18#include <vector>
19
20#include "threadeddatabase_p.h"
21
22#include <futuresql_export.h>
23
24struct DatabaseConfigurationPrivate;
25
26///
27/// Selection of database types.
28/// If the required one is not included, use the DatabaseConfiguration::setType QString overload instead.
29///
30enum DatabaseType {
31 SQLite
32};
33
34///
35/// Options for connecting to a database
36///
37class FUTURESQL_EXPORT DatabaseConfiguration {
38public:
42
43 /// Set the name of the database driver. If it is included in DatabaseType, use the enum overload instead
44 void setType(const QString &type);
45 /// Set the type of database. If DatabaseType doesn't include the one you need, use the QString overload instead
46 void setType(DatabaseType type);
47 /// Get the name of the database driver
48 const QString &type() const;
49
50 /// Set the hostname
51 void setHostName(const QString &hostName);
52 const std::optional<QString> &hostName() const;
53
54 /// Set the name of the database (path of the file for SQLite)
55 void setDatabaseName(const QString &databaseName);
56 const std::optional<QString> &databaseName() const;
57
58 /// Set user name
59 void setUserName(const QString &userName);
60 const std::optional<QString> &userName() const;
61
62 /// Set password
63 void setPassword(const QString &password);
64 const std::optional<QString> &password() const;
65
66private:
68};
69
70template <typename T>
71concept FromSql = requires(T v, typename T::ColumnTypes row)
72{
73 typename T::ColumnTypes;
74 { std::tuple(row) } -> std::same_as<typename T::ColumnTypes>;
75};
76
77namespace detail {
78
79template <typename ...Args>
80constexpr bool isQVariantConvertible = std::conjunction_v<std::is_convertible<Args, QVariant>...>;
81
82}
83
84struct ThreadedDatabasePrivate;
85
86///
87/// A database connection that lives on a new thread
88///
89class FUTURESQL_EXPORT ThreadedDatabase : public QThread {
90public:
91 ///
92 /// \brief Connect to a database
93 /// \param config Configuration of the database connection
94 /// \return
95 ///
96 static std::unique_ptr<ThreadedDatabase> establishConnection(const DatabaseConfiguration &config);
97
98 ///
99 /// \brief Execute an SQL query on the database, ignoring the result.
100 /// \param sqlQuery SQL query string to execute
101 /// \param args Parameters to bind to the placeholders in the SQL Query
102 /// \return
103 ///
104 template <typename ...Args>
105 requires detail::isQVariantConvertible<Args...>
106 auto execute(const QString &sqlQuery, Args... args) -> QFuture<void> {
107 return db().execute(sqlQuery, args...);
108 }
109
110 ///
111 /// Run the database migrations in the given directory.
112 /// The directory needs to contain a subdirectory for each migration.
113 /// The subdirectories need to be named so that when sorted alphabetically the migrations will be run in the correct order.
114 /// Each subdirectory needs to contain a file named up.sql.
115 ///
116 /// \param migrationDirectory Directory which contains the migrations.
117 /// \return a future that finishes when the database changes are finished
118 ///
119 auto runMigrations(const QString &migrationDirectory) -> QFuture<void>;
120
121 ///
122 /// Declare that the database is currently at the state of the migration in the migration subdirectory
123 /// migrationName.
124 ///
125 /// The automatic migrations will then start with all migrations that are newer than migrationName.
126 ///
127 /// @warning This function should only be used for the initial switch from a different migration system, for example a custom made one.
128 /// \param migrationName
129 /// \return a future that finishes when the database changes are finished
130 ///
131 auto setCurrentMigrationLevel(const QString &migrationName) -> QFuture<void>;
132
133 ///
134 /// \brief Execute an SQL query on the database, retrieving the result.
135 /// \param sqlQuery SQL Query to execute
136 /// \param args Parameters to bind to the placeholders in the SQL query.
137 /// \return Future of a list of lists of variants.
138 ///
139 /// T must provide a tuple of the column types as `using ColumnTypes = std::tuple<...>`
140 /// and a, if the column types are not the same types in the same order as the attributes of the struct,
141 /// a `static T fromSql(ColumnTypes tuple)` deserialization method.
142 ///
143 template <typename T, typename ...Args>
144 requires FromSql<T> && detail::isQVariantConvertible<Args...>
145 auto getResults(const QString &sqlQuery, Args... args) -> QFuture<std::vector<T>> {
146 return db().getResults<T, Args...>(sqlQuery, args...);
147 }
148
149 ///
150 /// \brief Like getResults, but for retrieving just one row.
151 /// \param sqlQuery SQL Query to execute
152 /// \param args Parameters to bind to the placeholders in the SQL query.
153 ///
154 template <typename T, typename ...Args>
155 requires FromSql<T> && detail::isQVariantConvertible<Args...>
156 auto getResult(const QString &sqlQuery, Args... args) -> QFuture<std::optional<T>> {
157 return db().getResult<T, Args...>(sqlQuery, args...);
158 }
159
160 ///
161 /// \brief Run a custom function on the database thread. The function is passed the internal QSqlDatabase.
162 /// \param func A function that takes a QSqlDatabase
163 /// \return The result of the function, wrapped in a QFuture
164 ///
165 template <typename Func>
166 requires std::is_invocable_v<Func, const QSqlDatabase &>
168 return db().runOnThread(std::move(func));
169 }
170
172
173private:
175
176 asyncdatabase_private::AsyncSqlDatabase &db();
177
178 std::unique_ptr<ThreadedDatabasePrivate> d;
179};
180
181///
182/// \brief Deserialize just a single value from a query result.
183///
184template <typename T>
186 using ColumnTypes = std::tuple<T>;
187
188 static SingleValue fromSql(ColumnTypes tuple) {
189 auto [value] = tuple;
190 return SingleValue { value };
191 }
192
193 operator const T &() const {
194 return value;
195 }
196
197 T value;
198};
Options for connecting to a database.
A database connection that lives on a new thread.
auto getResults(const QString &sqlQuery, Args... args) -> QFuture< std::vector< T > >
Execute an SQL query on the database, retrieving the result.
auto execute(const QString &sqlQuery, Args... args) -> QFuture< void >
Execute an SQL query on the database, ignoring the result.
auto runOnThread(Func &&func) -> QFuture< std::invoke_result_t< Func, const QSqlDatabase & > >
Run a custom function on the database thread.
auto getResult(const QString &sqlQuery, Args... args) -> QFuture< std::optional< T > >
Like getResults, but for retrieving just one row.
Deserialize just a single value from a query result.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:50 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.