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:
@@ -28,12 +28,11 @@
|
||||
namespace Sqlite {
|
||||
|
||||
CreateTableSqlStatementBuilder::CreateTableSqlStatementBuilder()
|
||||
: m_sqlStatementBuilder("CREATE TABLE IF NOT EXISTS $table($columnDefinitions)$withoutRowId"),
|
||||
m_useWithoutRowId(false)
|
||||
: m_sqlStatementBuilder("CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId")
|
||||
{
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName)
|
||||
void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName)
|
||||
{
|
||||
m_sqlStatementBuilder.clear();
|
||||
|
||||
@@ -42,11 +41,11 @@ void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName)
|
||||
|
||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
||||
ColumnType columnType,
|
||||
IsPrimaryKey isPrimaryKey)
|
||||
Contraint constraint)
|
||||
{
|
||||
m_sqlStatementBuilder.clear();
|
||||
|
||||
m_columns.emplace_back(std::move(columnName), columnType, isPrimaryKey);
|
||||
m_columns.emplace_back(std::move(columnName), columnType, constraint);
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
|
||||
@@ -61,6 +60,16 @@ void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId)
|
||||
m_useWithoutRowId = useWithoutRowId;
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::setUseIfNotExists(bool useIfNotExists)
|
||||
{
|
||||
m_useIfNotExits = useIfNotExists;
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::setUseTemporaryTable(bool useTemporaryTable)
|
||||
{
|
||||
m_useTemporaryTable = useTemporaryTable;
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::clear()
|
||||
{
|
||||
m_sqlStatementBuilder.clear();
|
||||
@@ -95,8 +104,11 @@ void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
||||
for (const SqliteColumn &columns : m_columns) {
|
||||
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
||||
|
||||
if (columns.isPrimaryKey())
|
||||
columnDefinitionString.append(" PRIMARY KEY");
|
||||
switch (columns.constraint()) {
|
||||
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break;
|
||||
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break;
|
||||
case Contraint::NoConstraint: break;
|
||||
}
|
||||
|
||||
columnDefinitionStrings.push_back(columnDefinitionString);
|
||||
}
|
||||
@@ -108,12 +120,34 @@ void CreateTableSqlStatementBuilder::bindAll() const
|
||||
{
|
||||
m_sqlStatementBuilder.bind("$table", m_tableName.clone());
|
||||
|
||||
bindTemporary();
|
||||
bindIfNotExists();
|
||||
bindColumnDefinitions();
|
||||
bindWithoutRowId();
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::bindWithoutRowId() const
|
||||
{
|
||||
if (m_useWithoutRowId)
|
||||
m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID");
|
||||
else
|
||||
m_sqlStatementBuilder.bindEmptyText("$withoutRowId");
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::bindIfNotExists() const
|
||||
{
|
||||
if (m_useIfNotExits)
|
||||
m_sqlStatementBuilder.bind("$ifNotExits", "IF NOT EXISTS ");
|
||||
else
|
||||
m_sqlStatementBuilder.bindEmptyText("$ifNotExits");
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::bindTemporary() const
|
||||
{
|
||||
if (m_useTemporaryTable)
|
||||
m_sqlStatementBuilder.bind("$temporary", "TEMPORARY ");
|
||||
else
|
||||
m_sqlStatementBuilder.bindEmptyText("$temporary");
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -35,12 +35,14 @@ class SQLITE_EXPORT CreateTableSqlStatementBuilder
|
||||
public:
|
||||
CreateTableSqlStatementBuilder();
|
||||
|
||||
void setTable(Utils::SmallString &&tableName);
|
||||
void setTableName(Utils::SmallString &&tableName);
|
||||
void addColumn(Utils::SmallString &&columnName,
|
||||
ColumnType columnType,
|
||||
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No);
|
||||
Contraint constraint = Contraint::NoConstraint);
|
||||
void setColumns(const SqliteColumns &columns);
|
||||
void setUseWithoutRowId(bool useWithoutRowId);
|
||||
void setUseIfNotExists(bool useIfNotExists);
|
||||
void setUseTemporaryTable(bool useTemporaryTable);
|
||||
|
||||
void clear();
|
||||
void clearColumns();
|
||||
@@ -52,12 +54,17 @@ public:
|
||||
protected:
|
||||
void bindColumnDefinitions() const;
|
||||
void bindAll() const;
|
||||
void bindWithoutRowId() const;
|
||||
void bindIfNotExists() const;
|
||||
void bindTemporary() const;
|
||||
|
||||
private:
|
||||
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
||||
Utils::SmallString m_tableName;
|
||||
SqliteColumns m_columns;
|
||||
bool m_useWithoutRowId;
|
||||
bool m_useWithoutRowId = false;
|
||||
bool m_useIfNotExits = false;
|
||||
bool m_useTemporaryTable = false;
|
||||
};
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -38,17 +38,17 @@ public:
|
||||
|
||||
SqliteColumn(Utils::SmallString &&name,
|
||||
ColumnType type = ColumnType::Numeric,
|
||||
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No)
|
||||
Contraint constraint = Contraint::NoConstraint)
|
||||
: m_name(std::move(name)),
|
||||
m_type(type),
|
||||
m_isPrimaryKey(isPrimaryKey)
|
||||
m_constraint(constraint)
|
||||
{}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_name.clear();
|
||||
m_type = ColumnType::Numeric;
|
||||
m_isPrimaryKey = IsPrimaryKey::No;
|
||||
m_constraint = Contraint::NoConstraint;
|
||||
}
|
||||
|
||||
void setName(Utils::SmallString &&newName)
|
||||
@@ -71,14 +71,14 @@ public:
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void setIsPrimaryKey(IsPrimaryKey isPrimaryKey)
|
||||
void setContraint(Contraint constraint)
|
||||
{
|
||||
m_isPrimaryKey = isPrimaryKey;
|
||||
m_constraint = constraint;
|
||||
}
|
||||
|
||||
bool isPrimaryKey() const
|
||||
Contraint constraint() const
|
||||
{
|
||||
return m_isPrimaryKey == IsPrimaryKey::Yes;
|
||||
return m_constraint;
|
||||
}
|
||||
|
||||
Utils::SmallString typeString() const
|
||||
@@ -98,13 +98,13 @@ public:
|
||||
{
|
||||
return first.m_name == second.m_name
|
||||
&& first.m_type == second.m_type
|
||||
&& first.m_isPrimaryKey == second.m_isPrimaryKey;
|
||||
&& first.m_constraint == second.m_constraint;
|
||||
}
|
||||
|
||||
private:
|
||||
Utils::SmallString m_name;
|
||||
ColumnType m_type = ColumnType::Numeric;
|
||||
IsPrimaryKey m_isPrimaryKey = IsPrimaryKey::No;
|
||||
Contraint m_constraint = Contraint::NoConstraint;
|
||||
};
|
||||
|
||||
using SqliteColumns = std::vector<SqliteColumn>;
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "sqlitedatabase.h"
|
||||
|
||||
#include "sqlitetable.h"
|
||||
#include "sqlitetransaction.h"
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
@@ -34,6 +35,12 @@ SqliteDatabase::SqliteDatabase()
|
||||
{
|
||||
}
|
||||
|
||||
SqliteDatabase::SqliteDatabase(Utils::PathString &&databaseFilePath)
|
||||
: m_databaseBackend(*this)
|
||||
{
|
||||
open(std::move(databaseFilePath));
|
||||
}
|
||||
|
||||
void SqliteDatabase::open()
|
||||
{
|
||||
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
||||
@@ -61,7 +68,7 @@ bool SqliteDatabase::isOpen() const
|
||||
|
||||
SqliteTable &SqliteDatabase::addTable()
|
||||
{
|
||||
m_sqliteTables.emplace_back(*this);
|
||||
m_sqliteTables.emplace_back();
|
||||
|
||||
return m_sqliteTables.back();
|
||||
}
|
||||
@@ -118,8 +125,12 @@ void SqliteDatabase::execute(Utils::SmallStringView sqlStatement)
|
||||
|
||||
void SqliteDatabase::initializeTables()
|
||||
{
|
||||
SqliteImmediateTransaction<SqliteDatabase> transaction(*this);
|
||||
|
||||
for (SqliteTable &table : m_sqliteTables)
|
||||
table.initialize();
|
||||
table.initialize(*this);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
SqliteDatabaseBackend &SqliteDatabase::backend()
|
||||
|
@@ -37,12 +37,14 @@ namespace Sqlite {
|
||||
|
||||
class SQLITE_EXPORT SqliteDatabase
|
||||
{
|
||||
template <typename Database>
|
||||
friend class SqliteAbstractTransaction;
|
||||
friend class SqliteStatement;
|
||||
friend class SqliteBackend;
|
||||
|
||||
public:
|
||||
SqliteDatabase();
|
||||
SqliteDatabase(Utils::PathString &&databaseFilePath);
|
||||
|
||||
SqliteDatabase(const SqliteDatabase &) = delete;
|
||||
bool operator=(const SqliteDatabase &) = delete;
|
||||
|
@@ -38,14 +38,6 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#if defined(Q_OS_DARWIN) && defined(Q_CC_GNU)
|
||||
#define QTC_THREAD_LOCAL __thread
|
||||
#else
|
||||
#define QTC_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
#define SIZE_OF_BYTEARRAY_ARRAY(array) sizeof(array)/sizeof(QByteArray)
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
SqliteDatabaseBackend::SqliteDatabaseBackend(SqliteDatabase &database)
|
||||
|
@@ -37,6 +37,8 @@
|
||||
# define SQLITE_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
enum class ColumnType : char
|
||||
{
|
||||
Numeric,
|
||||
@@ -46,10 +48,11 @@ enum class ColumnType : char
|
||||
None
|
||||
};
|
||||
|
||||
enum class IsPrimaryKey : char
|
||||
enum class Contraint : char
|
||||
{
|
||||
No,
|
||||
Yes
|
||||
NoConstraint,
|
||||
PrimaryKey,
|
||||
Unique
|
||||
};
|
||||
|
||||
enum class ColumnConstraint : char
|
||||
@@ -84,3 +87,5 @@ enum TextEncoding : char
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -37,6 +37,8 @@ public:
|
||||
using SqliteStatement::next;
|
||||
using SqliteStatement::reset;
|
||||
using SqliteStatement::value;
|
||||
using SqliteStatement::structValues;
|
||||
using SqliteStatement::tupleValues;
|
||||
using SqliteStatement::text;
|
||||
using SqliteStatement::values;
|
||||
using SqliteStatement::columnCount;
|
||||
|
@@ -48,6 +48,8 @@ public:
|
||||
using SqliteStatement::value;
|
||||
using SqliteStatement::text;
|
||||
using SqliteStatement::values;
|
||||
using SqliteStatement::structValues;
|
||||
using SqliteStatement::tupleValues;
|
||||
using SqliteStatement::columnCount;
|
||||
using SqliteStatement::columnNames;
|
||||
using SqliteStatement::toValue;
|
||||
|
@@ -29,13 +29,11 @@
|
||||
#include "sqlitedatabasebackend.h"
|
||||
#include "sqliteexception.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QtGlobal>
|
||||
#include <QVariant>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#endif
|
||||
@@ -61,8 +59,8 @@ void SqliteStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement)
|
||||
sqlite3_finalize(compiledStatement);
|
||||
}
|
||||
|
||||
class UnlockNotification {
|
||||
|
||||
class UnlockNotification
|
||||
{
|
||||
public:
|
||||
static void unlockNotifyCallBack(void **arguments, int argumentCount)
|
||||
{
|
||||
@@ -74,27 +72,24 @@ public:
|
||||
|
||||
void wakeupWaitCondition()
|
||||
{
|
||||
mutex.lock();
|
||||
fired = 1;
|
||||
waitCondition.wakeAll();
|
||||
mutex.unlock();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_fired = 1;
|
||||
}
|
||||
m_waitCondition.notify_all();
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
mutex.lock();
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (!fired) {
|
||||
waitCondition.wait(&mutex);
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
m_waitCondition.wait(lock, [&] () { return m_fired; });
|
||||
}
|
||||
|
||||
private:
|
||||
bool fired = false;
|
||||
QWaitCondition waitCondition;
|
||||
QMutex mutex;
|
||||
bool m_fired = false;
|
||||
std::condition_variable m_waitCondition;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
void SqliteStatement::waitForUnlockNotify() const
|
||||
@@ -143,6 +138,7 @@ void SqliteStatement::step() const
|
||||
void SqliteStatement::execute() const
|
||||
{
|
||||
next();
|
||||
reset();
|
||||
}
|
||||
|
||||
int SqliteStatement::columnCount() const
|
||||
@@ -168,7 +164,7 @@ void SqliteStatement::bind(int index, int value)
|
||||
throwException("SqliteStatement::bind: cant' bind 32 bit integer!");
|
||||
}
|
||||
|
||||
void SqliteStatement::bind(int index, qint64 value)
|
||||
void SqliteStatement::bind(int index, long long value)
|
||||
{
|
||||
int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value);
|
||||
if (resultCode != SQLITE_OK)
|
||||
@@ -198,7 +194,8 @@ void SqliteStatement::bind(Utils::SmallStringView name, Type value)
|
||||
}
|
||||
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, int value);
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, qint64 value);
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long value);
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long long value);
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, double value);
|
||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
||||
|
||||
@@ -363,21 +360,23 @@ SqliteDatabase &SqliteStatement::database() const
|
||||
return m_database;
|
||||
}
|
||||
|
||||
static Utils::SmallString textForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
template <typename StringType>
|
||||
static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
{
|
||||
const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
|
||||
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
|
||||
|
||||
return Utils::SmallString(text, size);
|
||||
return StringType(text, size);
|
||||
}
|
||||
|
||||
static Utils::SmallString convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
template <typename StringType>
|
||||
static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
{
|
||||
int dataType = sqlite3_column_type(sqlStatment, column);
|
||||
switch (dataType) {
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
case SQLITE3_TEXT: return textForColumn(sqlStatment, column);
|
||||
case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column);
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_NULL: return {};
|
||||
}
|
||||
@@ -394,7 +393,13 @@ int SqliteStatement::value<int>(int column) const
|
||||
}
|
||||
|
||||
template<>
|
||||
qint64 SqliteStatement::value<qint64>(int column) const
|
||||
long SqliteStatement::value<long>(int column) const
|
||||
{
|
||||
return long(value<long long>(column));
|
||||
}
|
||||
|
||||
template<>
|
||||
long long SqliteStatement::value<long long>(int column) const
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(column);
|
||||
@@ -409,14 +414,17 @@ double SqliteStatement::value<double>(int column) const
|
||||
return sqlite3_column_double(m_compiledStatement.get(), column);
|
||||
}
|
||||
|
||||
template<>
|
||||
Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const
|
||||
template<typename StringType>
|
||||
StringType SqliteStatement::value(int column) const
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(column);
|
||||
return convertToTextForColumn(m_compiledStatement.get(), column);
|
||||
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
|
||||
}
|
||||
|
||||
template SQLITE_EXPORT Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const;
|
||||
template SQLITE_EXPORT Utils::PathString SqliteStatement::value<Utils::PathString>(int column) const;
|
||||
|
||||
Utils::SmallString SqliteStatement::text(int column) const
|
||||
{
|
||||
return value<Utils::SmallString>(column);
|
||||
@@ -434,45 +442,6 @@ ContainerType SqliteStatement::columnValues(const std::vector<int> &columnIndice
|
||||
return valueContainer;
|
||||
}
|
||||
|
||||
template <typename ContainerType>
|
||||
ContainerType SqliteStatement::values(const std::vector<int> &columns, int size) const
|
||||
{
|
||||
checkColumnsAreValid(columns);
|
||||
|
||||
ContainerType resultValues;
|
||||
resultValues.reserve(typename ContainerType::size_type(size));
|
||||
|
||||
reset();
|
||||
|
||||
while (next()) {
|
||||
auto values = columnValues<ContainerType>(columns);
|
||||
std::move(values.begin(), values.end(), std::back_inserter(resultValues));
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template SQLITE_EXPORT Utils::SmallStringVector SqliteStatement::values<Utils::SmallStringVector>(const std::vector<int> &columnIndices, int size) const;
|
||||
|
||||
template <typename ContainerType>
|
||||
ContainerType SqliteStatement::values(int column) const
|
||||
{
|
||||
typedef typename ContainerType::value_type ElementType;
|
||||
ContainerType resultValues;
|
||||
|
||||
reset();
|
||||
|
||||
while (next()) {
|
||||
resultValues.push_back(value<ElementType>(column));
|
||||
}
|
||||
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
template SQLITE_EXPORT std::vector<qint64> SqliteStatement::values<std::vector<qint64>>(int column) const;
|
||||
template SQLITE_EXPORT std::vector<double> SqliteStatement::values<std::vector<double>>(int column) const;
|
||||
template SQLITE_EXPORT Utils::SmallStringVector SqliteStatement::values<Utils::SmallStringVector>(int column) const;
|
||||
|
||||
template <typename Type>
|
||||
Type SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database)
|
||||
{
|
||||
@@ -484,7 +453,7 @@ Type SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabas
|
||||
}
|
||||
|
||||
template SQLITE_EXPORT int SqliteStatement::toValue<int>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
template SQLITE_EXPORT qint64 SqliteStatement::toValue<qint64>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
template SQLITE_EXPORT long long SqliteStatement::toValue<long long>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
template SQLITE_EXPORT double SqliteStatement::toValue<double>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue<Utils::SmallString>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -25,32 +25,8 @@
|
||||
|
||||
#include "sqlitetable.h"
|
||||
|
||||
#include "sqlitecolumn.h"
|
||||
#include "sqlitedatabase.h"
|
||||
#include "createtablesqlstatementbuilder.h"
|
||||
#include "sqlitewritestatement.h"
|
||||
#include "sqlitetransaction.h"
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
void SqliteTable::initialize()
|
||||
{
|
||||
try {
|
||||
CreateTableSqlStatementBuilder createTableSqlStatementBuilder;
|
||||
|
||||
createTableSqlStatementBuilder.setTable(m_tableName.clone());
|
||||
createTableSqlStatementBuilder.setUseWithoutRowId(m_withoutRowId);
|
||||
createTableSqlStatementBuilder.setColumns(m_sqliteColumns);
|
||||
|
||||
SqliteImmediateTransaction transaction(m_sqliteDatabase);
|
||||
m_sqliteDatabase.execute(createTableSqlStatementBuilder.sqlStatement());
|
||||
transaction.commit();
|
||||
|
||||
m_isReady = true;
|
||||
|
||||
} catch (const SqliteException &exception) {
|
||||
exception.printWarning();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -25,8 +25,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "createtablesqlstatementbuilder.h"
|
||||
#include "sqliteglobal.h"
|
||||
#include "sqlitecolumn.h"
|
||||
#include "sqliteexception.h"
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
@@ -35,11 +37,6 @@ class SqliteDatabase;
|
||||
class SqliteTable
|
||||
{
|
||||
public:
|
||||
SqliteTable(SqliteDatabase &m_sqliteDatabase)
|
||||
: m_sqliteDatabase(m_sqliteDatabase)
|
||||
{
|
||||
}
|
||||
|
||||
void setName(Utils::SmallString &&name)
|
||||
{
|
||||
m_tableName = std::move(name);
|
||||
@@ -60,11 +57,16 @@ public:
|
||||
return m_withoutRowId;
|
||||
}
|
||||
|
||||
void setUseIfNotExists(bool useIfNotExists)
|
||||
{
|
||||
m_useIfNotExists = useIfNotExists;
|
||||
}
|
||||
|
||||
SqliteColumn &addColumn(Utils::SmallString &&name,
|
||||
ColumnType type = ColumnType::Numeric,
|
||||
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No)
|
||||
Contraint constraint = Contraint::NoConstraint)
|
||||
{
|
||||
m_sqliteColumns.emplace_back(std::move(name), type, isPrimaryKey);
|
||||
m_sqliteColumns.emplace_back(std::move(name), type, constraint);
|
||||
|
||||
return m_sqliteColumns.back();
|
||||
}
|
||||
@@ -79,13 +81,31 @@ public:
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
void initialize();
|
||||
template <typename Database>
|
||||
void initialize(Database &database)
|
||||
{
|
||||
try {
|
||||
CreateTableSqlStatementBuilder builder;
|
||||
|
||||
builder.setTableName(m_tableName.clone());
|
||||
builder.setUseWithoutRowId(m_withoutRowId);
|
||||
builder.setUseIfNotExists(m_useIfNotExists);
|
||||
builder.setColumns(m_sqliteColumns);
|
||||
|
||||
database.execute(builder.sqlStatement());
|
||||
|
||||
m_isReady = true;
|
||||
|
||||
} catch (const SqliteException &exception) {
|
||||
exception.printWarning();
|
||||
}
|
||||
}
|
||||
|
||||
friend bool operator==(const SqliteTable &first, const SqliteTable &second)
|
||||
{
|
||||
return first.m_tableName == second.m_tableName
|
||||
&& &first.m_sqliteDatabase == &second.m_sqliteDatabase
|
||||
&& first.m_withoutRowId == second.m_withoutRowId
|
||||
&& first.m_useIfNotExists == second.m_useIfNotExists
|
||||
&& first.m_isReady == second.m_isReady
|
||||
&& first.m_sqliteColumns == second.m_sqliteColumns;
|
||||
}
|
||||
@@ -93,8 +113,8 @@ public:
|
||||
private:
|
||||
Utils::SmallString m_tableName;
|
||||
SqliteColumns m_sqliteColumns;
|
||||
SqliteDatabase &m_sqliteDatabase;
|
||||
bool m_withoutRowId = false;
|
||||
bool m_useIfNotExists = false;
|
||||
bool m_isReady = false;
|
||||
};
|
||||
|
||||
|
@@ -31,44 +31,4 @@
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
SqliteAbstractTransaction::~SqliteAbstractTransaction()
|
||||
{
|
||||
if (!m_isAlreadyCommited)
|
||||
m_databaseBackend.execute("ROLLBACK");
|
||||
}
|
||||
|
||||
void SqliteAbstractTransaction::commit()
|
||||
{
|
||||
m_databaseBackend.execute("COMMIT");
|
||||
m_isAlreadyCommited = true;
|
||||
}
|
||||
|
||||
SqliteAbstractTransaction::SqliteAbstractTransaction(SqliteDatabaseBackend &backend)
|
||||
: m_databaseBackend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
SqliteAbstractTransaction::SqliteAbstractTransaction(SqliteDatabase &database)
|
||||
: SqliteAbstractTransaction(database.backend())
|
||||
{
|
||||
}
|
||||
|
||||
SqliteTransaction::SqliteTransaction(SqliteDatabase &database)
|
||||
: SqliteAbstractTransaction(database)
|
||||
{
|
||||
m_databaseBackend.execute("BEGIN");
|
||||
}
|
||||
|
||||
SqliteImmediateTransaction::SqliteImmediateTransaction(SqliteDatabase &database)
|
||||
: SqliteAbstractTransaction(database)
|
||||
{
|
||||
m_databaseBackend.execute("BEGIN IMMEDIATE");
|
||||
}
|
||||
|
||||
SqliteExclusiveTransaction::SqliteExclusiveTransaction(SqliteDatabase &database)
|
||||
: SqliteAbstractTransaction(database)
|
||||
{
|
||||
m_databaseBackend.execute("BEGIN EXCLUSIVE");
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -32,43 +32,66 @@ namespace Sqlite {
|
||||
class SqliteDatabaseBackend;
|
||||
class SqliteDatabase;
|
||||
|
||||
class SQLITE_EXPORT SqliteAbstractTransaction
|
||||
template <typename Database>
|
||||
class SqliteAbstractTransaction
|
||||
{
|
||||
public:
|
||||
virtual ~SqliteAbstractTransaction();
|
||||
virtual ~SqliteAbstractTransaction()
|
||||
{
|
||||
if (!m_isAlreadyCommited)
|
||||
m_database.execute("ROLLBACK");
|
||||
}
|
||||
|
||||
void commit();
|
||||
void commit()
|
||||
{
|
||||
m_database.execute("COMMIT");
|
||||
m_isAlreadyCommited = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
SqliteAbstractTransaction(SqliteDatabaseBackend &backend);
|
||||
SqliteAbstractTransaction(SqliteDatabase &database);
|
||||
|
||||
protected:
|
||||
SqliteDatabaseBackend &m_databaseBackend;
|
||||
SqliteAbstractTransaction(Database &database)
|
||||
: m_database(database)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Database &m_database;
|
||||
bool m_isAlreadyCommited = false;
|
||||
};
|
||||
|
||||
|
||||
class SQLITE_EXPORT SqliteTransaction final : public SqliteAbstractTransaction
|
||||
template <typename Database>
|
||||
class SqliteTransaction final : public SqliteAbstractTransaction<Database>
|
||||
{
|
||||
public:
|
||||
SqliteTransaction(SqliteDatabase &database);
|
||||
SqliteTransaction(Database &database)
|
||||
: SqliteAbstractTransaction<Database>(database)
|
||||
{
|
||||
database.execute("BEGIN");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class SQLITE_EXPORT SqliteImmediateTransaction final : public SqliteAbstractTransaction
|
||||
template <typename Database>
|
||||
class SqliteImmediateTransaction final : public SqliteAbstractTransaction<Database>
|
||||
{
|
||||
public:
|
||||
SqliteImmediateTransaction(SqliteDatabase &database);
|
||||
SqliteImmediateTransaction(Database &database)
|
||||
: SqliteAbstractTransaction<Database>(database)
|
||||
{
|
||||
database.execute("BEGIN IMMEDIATE");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class SQLITE_EXPORT SqliteExclusiveTransaction final : public SqliteAbstractTransaction
|
||||
template <typename Database>
|
||||
class SqliteExclusiveTransaction final : public SqliteAbstractTransaction<Database>
|
||||
{
|
||||
public:
|
||||
SqliteExclusiveTransaction(SqliteDatabase &database);
|
||||
SqliteExclusiveTransaction(Database &database)
|
||||
: SqliteAbstractTransaction<Database>(database)
|
||||
{
|
||||
database.execute("BEGIN EXCLUSIVE");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@@ -33,7 +33,7 @@
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
SqlStatementBuilder::SqlStatementBuilder(Utils::SmallString &&sqlTemplate)
|
||||
SqlStatementBuilder::SqlStatementBuilder(Utils::SmallStringView sqlTemplate)
|
||||
: m_sqlTemplate(std::move(sqlTemplate))
|
||||
{
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ class SQLITE_EXPORT SqlStatementBuilder
|
||||
{
|
||||
using BindingPair = std::pair<Utils::SmallString, Utils::SmallString>;
|
||||
public:
|
||||
SqlStatementBuilder(Utils::SmallString &&m_sqlTemplate);
|
||||
SqlStatementBuilder(Utils::SmallStringView m_sqlTemplate);
|
||||
|
||||
void bindEmptyText(Utils::SmallString &&name);
|
||||
void bind(Utils::SmallString &&name, Utils::SmallString &&text);
|
||||
@@ -79,8 +79,8 @@ protected:
|
||||
Q_NORETURN static void throwException(const char *whatHasHappened, const char *errorMessage);
|
||||
|
||||
private:
|
||||
Utils::SmallString m_sqlTemplate;
|
||||
mutable Utils::SmallString m_sqlStatement;
|
||||
Utils::BasicSmallString<510> m_sqlTemplate;
|
||||
mutable Utils::BasicSmallString<510> m_sqlStatement;
|
||||
mutable std::vector<BindingPair> m_bindings;
|
||||
};
|
||||
|
||||
|
@@ -30,6 +30,10 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::Contraint;
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::OpenMode;
|
||||
using Sqlite::SqliteColumn;
|
||||
using Sqlite::SqliteColumns;
|
||||
|
||||
@@ -81,7 +85,7 @@ TEST_F(CreateTableSqlStatementBuilder, SqlStatement)
|
||||
bindValues();
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)");
|
||||
"CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
|
||||
@@ -91,17 +95,17 @@ TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
|
||||
builder.addColumn("number2", ColumnType::Real);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC, number2 REAL)");
|
||||
"CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC, number2 REAL)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, ChangeTable)
|
||||
{
|
||||
bindValues();
|
||||
|
||||
builder.setTable("test2");
|
||||
builder.setTableName("test2");
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test2(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"
|
||||
"CREATE TABLE test2(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,7 +128,7 @@ TEST_F(CreateTableSqlStatementBuilder, ClearColumnsAndAddColumnNewColumns)
|
||||
builder.addColumn("number3", ColumnType::Real);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(name3 TEXT, number3 REAL)");
|
||||
"CREATE TABLE test(name3 TEXT, number3 REAL)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId)
|
||||
@@ -134,25 +138,60 @@ TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId)
|
||||
builder.setUseWithoutRowId(true);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC) WITHOUT ROWID");
|
||||
"CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC) WITHOUT ROWID");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions)
|
||||
{
|
||||
builder.clear();
|
||||
builder.setTable("test");
|
||||
builder.setTableName("test");
|
||||
|
||||
builder.setColumns(createColumns());
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)");
|
||||
"CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, UniqueContraint)
|
||||
{
|
||||
builder.clear();
|
||||
builder.setTableName("test");
|
||||
|
||||
builder.addColumn("id", ColumnType::Integer, Contraint::Unique);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE test(id INTEGER UNIQUE)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, IfNotExitsModifier)
|
||||
{
|
||||
builder.clear();
|
||||
builder.setTableName("test");
|
||||
builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint);
|
||||
|
||||
builder.setUseIfNotExists(true);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TABLE IF NOT EXISTS test(id INTEGER)");
|
||||
}
|
||||
|
||||
TEST_F(CreateTableSqlStatementBuilder, TemporaryTable)
|
||||
{
|
||||
builder.clear();
|
||||
builder.setTableName("test");
|
||||
builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint);
|
||||
|
||||
builder.setUseTemporaryTable(true);
|
||||
|
||||
ASSERT_THAT(builder.sqlStatement(),
|
||||
"CREATE TEMPORARY TABLE test(id INTEGER)");
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::bindValues()
|
||||
{
|
||||
builder.clear();
|
||||
builder.setTable("test");
|
||||
builder.addColumn("id", ColumnType::Integer, IsPrimaryKey::Yes);
|
||||
builder.setTableName("test");
|
||||
builder.addColumn("id", ColumnType::Integer, Contraint::PrimaryKey);
|
||||
builder.addColumn("name", ColumnType::Text);
|
||||
builder.addColumn("number",ColumnType:: Numeric);
|
||||
}
|
||||
@@ -160,7 +199,7 @@ void CreateTableSqlStatementBuilder::bindValues()
|
||||
SqliteColumns CreateTableSqlStatementBuilder::createColumns()
|
||||
{
|
||||
SqliteColumns columns;
|
||||
columns.emplace_back("id", ColumnType::Integer, IsPrimaryKey::Yes);
|
||||
columns.emplace_back("id", ColumnType::Integer, Contraint::PrimaryKey);
|
||||
columns.emplace_back("name", ColumnType::Text);
|
||||
columns.emplace_back("number", ColumnType::Numeric);
|
||||
|
||||
|
@@ -33,6 +33,10 @@ using testing::AllOf;
|
||||
using testing::Contains;
|
||||
using testing::Property;
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::Contraint;
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::OpenMode;
|
||||
using Column = Sqlite::SqliteColumn;
|
||||
using Sqlite::SqliteColumns;
|
||||
|
||||
@@ -63,16 +67,16 @@ TEST_F(SqliteColumn, ChangeType)
|
||||
ASSERT_THAT(column.type(), ColumnType::Text);
|
||||
}
|
||||
|
||||
TEST_F(SqliteColumn, DefaultPrimaryKey)
|
||||
TEST_F(SqliteColumn, DefaultConstraint)
|
||||
{
|
||||
ASSERT_FALSE(column.isPrimaryKey());
|
||||
ASSERT_THAT(column.constraint(), Contraint::NoConstraint);
|
||||
}
|
||||
|
||||
TEST_F(SqliteColumn, SetPrimaryKey)
|
||||
TEST_F(SqliteColumn, SetConstraint)
|
||||
{
|
||||
column.setIsPrimaryKey(IsPrimaryKey::Yes);
|
||||
column.setContraint(Contraint::PrimaryKey);
|
||||
|
||||
ASSERT_TRUE(column.isPrimaryKey());
|
||||
ASSERT_THAT(column.constraint(), Contraint::PrimaryKey);
|
||||
}
|
||||
|
||||
TEST_F(SqliteColumn, GetColumnDefinition)
|
||||
@@ -83,7 +87,7 @@ TEST_F(SqliteColumn, GetColumnDefinition)
|
||||
AllOf(
|
||||
Property(&Column::name, "Claudia"),
|
||||
Property(&Column::type, ColumnType::Numeric),
|
||||
Property(&Column::isPrimaryKey, false)));
|
||||
Property(&Column::constraint, Contraint::NoConstraint)));
|
||||
}
|
||||
|
||||
void SqliteColumn::SetUp()
|
||||
|
@@ -38,6 +38,9 @@ namespace {
|
||||
|
||||
using testing::Contains;
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::OpenMode;
|
||||
using Sqlite::SqliteTable;
|
||||
|
||||
class SqliteDatabase : public ::testing::Test
|
||||
|
@@ -38,6 +38,11 @@ namespace {
|
||||
|
||||
using Backend = Sqlite::SqliteDatabaseBackend;
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::Contraint;
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::OpenMode;
|
||||
using Sqlite::TextEncoding;
|
||||
using Sqlite::SqliteException;
|
||||
using Sqlite::SqliteWriteStatement;
|
||||
|
||||
@@ -106,35 +111,35 @@ TEST_F(SqliteDatabaseBackend, PersistJournalMode)
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, DefaultTextEncoding)
|
||||
{
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf8);
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf8);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, Utf16TextEncoding)
|
||||
{
|
||||
databaseBackend.setTextEncoding(Utf16);
|
||||
databaseBackend.setTextEncoding(TextEncoding::Utf16);
|
||||
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf16);
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf16);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, Utf16beTextEncoding)
|
||||
{
|
||||
databaseBackend.setTextEncoding(Utf16be);
|
||||
databaseBackend.setTextEncoding(TextEncoding::Utf16be);
|
||||
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf16be);
|
||||
ASSERT_THAT(databaseBackend.textEncoding(),TextEncoding::Utf16be);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, Utf16leTextEncoding)
|
||||
{
|
||||
databaseBackend.setTextEncoding(Utf16le);
|
||||
databaseBackend.setTextEncoding(TextEncoding::Utf16le);
|
||||
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf16le);
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf16le);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, Utf8TextEncoding)
|
||||
{
|
||||
databaseBackend.setTextEncoding(Utf8);
|
||||
databaseBackend.setTextEncoding(TextEncoding::Utf8);
|
||||
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf8);
|
||||
ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf8);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
|
||||
@@ -143,7 +148,7 @@ TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
|
||||
|
||||
databaseBackend.execute("CREATE TABLE text(name, number)");
|
||||
|
||||
ASSERT_THROW(databaseBackend.setTextEncoding(Utf16), SqliteException);
|
||||
ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16), SqliteException);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
|
||||
|
@@ -30,14 +30,15 @@
|
||||
#include <sqlitereadwritestatement.h>
|
||||
#include <sqlitewritestatement.h>
|
||||
|
||||
#include <utils/smallstringio.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
using testing::ElementsAre;
|
||||
using testing::PrintToString;
|
||||
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::SqliteException;
|
||||
using Sqlite::SqliteDatabase;
|
||||
using Sqlite::SqliteReadStatement;
|
||||
@@ -71,6 +72,21 @@ protected:
|
||||
SqliteDatabase database;
|
||||
};
|
||||
|
||||
struct Output
|
||||
{
|
||||
Utils::SmallString name;
|
||||
Utils::SmallString number;
|
||||
long long value;
|
||||
friend bool operator==(const Output &f, const Output &s)
|
||||
{
|
||||
return f.name == s.name && f.number == s.number && f.value == s.value;
|
||||
}
|
||||
friend std::ostream &operator<<(std::ostream &out, const Output &o)
|
||||
{
|
||||
return out << "(" << o.name << ", " << ", " << o.number<< ", " << o.value<< ")";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SqliteStatement, PrepareFailure)
|
||||
{
|
||||
ASSERT_THROW(SqliteReadStatement("blah blah blah", database), SqliteException);
|
||||
@@ -99,11 +115,11 @@ TEST_F(SqliteStatement, Value)
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.value<int>(0), 0);
|
||||
ASSERT_THAT(statement.value<qint64>(0), 0);
|
||||
ASSERT_THAT(statement.value<int64_t>(0), 0);
|
||||
ASSERT_THAT(statement.value<double>(0), 0.0);
|
||||
ASSERT_THAT(statement.text(0), "foo");
|
||||
ASSERT_THAT(statement.value<int>(1), 23);
|
||||
ASSERT_THAT(statement.value<qint64>(1), 23);
|
||||
ASSERT_THAT(statement.value<int64_t>(1), 23);
|
||||
ASSERT_THAT(statement.value<double>(1), 23.3);
|
||||
ASSERT_THAT(statement.text(1), "23.3");
|
||||
}
|
||||
@@ -127,12 +143,14 @@ TEST_F(SqliteStatement, ValueFailure)
|
||||
|
||||
TEST_F(SqliteStatement, ToIntergerValue)
|
||||
{
|
||||
ASSERT_THAT(SqliteReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database), 23);
|
||||
auto value = SqliteReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database);
|
||||
|
||||
ASSERT_THAT(value, 23);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ToLongIntergerValue)
|
||||
{
|
||||
ASSERT_THAT(SqliteReadStatement::toValue<qint64>("SELECT number FROM test WHERE name='foo'", database), 23LL);
|
||||
ASSERT_THAT(SqliteReadStatement::toValue<qint64>("SELECT number FROM test WHERE name='foo'", database), Eq(23));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ToDoubleValue)
|
||||
@@ -145,31 +163,6 @@ TEST_F(SqliteStatement, ToStringValue)
|
||||
ASSERT_THAT(SqliteReadStatement::toValue<Utils::SmallString>("SELECT name FROM test WHERE name='foo'", database), "foo");
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, Utf8Values)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test ORDER by name", database);
|
||||
|
||||
auto values = statement.values<Utils::SmallStringVector>();
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("bar", "foo", "poo"));
|
||||
}
|
||||
TEST_F(SqliteStatement, DoubleValues)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test ORDER by name", database);
|
||||
|
||||
auto values = statement.values<std::vector<double>>(1);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(0.0, 23.3, 40.0));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ValuesFailure)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test", database);
|
||||
|
||||
ASSERT_THROW(statement.values<Utils::SmallStringVector>({1, 2}), SqliteException);
|
||||
ASSERT_THROW(statement.values<Utils::SmallStringVector>({-1, 1}), SqliteException);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ColumnNames)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test", database);
|
||||
@@ -206,7 +199,7 @@ TEST_F(SqliteStatement, BindLongInteger)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test WHERE number=?", database);
|
||||
|
||||
statement.bind(1, qint64(40));
|
||||
statement.bind(1, int64_t(40));
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.text(0), "poo");
|
||||
@@ -236,7 +229,7 @@ TEST_F(SqliteStatement, BindLongIntegerByParameter)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number FROM test WHERE number=@number", database);
|
||||
|
||||
statement.bind("@number", qint64(40));
|
||||
statement.bind("@number", int64_t(40));
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.text(0), "poo");
|
||||
@@ -315,14 +308,156 @@ TEST_F(SqliteStatement, ClosedDatabase)
|
||||
database.open(QDir::tempPath() + QStringLiteral("/SqliteStatementTest.db"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetTupleValuesWithoutArguments)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, double, int>;
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test", database);
|
||||
|
||||
auto values = statement.tupleValues<Utils::SmallString, double, int>(3);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"bar", 0, 1},
|
||||
Tuple{"foo", 23.3, 2},
|
||||
Tuple{"poo", 40.0, 3}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name FROM test", database);
|
||||
|
||||
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("bar", "foo", "poo"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test", database);
|
||||
|
||||
auto values = statement.structValues<Output, Utils::SmallString, Utils::SmallString, long long>(3);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1},
|
||||
Output{"foo", "23.3", 2},
|
||||
Output{"poo", "40", 3}));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name FROM test WHERE number=?", database);
|
||||
statement.values<Utils::SmallString>(3, 40);
|
||||
|
||||
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3, 40);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("poo"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, double, double>;
|
||||
std::vector<double> queryValues = {40, 23.3};
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database);
|
||||
|
||||
auto values = statement.tupleValues<Utils::SmallString, double, double>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"poo", 40, 3.},
|
||||
Tuple{"foo", 23.3, 2.}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues)
|
||||
{
|
||||
std::vector<double> queryValues = {40, 23.3};
|
||||
SqliteReadStatement statement("SELECT name, number FROM test WHERE number=?", database);
|
||||
|
||||
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("poo", "foo"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleValues)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, int>;
|
||||
using Tuple2 = std::tuple<Utils::SmallString, double, int>;
|
||||
std::vector<Tuple> queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}};
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database);
|
||||
|
||||
auto values = statement.tupleValues<Utils::SmallString, double, int>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple2{"poo", 40, 3},
|
||||
Tuple2{"bar", 0, 1}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValues)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString>;
|
||||
std::vector<Tuple> queryValues = {{"poo", "40"}, {"bar", "blah"}};
|
||||
SqliteReadStatement statement("SELECT name, number FROM test WHERE name= ? AND number=?", database);
|
||||
|
||||
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("poo", "bar"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
|
||||
|
||||
auto values = statement.tupleValues<Utils::SmallString, Utils::SmallString, long long>(3, "bar", "blah", 1);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValueMultipleTimes)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=?", database);
|
||||
statement.tupleValues<Utils::SmallString, Utils::SmallString, long long>(3, "bar", "blah");
|
||||
|
||||
auto values = statement.tupleValues<Utils::SmallString, Utils::SmallString, long long>(3, "bar", "blah");
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetStructOutputValuesAndMultipleQueryValue)
|
||||
{
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
|
||||
|
||||
auto values = statement.structValues<Output, Utils::SmallString, Utils::SmallString, long long>(3, "bar", "blah", 1);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryValues)
|
||||
{
|
||||
std::vector<double> queryValues = {40, 23.3};
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database);
|
||||
|
||||
auto values = statement.structValues<Output, Utils::SmallString, Utils::SmallString, long long>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3},
|
||||
Output{"foo", "23.3", 2}));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues)
|
||||
{
|
||||
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, int>;
|
||||
std::vector<Tuple> queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}};
|
||||
SqliteReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database);
|
||||
|
||||
auto values = statement.structValues<Output, Utils::SmallString, Utils::SmallString, long long>(3, queryValues);
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3},
|
||||
Output{"bar", "blah", 1}));
|
||||
}
|
||||
|
||||
void SqliteStatement::SetUp()
|
||||
{
|
||||
database.setJournalMode(JournalMode::Memory);
|
||||
database.open(":memory:");
|
||||
database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC)");
|
||||
database.execute("INSERT INTO test VALUES ('bar', 'blah')");
|
||||
database.execute("INSERT INTO test VALUES ('foo', 23.3)");
|
||||
database.execute("INSERT INTO test VALUES ('poo', 40)");
|
||||
database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)");
|
||||
database.execute("INSERT INTO test VALUES ('bar', 'blah', 1)");
|
||||
database.execute("INSERT INTO test VALUES ('foo', 23.3, 2)");
|
||||
database.execute("INSERT INTO test VALUES ('poo', 40, 3)");
|
||||
}
|
||||
|
||||
void SqliteStatement::TearDown()
|
||||
|
@@ -32,6 +32,9 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::JournalMode;
|
||||
using Sqlite::OpenMode;
|
||||
using Sqlite::SqliteColumn;
|
||||
using Sqlite::SqliteDatabase;
|
||||
|
||||
|
@@ -30,6 +30,7 @@
|
||||
|
||||
using namespace ::testing;
|
||||
|
||||
using Sqlite::ColumnType;
|
||||
using Sqlite::SqlStatementBuilder;
|
||||
using Sqlite::SqlStatementBuilderException;
|
||||
|
||||
|
Reference in New Issue
Block a user