forked from qt-creator/qt-creator
Sqlite: Improve Sqlite wrapper
It is now possible to read values at once. for (auto [name, value] : statement.tupleValues<String, int>(1000, "foo", 20)) .... Change-Id: I3d4bc5218810b4620e1df625126aa490f30bbc71 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -31,8 +31,12 @@
|
||||
|
||||
#include <utils/smallstringvector.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
|
||||
using std::int64_t;
|
||||
|
||||
struct sqlite3_stmt;
|
||||
struct sqlite3;
|
||||
@@ -61,31 +65,45 @@ protected:
|
||||
Utils::SmallStringVector columnNames() const;
|
||||
|
||||
void bind(int index, int value);
|
||||
void bind(int index, qint64 value);
|
||||
void bind(int index, long long value);
|
||||
void bind(int index, double value);
|
||||
void bind(int index, Utils::SmallStringView value);
|
||||
|
||||
template<typename ... Values>
|
||||
void bindValues(Values ... values)
|
||||
void bind(int index, uint value)
|
||||
{
|
||||
bind(index, static_cast<long long>(value));
|
||||
}
|
||||
|
||||
void bind(int index, long value)
|
||||
{
|
||||
bind(index, static_cast<long long>(value));
|
||||
}
|
||||
|
||||
void bindValues()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Values>
|
||||
void bindValues(Values... values)
|
||||
{
|
||||
bindValuesByIndex(1, values...);
|
||||
}
|
||||
|
||||
template<typename ... Values>
|
||||
void write(Values ... values)
|
||||
template<typename... Values>
|
||||
void write(Values... values)
|
||||
{
|
||||
bindValuesByIndex(1, values...);
|
||||
execute();
|
||||
}
|
||||
|
||||
template<typename ... Values>
|
||||
void bindNameValues(Values ... values)
|
||||
template<typename... Values>
|
||||
void bindNameValues(Values... values)
|
||||
{
|
||||
bindValuesByName(values...);
|
||||
}
|
||||
|
||||
template<typename ... Values>
|
||||
void writeNamed(Values ... values)
|
||||
template<typename... Values>
|
||||
void writeNamed(Values... values)
|
||||
{
|
||||
bindValuesByName(values...);
|
||||
execute();
|
||||
@@ -99,11 +117,231 @@ protected:
|
||||
void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames);
|
||||
const Utils::SmallStringVector &bindingColumnNames() const;
|
||||
|
||||
template <typename ContainerType>
|
||||
ContainerType values(const std::vector<int> &columns, int size = 0) const;
|
||||
template <typename... ResultType>
|
||||
std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize)
|
||||
{
|
||||
using Container = std::vector<std::tuple<ResultType...>>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
template <typename ContainerType>
|
||||
ContainerType values(int column = 0) const;
|
||||
while (next())
|
||||
emplaceTupleValues<Container, ResultType...>(resultValues);
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename... ResultType,
|
||||
typename... QueryType>
|
||||
std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, const QueryType&... queryValues)
|
||||
{
|
||||
using Container = std::vector<std::tuple<ResultType...>>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
bindValues(queryValues...);
|
||||
|
||||
while (next())
|
||||
emplaceTupleValues<Container, ResultType...>(resultValues);
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename... ResultType,
|
||||
typename... ElementType>
|
||||
std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize,
|
||||
const std::vector<std::tuple<ElementType...>> &queryTuples)
|
||||
{
|
||||
using Container = std::vector<std::tuple<ResultType...>>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const auto &queryTuple : queryTuples) {
|
||||
bindTupleValues(queryTuple);
|
||||
|
||||
while (next())
|
||||
emplaceTupleValues<Container, ResultType...>(resultValues);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename... ResultType,
|
||||
typename QueryElementType>
|
||||
std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize,
|
||||
const std::vector<QueryElementType> &queryValues)
|
||||
{
|
||||
using Container = std::vector<std::tuple<ResultType...>>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const QueryElementType &queryValue : queryValues) {
|
||||
bindValues(queryValue);
|
||||
|
||||
while (next())
|
||||
emplaceTupleValues<Container, ResultType...>(resultValues);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ResultEntryType>
|
||||
std::vector<ResultType> structValues(std::size_t reserveSize)
|
||||
{
|
||||
using Container = std::vector<ResultType>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
while (next())
|
||||
pushBackStructValues<Container, ResultEntryType...>(resultValues);
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ResultEntryType,
|
||||
typename... QueryType>
|
||||
std::vector<ResultType> structValues(std::size_t reserveSize, const QueryType&... queryValues)
|
||||
{
|
||||
using Container = std::vector<ResultType>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
bindValues(queryValues...);
|
||||
|
||||
while (next())
|
||||
pushBackStructValues<Container, ResultEntryType...>(resultValues);
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ResultEntryType,
|
||||
typename QueryElementType>
|
||||
std::vector<ResultType> structValues(std::size_t reserveSize,
|
||||
const std::vector<QueryElementType> &queryValues)
|
||||
{
|
||||
using Container = std::vector<ResultType>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const QueryElementType &queryValue : queryValues) {
|
||||
bindValues(queryValue);
|
||||
|
||||
while (next())
|
||||
pushBackStructValues<Container, ResultEntryType...>(resultValues);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ResultEntryType,
|
||||
typename... QueryElementType>
|
||||
std::vector<ResultType> structValues(std::size_t reserveSize,
|
||||
const std::vector<std::tuple<QueryElementType...>> &queryTuples)
|
||||
{
|
||||
using Container = std::vector<ResultType>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const auto &queryTuple : queryTuples) {
|
||||
bindTupleValues(queryTuple);
|
||||
|
||||
while (next())
|
||||
pushBackStructValues<Container, ResultEntryType...>(resultValues);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ElementType>
|
||||
std::vector<ResultType> values(std::size_t reserveSize)
|
||||
{
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
while (next())
|
||||
resultValues.push_back(value<ResultType>(0));
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... ElementType>
|
||||
std::vector<ResultType> values(std::size_t reserveSize,
|
||||
const std::vector<std::tuple<ElementType...>> &queryTuples)
|
||||
{
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const auto &queryTuple : queryTuples) {
|
||||
bindTupleValues(queryTuple);
|
||||
|
||||
while (next())
|
||||
resultValues.push_back(value<ResultType>(0));
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename ElementType>
|
||||
std::vector<ResultType> values(std::size_t reserveSize,
|
||||
const std::vector<ElementType> &queryValues)
|
||||
{
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
for (const ElementType &queryValue : queryValues) {
|
||||
bindValues(queryValue);
|
||||
|
||||
while (next())
|
||||
resultValues.push_back(value<ResultType>(0));
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename ResultType,
|
||||
typename... QueryType>
|
||||
std::vector<ResultType> values(std::size_t reserveSize, const QueryType&... queryValues)
|
||||
{
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
|
||||
bindValues(queryValues...);
|
||||
|
||||
while (next())
|
||||
resultValues.push_back(value<ResultType>(0));
|
||||
|
||||
reset();
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static Type toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
@@ -141,14 +379,45 @@ protected:
|
||||
SqliteDatabaseBackend &databaseBackend);
|
||||
|
||||
private:
|
||||
template <typename Container,
|
||||
typename... ResultType,
|
||||
int... Index>
|
||||
void emplaceTupleValues(Container &container, std::integer_sequence<int, Index...>)
|
||||
{
|
||||
container.emplace_back(value<ResultType>(Index)...);
|
||||
}
|
||||
|
||||
template <typename Container,
|
||||
typename... ResultType>
|
||||
void emplaceTupleValues(Container &container)
|
||||
{
|
||||
emplaceTupleValues<Container, ResultType...>(container, std::make_integer_sequence<int, sizeof...(ResultType)>{});
|
||||
}
|
||||
|
||||
template <typename Container,
|
||||
typename... ResultEntryType,
|
||||
int... Index>
|
||||
void pushBackStructValues(Container &container, std::integer_sequence<int, Index...>)
|
||||
{
|
||||
using ResultType = typename Container::value_type;
|
||||
container.push_back(ResultType{value<ResultEntryType>(Index)...});
|
||||
}
|
||||
|
||||
template <typename Container,
|
||||
typename... ResultEntryType>
|
||||
void pushBackStructValues(Container &container)
|
||||
{
|
||||
pushBackStructValues<Container, ResultEntryType...>(container, std::make_integer_sequence<int, sizeof...(ResultEntryType)>{});
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void bindValuesByIndex(int index, Type value)
|
||||
{
|
||||
bind(index, value);
|
||||
}
|
||||
|
||||
template<typename Type, typename ... Value>
|
||||
void bindValuesByIndex(int index, Type value, Value ... values)
|
||||
template<typename Type, typename... Value>
|
||||
void bindValuesByIndex(int index, Type value, Value... values)
|
||||
{
|
||||
bind(index, value);
|
||||
bindValuesByIndex(index + 1, values...);
|
||||
@@ -160,13 +429,26 @@ private:
|
||||
bind(bindingIndexForName(name), value);
|
||||
}
|
||||
|
||||
template<typename Type, typename ... Values>
|
||||
void bindValuesByName(Utils::SmallStringView name, Type value, Values ... values)
|
||||
template<typename Type, typename... Values>
|
||||
void bindValuesByName(Utils::SmallStringView name, Type value, Values... values)
|
||||
{
|
||||
bind(bindingIndexForName(name), value);
|
||||
bindValuesByName(values...);
|
||||
}
|
||||
|
||||
template <typename TupleType, std::size_t... Index>
|
||||
void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<Index...>)
|
||||
{
|
||||
bindValues(std::get<Index>(tuple)...);
|
||||
}
|
||||
|
||||
template <typename TupleType,
|
||||
typename Indices = std::make_index_sequence<std::tuple_size<TupleType>::value>>
|
||||
void bindTupleValues(const TupleType &element)
|
||||
{
|
||||
bindTupleValuesElement(element, Indices());
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement;
|
||||
Utils::SmallStringVector m_bindingColumnNames;
|
||||
@@ -176,4 +458,21 @@ private:
|
||||
mutable bool m_isReadyToFetchValues;
|
||||
};
|
||||
|
||||
extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, int value);
|
||||
extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long value);
|
||||
extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long long value);
|
||||
extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, double value);
|
||||
extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
||||
|
||||
extern template SQLITE_EXPORT int SqliteStatement::toValue<int>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
extern template SQLITE_EXPORT long long SqliteStatement::toValue<long long>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
extern template SQLITE_EXPORT double SqliteStatement::toValue<double>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue<Utils::SmallString>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
|
||||
template <> SQLITE_EXPORT int SqliteStatement::value<int>(int column) const;
|
||||
template <> SQLITE_EXPORT long SqliteStatement::value<long>(int column) const;
|
||||
template <> SQLITE_EXPORT long long SqliteStatement::value<long long>(int column) const;
|
||||
template <> SQLITE_EXPORT double SqliteStatement::value<double>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::PathString SqliteStatement::value<Utils::PathString>(int column) const;
|
||||
} // namespace Sqlite
|
||||
|
||||
Reference in New Issue
Block a user