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 {
|
namespace Sqlite {
|
||||||
|
|
||||||
CreateTableSqlStatementBuilder::CreateTableSqlStatementBuilder()
|
CreateTableSqlStatementBuilder::CreateTableSqlStatementBuilder()
|
||||||
: m_sqlStatementBuilder("CREATE TABLE IF NOT EXISTS $table($columnDefinitions)$withoutRowId"),
|
: m_sqlStatementBuilder("CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId")
|
||||||
m_useWithoutRowId(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName)
|
void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName)
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
m_sqlStatementBuilder.clear();
|
||||||
|
|
||||||
@@ -42,11 +41,11 @@ void CreateTableSqlStatementBuilder::setTable(Utils::SmallString &&tableName)
|
|||||||
|
|
||||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
IsPrimaryKey isPrimaryKey)
|
Contraint constraint)
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
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)
|
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
|
||||||
@@ -61,6 +60,16 @@ void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId)
|
|||||||
m_useWithoutRowId = useWithoutRowId;
|
m_useWithoutRowId = useWithoutRowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreateTableSqlStatementBuilder::setUseIfNotExists(bool useIfNotExists)
|
||||||
|
{
|
||||||
|
m_useIfNotExits = useIfNotExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateTableSqlStatementBuilder::setUseTemporaryTable(bool useTemporaryTable)
|
||||||
|
{
|
||||||
|
m_useTemporaryTable = useTemporaryTable;
|
||||||
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::clear()
|
void CreateTableSqlStatementBuilder::clear()
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
m_sqlStatementBuilder.clear();
|
||||||
@@ -95,8 +104,11 @@ void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
|||||||
for (const SqliteColumn &columns : m_columns) {
|
for (const SqliteColumn &columns : m_columns) {
|
||||||
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
||||||
|
|
||||||
if (columns.isPrimaryKey())
|
switch (columns.constraint()) {
|
||||||
columnDefinitionString.append(" PRIMARY KEY");
|
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break;
|
||||||
|
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break;
|
||||||
|
case Contraint::NoConstraint: break;
|
||||||
|
}
|
||||||
|
|
||||||
columnDefinitionStrings.push_back(columnDefinitionString);
|
columnDefinitionStrings.push_back(columnDefinitionString);
|
||||||
}
|
}
|
||||||
@@ -108,12 +120,34 @@ void CreateTableSqlStatementBuilder::bindAll() const
|
|||||||
{
|
{
|
||||||
m_sqlStatementBuilder.bind("$table", m_tableName.clone());
|
m_sqlStatementBuilder.bind("$table", m_tableName.clone());
|
||||||
|
|
||||||
|
bindTemporary();
|
||||||
|
bindIfNotExists();
|
||||||
bindColumnDefinitions();
|
bindColumnDefinitions();
|
||||||
|
bindWithoutRowId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateTableSqlStatementBuilder::bindWithoutRowId() const
|
||||||
|
{
|
||||||
if (m_useWithoutRowId)
|
if (m_useWithoutRowId)
|
||||||
m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID");
|
m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID");
|
||||||
else
|
else
|
||||||
m_sqlStatementBuilder.bindEmptyText("$withoutRowId");
|
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
|
} // namespace Sqlite
|
||||||
|
@@ -35,12 +35,14 @@ class SQLITE_EXPORT CreateTableSqlStatementBuilder
|
|||||||
public:
|
public:
|
||||||
CreateTableSqlStatementBuilder();
|
CreateTableSqlStatementBuilder();
|
||||||
|
|
||||||
void setTable(Utils::SmallString &&tableName);
|
void setTableName(Utils::SmallString &&tableName);
|
||||||
void addColumn(Utils::SmallString &&columnName,
|
void addColumn(Utils::SmallString &&columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No);
|
Contraint constraint = Contraint::NoConstraint);
|
||||||
void setColumns(const SqliteColumns &columns);
|
void setColumns(const SqliteColumns &columns);
|
||||||
void setUseWithoutRowId(bool useWithoutRowId);
|
void setUseWithoutRowId(bool useWithoutRowId);
|
||||||
|
void setUseIfNotExists(bool useIfNotExists);
|
||||||
|
void setUseTemporaryTable(bool useTemporaryTable);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void clearColumns();
|
void clearColumns();
|
||||||
@@ -52,12 +54,17 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void bindColumnDefinitions() const;
|
void bindColumnDefinitions() const;
|
||||||
void bindAll() const;
|
void bindAll() const;
|
||||||
|
void bindWithoutRowId() const;
|
||||||
|
void bindIfNotExists() const;
|
||||||
|
void bindTemporary() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
||||||
Utils::SmallString m_tableName;
|
Utils::SmallString m_tableName;
|
||||||
SqliteColumns m_columns;
|
SqliteColumns m_columns;
|
||||||
bool m_useWithoutRowId;
|
bool m_useWithoutRowId = false;
|
||||||
|
bool m_useIfNotExits = false;
|
||||||
|
bool m_useTemporaryTable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -38,17 +38,17 @@ public:
|
|||||||
|
|
||||||
SqliteColumn(Utils::SmallString &&name,
|
SqliteColumn(Utils::SmallString &&name,
|
||||||
ColumnType type = ColumnType::Numeric,
|
ColumnType type = ColumnType::Numeric,
|
||||||
IsPrimaryKey isPrimaryKey = IsPrimaryKey::No)
|
Contraint constraint = Contraint::NoConstraint)
|
||||||
: m_name(std::move(name)),
|
: m_name(std::move(name)),
|
||||||
m_type(type),
|
m_type(type),
|
||||||
m_isPrimaryKey(isPrimaryKey)
|
m_constraint(constraint)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
m_name.clear();
|
m_name.clear();
|
||||||
m_type = ColumnType::Numeric;
|
m_type = ColumnType::Numeric;
|
||||||
m_isPrimaryKey = IsPrimaryKey::No;
|
m_constraint = Contraint::NoConstraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setName(Utils::SmallString &&newName)
|
void setName(Utils::SmallString &&newName)
|
||||||
@@ -71,14 +71,14 @@ public:
|
|||||||
return m_type;
|
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
|
Utils::SmallString typeString() const
|
||||||
@@ -98,13 +98,13 @@ public:
|
|||||||
{
|
{
|
||||||
return first.m_name == second.m_name
|
return first.m_name == second.m_name
|
||||||
&& first.m_type == second.m_type
|
&& first.m_type == second.m_type
|
||||||
&& first.m_isPrimaryKey == second.m_isPrimaryKey;
|
&& first.m_constraint == second.m_constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Utils::SmallString m_name;
|
Utils::SmallString m_name;
|
||||||
ColumnType m_type = ColumnType::Numeric;
|
ColumnType m_type = ColumnType::Numeric;
|
||||||
IsPrimaryKey m_isPrimaryKey = IsPrimaryKey::No;
|
Contraint m_constraint = Contraint::NoConstraint;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SqliteColumns = std::vector<SqliteColumn>;
|
using SqliteColumns = std::vector<SqliteColumn>;
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "sqlitedatabase.h"
|
#include "sqlitedatabase.h"
|
||||||
|
|
||||||
#include "sqlitetable.h"
|
#include "sqlitetable.h"
|
||||||
|
#include "sqlitetransaction.h"
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
@@ -34,6 +35,12 @@ SqliteDatabase::SqliteDatabase()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SqliteDatabase::SqliteDatabase(Utils::PathString &&databaseFilePath)
|
||||||
|
: m_databaseBackend(*this)
|
||||||
|
{
|
||||||
|
open(std::move(databaseFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
void SqliteDatabase::open()
|
void SqliteDatabase::open()
|
||||||
{
|
{
|
||||||
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
||||||
@@ -61,7 +68,7 @@ bool SqliteDatabase::isOpen() const
|
|||||||
|
|
||||||
SqliteTable &SqliteDatabase::addTable()
|
SqliteTable &SqliteDatabase::addTable()
|
||||||
{
|
{
|
||||||
m_sqliteTables.emplace_back(*this);
|
m_sqliteTables.emplace_back();
|
||||||
|
|
||||||
return m_sqliteTables.back();
|
return m_sqliteTables.back();
|
||||||
}
|
}
|
||||||
@@ -118,8 +125,12 @@ void SqliteDatabase::execute(Utils::SmallStringView sqlStatement)
|
|||||||
|
|
||||||
void SqliteDatabase::initializeTables()
|
void SqliteDatabase::initializeTables()
|
||||||
{
|
{
|
||||||
|
SqliteImmediateTransaction<SqliteDatabase> transaction(*this);
|
||||||
|
|
||||||
for (SqliteTable &table : m_sqliteTables)
|
for (SqliteTable &table : m_sqliteTables)
|
||||||
table.initialize();
|
table.initialize(*this);
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
SqliteDatabaseBackend &SqliteDatabase::backend()
|
SqliteDatabaseBackend &SqliteDatabase::backend()
|
||||||
|
@@ -37,12 +37,14 @@ namespace Sqlite {
|
|||||||
|
|
||||||
class SQLITE_EXPORT SqliteDatabase
|
class SQLITE_EXPORT SqliteDatabase
|
||||||
{
|
{
|
||||||
|
template <typename Database>
|
||||||
friend class SqliteAbstractTransaction;
|
friend class SqliteAbstractTransaction;
|
||||||
friend class SqliteStatement;
|
friend class SqliteStatement;
|
||||||
friend class SqliteBackend;
|
friend class SqliteBackend;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SqliteDatabase();
|
SqliteDatabase();
|
||||||
|
SqliteDatabase(Utils::PathString &&databaseFilePath);
|
||||||
|
|
||||||
SqliteDatabase(const SqliteDatabase &) = delete;
|
SqliteDatabase(const SqliteDatabase &) = delete;
|
||||||
bool operator=(const SqliteDatabase &) = delete;
|
bool operator=(const SqliteDatabase &) = delete;
|
||||||
|
@@ -38,14 +38,6 @@
|
|||||||
|
|
||||||
#include "sqlite3.h"
|
#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 {
|
namespace Sqlite {
|
||||||
|
|
||||||
SqliteDatabaseBackend::SqliteDatabaseBackend(SqliteDatabase &database)
|
SqliteDatabaseBackend::SqliteDatabaseBackend(SqliteDatabase &database)
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
# define SQLITE_EXPORT Q_DECL_IMPORT
|
# define SQLITE_EXPORT Q_DECL_IMPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
enum class ColumnType : char
|
enum class ColumnType : char
|
||||||
{
|
{
|
||||||
Numeric,
|
Numeric,
|
||||||
@@ -46,10 +48,11 @@ enum class ColumnType : char
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IsPrimaryKey : char
|
enum class Contraint : char
|
||||||
{
|
{
|
||||||
No,
|
NoConstraint,
|
||||||
Yes
|
PrimaryKey,
|
||||||
|
Unique
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ColumnConstraint : char
|
enum class ColumnConstraint : char
|
||||||
@@ -84,3 +87,5 @@ enum TextEncoding : char
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
||||||
|
@@ -37,6 +37,8 @@ public:
|
|||||||
using SqliteStatement::next;
|
using SqliteStatement::next;
|
||||||
using SqliteStatement::reset;
|
using SqliteStatement::reset;
|
||||||
using SqliteStatement::value;
|
using SqliteStatement::value;
|
||||||
|
using SqliteStatement::structValues;
|
||||||
|
using SqliteStatement::tupleValues;
|
||||||
using SqliteStatement::text;
|
using SqliteStatement::text;
|
||||||
using SqliteStatement::values;
|
using SqliteStatement::values;
|
||||||
using SqliteStatement::columnCount;
|
using SqliteStatement::columnCount;
|
||||||
|
@@ -48,6 +48,8 @@ public:
|
|||||||
using SqliteStatement::value;
|
using SqliteStatement::value;
|
||||||
using SqliteStatement::text;
|
using SqliteStatement::text;
|
||||||
using SqliteStatement::values;
|
using SqliteStatement::values;
|
||||||
|
using SqliteStatement::structValues;
|
||||||
|
using SqliteStatement::tupleValues;
|
||||||
using SqliteStatement::columnCount;
|
using SqliteStatement::columnCount;
|
||||||
using SqliteStatement::columnNames;
|
using SqliteStatement::columnNames;
|
||||||
using SqliteStatement::toValue;
|
using SqliteStatement::toValue;
|
||||||
|
@@ -29,13 +29,11 @@
|
|||||||
#include "sqlitedatabasebackend.h"
|
#include "sqlitedatabasebackend.h"
|
||||||
#include "sqliteexception.h"
|
#include "sqliteexception.h"
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QWaitCondition>
|
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||||
#endif
|
#endif
|
||||||
@@ -61,8 +59,8 @@ void SqliteStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement)
|
|||||||
sqlite3_finalize(compiledStatement);
|
sqlite3_finalize(compiledStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnlockNotification {
|
class UnlockNotification
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
static void unlockNotifyCallBack(void **arguments, int argumentCount)
|
static void unlockNotifyCallBack(void **arguments, int argumentCount)
|
||||||
{
|
{
|
||||||
@@ -74,27 +72,24 @@ public:
|
|||||||
|
|
||||||
void wakeupWaitCondition()
|
void wakeupWaitCondition()
|
||||||
{
|
{
|
||||||
mutex.lock();
|
{
|
||||||
fired = 1;
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
waitCondition.wakeAll();
|
m_fired = 1;
|
||||||
mutex.unlock();
|
}
|
||||||
|
m_waitCondition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait()
|
void wait()
|
||||||
{
|
{
|
||||||
mutex.lock();
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!fired) {
|
m_waitCondition.wait(lock, [&] () { return m_fired; });
|
||||||
waitCondition.wait(&mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fired = false;
|
bool m_fired = false;
|
||||||
QWaitCondition waitCondition;
|
std::condition_variable m_waitCondition;
|
||||||
QMutex mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SqliteStatement::waitForUnlockNotify() const
|
void SqliteStatement::waitForUnlockNotify() const
|
||||||
@@ -143,6 +138,7 @@ void SqliteStatement::step() const
|
|||||||
void SqliteStatement::execute() const
|
void SqliteStatement::execute() const
|
||||||
{
|
{
|
||||||
next();
|
next();
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SqliteStatement::columnCount() const
|
int SqliteStatement::columnCount() const
|
||||||
@@ -168,7 +164,7 @@ void SqliteStatement::bind(int index, int value)
|
|||||||
throwException("SqliteStatement::bind: cant' bind 32 bit integer!");
|
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);
|
int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value);
|
||||||
if (resultCode != SQLITE_OK)
|
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, 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, double value);
|
||||||
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
||||||
|
|
||||||
@@ -363,21 +360,23 @@ SqliteDatabase &SqliteStatement::database() const
|
|||||||
return m_database;
|
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));
|
const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
|
||||||
std::size_t size = std::size_t(sqlite3_column_bytes(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);
|
int dataType = sqlite3_column_type(sqlStatment, column);
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case SQLITE_INTEGER:
|
case SQLITE_INTEGER:
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
case SQLITE3_TEXT: return textForColumn(sqlStatment, column);
|
case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column);
|
||||||
case SQLITE_BLOB:
|
case SQLITE_BLOB:
|
||||||
case SQLITE_NULL: return {};
|
case SQLITE_NULL: return {};
|
||||||
}
|
}
|
||||||
@@ -394,7 +393,13 @@ int SqliteStatement::value<int>(int column) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
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();
|
checkIfIsReadyToFetchValues();
|
||||||
checkColumnIsValid(column);
|
checkColumnIsValid(column);
|
||||||
@@ -409,14 +414,17 @@ double SqliteStatement::value<double>(int column) const
|
|||||||
return sqlite3_column_double(m_compiledStatement.get(), column);
|
return sqlite3_column_double(m_compiledStatement.get(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<typename StringType>
|
||||||
Utils::SmallString SqliteStatement::value<Utils::SmallString>(int column) const
|
StringType SqliteStatement::value(int column) const
|
||||||
{
|
{
|
||||||
checkIfIsReadyToFetchValues();
|
checkIfIsReadyToFetchValues();
|
||||||
checkColumnIsValid(column);
|
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
|
Utils::SmallString SqliteStatement::text(int column) const
|
||||||
{
|
{
|
||||||
return value<Utils::SmallString>(column);
|
return value<Utils::SmallString>(column);
|
||||||
@@ -434,45 +442,6 @@ ContainerType SqliteStatement::columnValues(const std::vector<int> &columnIndice
|
|||||||
return valueContainer;
|
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>
|
template <typename Type>
|
||||||
Type SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database)
|
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 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 double SqliteStatement::toValue<double>(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||||
template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue<Utils::SmallString>(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 <utils/smallstringvector.h>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
using std::int64_t;
|
||||||
|
|
||||||
struct sqlite3_stmt;
|
struct sqlite3_stmt;
|
||||||
struct sqlite3;
|
struct sqlite3;
|
||||||
@@ -61,31 +65,45 @@ protected:
|
|||||||
Utils::SmallStringVector columnNames() const;
|
Utils::SmallStringVector columnNames() const;
|
||||||
|
|
||||||
void bind(int index, int value);
|
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, double value);
|
||||||
void bind(int index, Utils::SmallStringView value);
|
void bind(int index, Utils::SmallStringView value);
|
||||||
|
|
||||||
template<typename ... Values>
|
void bind(int index, uint value)
|
||||||
void bindValues(Values ... values)
|
{
|
||||||
|
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...);
|
bindValuesByIndex(1, values...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ... Values>
|
template<typename... Values>
|
||||||
void write(Values ... values)
|
void write(Values... values)
|
||||||
{
|
{
|
||||||
bindValuesByIndex(1, values...);
|
bindValuesByIndex(1, values...);
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ... Values>
|
template<typename... Values>
|
||||||
void bindNameValues(Values ... values)
|
void bindNameValues(Values... values)
|
||||||
{
|
{
|
||||||
bindValuesByName(values...);
|
bindValuesByName(values...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ... Values>
|
template<typename... Values>
|
||||||
void writeNamed(Values ... values)
|
void writeNamed(Values... values)
|
||||||
{
|
{
|
||||||
bindValuesByName(values...);
|
bindValuesByName(values...);
|
||||||
execute();
|
execute();
|
||||||
@@ -99,11 +117,231 @@ protected:
|
|||||||
void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames);
|
void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames);
|
||||||
const Utils::SmallStringVector &bindingColumnNames() const;
|
const Utils::SmallStringVector &bindingColumnNames() const;
|
||||||
|
|
||||||
template <typename ContainerType>
|
template <typename... ResultType>
|
||||||
ContainerType values(const std::vector<int> &columns, int size = 0) const;
|
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>
|
while (next())
|
||||||
ContainerType values(int column = 0) const;
|
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>
|
template <typename Type>
|
||||||
static Type toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
static Type toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database);
|
||||||
@@ -141,14 +379,45 @@ protected:
|
|||||||
SqliteDatabaseBackend &databaseBackend);
|
SqliteDatabaseBackend &databaseBackend);
|
||||||
|
|
||||||
private:
|
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>
|
template<typename Type>
|
||||||
void bindValuesByIndex(int index, Type value)
|
void bindValuesByIndex(int index, Type value)
|
||||||
{
|
{
|
||||||
bind(index, value);
|
bind(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type, typename ... Value>
|
template<typename Type, typename... Value>
|
||||||
void bindValuesByIndex(int index, Type value, Value ... values)
|
void bindValuesByIndex(int index, Type value, Value... values)
|
||||||
{
|
{
|
||||||
bind(index, value);
|
bind(index, value);
|
||||||
bindValuesByIndex(index + 1, values...);
|
bindValuesByIndex(index + 1, values...);
|
||||||
@@ -160,13 +429,26 @@ private:
|
|||||||
bind(bindingIndexForName(name), value);
|
bind(bindingIndexForName(name), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type, typename ... Values>
|
template<typename Type, typename... Values>
|
||||||
void bindValuesByName(Utils::SmallStringView name, Type value, Values ... values)
|
void bindValuesByName(Utils::SmallStringView name, Type value, Values... values)
|
||||||
{
|
{
|
||||||
bind(bindingIndexForName(name), value);
|
bind(bindingIndexForName(name), value);
|
||||||
bindValuesByName(values...);
|
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:
|
private:
|
||||||
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement;
|
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement;
|
||||||
Utils::SmallStringVector m_bindingColumnNames;
|
Utils::SmallStringVector m_bindingColumnNames;
|
||||||
@@ -176,4 +458,21 @@ private:
|
|||||||
mutable bool m_isReadyToFetchValues;
|
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
|
} // namespace Sqlite
|
||||||
|
@@ -25,32 +25,8 @@
|
|||||||
|
|
||||||
#include "sqlitetable.h"
|
#include "sqlitetable.h"
|
||||||
|
|
||||||
#include "sqlitecolumn.h"
|
|
||||||
#include "sqlitedatabase.h"
|
|
||||||
#include "createtablesqlstatementbuilder.h"
|
|
||||||
#include "sqlitewritestatement.h"
|
|
||||||
#include "sqlitetransaction.h"
|
|
||||||
|
|
||||||
namespace Sqlite {
|
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
|
} // namespace Sqlite
|
||||||
|
@@ -25,8 +25,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "createtablesqlstatementbuilder.h"
|
||||||
#include "sqliteglobal.h"
|
#include "sqliteglobal.h"
|
||||||
#include "sqlitecolumn.h"
|
#include "sqlitecolumn.h"
|
||||||
|
#include "sqliteexception.h"
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
@@ -35,11 +37,6 @@ class SqliteDatabase;
|
|||||||
class SqliteTable
|
class SqliteTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SqliteTable(SqliteDatabase &m_sqliteDatabase)
|
|
||||||
: m_sqliteDatabase(m_sqliteDatabase)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setName(Utils::SmallString &&name)
|
void setName(Utils::SmallString &&name)
|
||||||
{
|
{
|
||||||
m_tableName = std::move(name);
|
m_tableName = std::move(name);
|
||||||
@@ -60,11 +57,16 @@ public:
|
|||||||
return m_withoutRowId;
|
return m_withoutRowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUseIfNotExists(bool useIfNotExists)
|
||||||
|
{
|
||||||
|
m_useIfNotExists = useIfNotExists;
|
||||||
|
}
|
||||||
|
|
||||||
SqliteColumn &addColumn(Utils::SmallString &&name,
|
SqliteColumn &addColumn(Utils::SmallString &&name,
|
||||||
ColumnType type = ColumnType::Numeric,
|
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();
|
return m_sqliteColumns.back();
|
||||||
}
|
}
|
||||||
@@ -79,13 +81,31 @@ public:
|
|||||||
return m_isReady;
|
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)
|
friend bool operator==(const SqliteTable &first, const SqliteTable &second)
|
||||||
{
|
{
|
||||||
return first.m_tableName == second.m_tableName
|
return first.m_tableName == second.m_tableName
|
||||||
&& &first.m_sqliteDatabase == &second.m_sqliteDatabase
|
|
||||||
&& first.m_withoutRowId == second.m_withoutRowId
|
&& first.m_withoutRowId == second.m_withoutRowId
|
||||||
|
&& first.m_useIfNotExists == second.m_useIfNotExists
|
||||||
&& first.m_isReady == second.m_isReady
|
&& first.m_isReady == second.m_isReady
|
||||||
&& first.m_sqliteColumns == second.m_sqliteColumns;
|
&& first.m_sqliteColumns == second.m_sqliteColumns;
|
||||||
}
|
}
|
||||||
@@ -93,8 +113,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
Utils::SmallString m_tableName;
|
Utils::SmallString m_tableName;
|
||||||
SqliteColumns m_sqliteColumns;
|
SqliteColumns m_sqliteColumns;
|
||||||
SqliteDatabase &m_sqliteDatabase;
|
|
||||||
bool m_withoutRowId = false;
|
bool m_withoutRowId = false;
|
||||||
|
bool m_useIfNotExists = false;
|
||||||
bool m_isReady = false;
|
bool m_isReady = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -31,44 +31,4 @@
|
|||||||
|
|
||||||
namespace Sqlite {
|
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
|
} // namespace Sqlite
|
||||||
|
@@ -32,43 +32,66 @@ namespace Sqlite {
|
|||||||
class SqliteDatabaseBackend;
|
class SqliteDatabaseBackend;
|
||||||
class SqliteDatabase;
|
class SqliteDatabase;
|
||||||
|
|
||||||
class SQLITE_EXPORT SqliteAbstractTransaction
|
template <typename Database>
|
||||||
|
class SqliteAbstractTransaction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~SqliteAbstractTransaction();
|
virtual ~SqliteAbstractTransaction()
|
||||||
|
{
|
||||||
|
if (!m_isAlreadyCommited)
|
||||||
|
m_database.execute("ROLLBACK");
|
||||||
|
}
|
||||||
|
|
||||||
void commit();
|
void commit()
|
||||||
|
{
|
||||||
|
m_database.execute("COMMIT");
|
||||||
|
m_isAlreadyCommited = true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SqliteAbstractTransaction(SqliteDatabaseBackend &backend);
|
SqliteAbstractTransaction(Database &database)
|
||||||
SqliteAbstractTransaction(SqliteDatabase &database);
|
: m_database(database)
|
||||||
|
{
|
||||||
protected:
|
}
|
||||||
SqliteDatabaseBackend &m_databaseBackend;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Database &m_database;
|
||||||
bool m_isAlreadyCommited = false;
|
bool m_isAlreadyCommited = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Database>
|
||||||
class SQLITE_EXPORT SqliteTransaction final : public SqliteAbstractTransaction
|
class SqliteTransaction final : public SqliteAbstractTransaction<Database>
|
||||||
{
|
{
|
||||||
public:
|
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:
|
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:
|
public:
|
||||||
SqliteExclusiveTransaction(SqliteDatabase &database);
|
SqliteExclusiveTransaction(Database &database)
|
||||||
|
: SqliteAbstractTransaction<Database>(database)
|
||||||
|
{
|
||||||
|
database.execute("BEGIN EXCLUSIVE");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
SqlStatementBuilder::SqlStatementBuilder(Utils::SmallString &&sqlTemplate)
|
SqlStatementBuilder::SqlStatementBuilder(Utils::SmallStringView sqlTemplate)
|
||||||
: m_sqlTemplate(std::move(sqlTemplate))
|
: m_sqlTemplate(std::move(sqlTemplate))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ class SQLITE_EXPORT SqlStatementBuilder
|
|||||||
{
|
{
|
||||||
using BindingPair = std::pair<Utils::SmallString, Utils::SmallString>;
|
using BindingPair = std::pair<Utils::SmallString, Utils::SmallString>;
|
||||||
public:
|
public:
|
||||||
SqlStatementBuilder(Utils::SmallString &&m_sqlTemplate);
|
SqlStatementBuilder(Utils::SmallStringView m_sqlTemplate);
|
||||||
|
|
||||||
void bindEmptyText(Utils::SmallString &&name);
|
void bindEmptyText(Utils::SmallString &&name);
|
||||||
void bind(Utils::SmallString &&name, Utils::SmallString &&text);
|
void bind(Utils::SmallString &&name, Utils::SmallString &&text);
|
||||||
@@ -79,8 +79,8 @@ protected:
|
|||||||
Q_NORETURN static void throwException(const char *whatHasHappened, const char *errorMessage);
|
Q_NORETURN static void throwException(const char *whatHasHappened, const char *errorMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Utils::SmallString m_sqlTemplate;
|
Utils::BasicSmallString<510> m_sqlTemplate;
|
||||||
mutable Utils::SmallString m_sqlStatement;
|
mutable Utils::BasicSmallString<510> m_sqlStatement;
|
||||||
mutable std::vector<BindingPair> m_bindings;
|
mutable std::vector<BindingPair> m_bindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -30,6 +30,10 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::Contraint;
|
||||||
|
using Sqlite::JournalMode;
|
||||||
|
using Sqlite::OpenMode;
|
||||||
using Sqlite::SqliteColumn;
|
using Sqlite::SqliteColumn;
|
||||||
using Sqlite::SqliteColumns;
|
using Sqlite::SqliteColumns;
|
||||||
|
|
||||||
@@ -81,7 +85,7 @@ TEST_F(CreateTableSqlStatementBuilder, SqlStatement)
|
|||||||
bindValues();
|
bindValues();
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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)
|
TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
|
||||||
@@ -91,17 +95,17 @@ TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
|
|||||||
builder.addColumn("number2", ColumnType::Real);
|
builder.addColumn("number2", ColumnType::Real);
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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)
|
TEST_F(CreateTableSqlStatementBuilder, ChangeTable)
|
||||||
{
|
{
|
||||||
bindValues();
|
bindValues();
|
||||||
|
|
||||||
builder.setTable("test2");
|
builder.setTableName("test2");
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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);
|
builder.addColumn("number3", ColumnType::Real);
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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)
|
TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId)
|
||||||
@@ -134,25 +138,60 @@ TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId)
|
|||||||
builder.setUseWithoutRowId(true);
|
builder.setUseWithoutRowId(true);
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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)
|
TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions)
|
||||||
{
|
{
|
||||||
builder.clear();
|
builder.clear();
|
||||||
builder.setTable("test");
|
builder.setTableName("test");
|
||||||
|
|
||||||
builder.setColumns(createColumns());
|
builder.setColumns(createColumns());
|
||||||
|
|
||||||
ASSERT_THAT(builder.sqlStatement(),
|
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()
|
void CreateTableSqlStatementBuilder::bindValues()
|
||||||
{
|
{
|
||||||
builder.clear();
|
builder.clear();
|
||||||
builder.setTable("test");
|
builder.setTableName("test");
|
||||||
builder.addColumn("id", ColumnType::Integer, IsPrimaryKey::Yes);
|
builder.addColumn("id", ColumnType::Integer, Contraint::PrimaryKey);
|
||||||
builder.addColumn("name", ColumnType::Text);
|
builder.addColumn("name", ColumnType::Text);
|
||||||
builder.addColumn("number",ColumnType:: Numeric);
|
builder.addColumn("number",ColumnType:: Numeric);
|
||||||
}
|
}
|
||||||
@@ -160,7 +199,7 @@ void CreateTableSqlStatementBuilder::bindValues()
|
|||||||
SqliteColumns CreateTableSqlStatementBuilder::createColumns()
|
SqliteColumns CreateTableSqlStatementBuilder::createColumns()
|
||||||
{
|
{
|
||||||
SqliteColumns columns;
|
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("name", ColumnType::Text);
|
||||||
columns.emplace_back("number", ColumnType::Numeric);
|
columns.emplace_back("number", ColumnType::Numeric);
|
||||||
|
|
||||||
|
@@ -33,6 +33,10 @@ using testing::AllOf;
|
|||||||
using testing::Contains;
|
using testing::Contains;
|
||||||
using testing::Property;
|
using testing::Property;
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::Contraint;
|
||||||
|
using Sqlite::JournalMode;
|
||||||
|
using Sqlite::OpenMode;
|
||||||
using Column = Sqlite::SqliteColumn;
|
using Column = Sqlite::SqliteColumn;
|
||||||
using Sqlite::SqliteColumns;
|
using Sqlite::SqliteColumns;
|
||||||
|
|
||||||
@@ -63,16 +67,16 @@ TEST_F(SqliteColumn, ChangeType)
|
|||||||
ASSERT_THAT(column.type(), ColumnType::Text);
|
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)
|
TEST_F(SqliteColumn, GetColumnDefinition)
|
||||||
@@ -83,7 +87,7 @@ TEST_F(SqliteColumn, GetColumnDefinition)
|
|||||||
AllOf(
|
AllOf(
|
||||||
Property(&Column::name, "Claudia"),
|
Property(&Column::name, "Claudia"),
|
||||||
Property(&Column::type, ColumnType::Numeric),
|
Property(&Column::type, ColumnType::Numeric),
|
||||||
Property(&Column::isPrimaryKey, false)));
|
Property(&Column::constraint, Contraint::NoConstraint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SqliteColumn::SetUp()
|
void SqliteColumn::SetUp()
|
||||||
|
@@ -38,6 +38,9 @@ namespace {
|
|||||||
|
|
||||||
using testing::Contains;
|
using testing::Contains;
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::JournalMode;
|
||||||
|
using Sqlite::OpenMode;
|
||||||
using Sqlite::SqliteTable;
|
using Sqlite::SqliteTable;
|
||||||
|
|
||||||
class SqliteDatabase : public ::testing::Test
|
class SqliteDatabase : public ::testing::Test
|
||||||
|
@@ -38,6 +38,11 @@ namespace {
|
|||||||
|
|
||||||
using Backend = Sqlite::SqliteDatabaseBackend;
|
using Backend = Sqlite::SqliteDatabaseBackend;
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::Contraint;
|
||||||
|
using Sqlite::JournalMode;
|
||||||
|
using Sqlite::OpenMode;
|
||||||
|
using Sqlite::TextEncoding;
|
||||||
using Sqlite::SqliteException;
|
using Sqlite::SqliteException;
|
||||||
using Sqlite::SqliteWriteStatement;
|
using Sqlite::SqliteWriteStatement;
|
||||||
|
|
||||||
@@ -106,35 +111,35 @@ TEST_F(SqliteDatabaseBackend, PersistJournalMode)
|
|||||||
|
|
||||||
TEST_F(SqliteDatabaseBackend, DefaultTextEncoding)
|
TEST_F(SqliteDatabaseBackend, DefaultTextEncoding)
|
||||||
{
|
{
|
||||||
ASSERT_THAT(databaseBackend.textEncoding(), Utf8);
|
ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SqliteDatabaseBackend, Utf16TextEncoding)
|
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)
|
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)
|
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)
|
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)
|
TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
|
||||||
@@ -143,7 +148,7 @@ TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
|
|||||||
|
|
||||||
databaseBackend.execute("CREATE TABLE text(name, number)");
|
databaseBackend.execute("CREATE TABLE text(name, number)");
|
||||||
|
|
||||||
ASSERT_THROW(databaseBackend.setTextEncoding(Utf16), SqliteException);
|
ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16), SqliteException);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
|
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
|
||||||
|
@@ -30,14 +30,15 @@
|
|||||||
#include <sqlitereadwritestatement.h>
|
#include <sqlitereadwritestatement.h>
|
||||||
#include <sqlitewritestatement.h>
|
#include <sqlitewritestatement.h>
|
||||||
|
|
||||||
|
#include <utils/smallstringio.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using testing::ElementsAre;
|
|
||||||
using testing::PrintToString;
|
|
||||||
|
|
||||||
|
using Sqlite::JournalMode;
|
||||||
using Sqlite::SqliteException;
|
using Sqlite::SqliteException;
|
||||||
using Sqlite::SqliteDatabase;
|
using Sqlite::SqliteDatabase;
|
||||||
using Sqlite::SqliteReadStatement;
|
using Sqlite::SqliteReadStatement;
|
||||||
@@ -71,6 +72,21 @@ protected:
|
|||||||
SqliteDatabase database;
|
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)
|
TEST_F(SqliteStatement, PrepareFailure)
|
||||||
{
|
{
|
||||||
ASSERT_THROW(SqliteReadStatement("blah blah blah", database), SqliteException);
|
ASSERT_THROW(SqliteReadStatement("blah blah blah", database), SqliteException);
|
||||||
@@ -99,11 +115,11 @@ TEST_F(SqliteStatement, Value)
|
|||||||
statement.next();
|
statement.next();
|
||||||
|
|
||||||
ASSERT_THAT(statement.value<int>(0), 0);
|
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.value<double>(0), 0.0);
|
||||||
ASSERT_THAT(statement.text(0), "foo");
|
ASSERT_THAT(statement.text(0), "foo");
|
||||||
ASSERT_THAT(statement.value<int>(1), 23);
|
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.value<double>(1), 23.3);
|
||||||
ASSERT_THAT(statement.text(1), "23.3");
|
ASSERT_THAT(statement.text(1), "23.3");
|
||||||
}
|
}
|
||||||
@@ -127,12 +143,14 @@ TEST_F(SqliteStatement, ValueFailure)
|
|||||||
|
|
||||||
TEST_F(SqliteStatement, ToIntergerValue)
|
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)
|
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)
|
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");
|
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)
|
TEST_F(SqliteStatement, ColumnNames)
|
||||||
{
|
{
|
||||||
SqliteReadStatement statement("SELECT name, number FROM test", database);
|
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);
|
SqliteReadStatement statement("SELECT name, number FROM test WHERE number=?", database);
|
||||||
|
|
||||||
statement.bind(1, qint64(40));
|
statement.bind(1, int64_t(40));
|
||||||
statement.next();
|
statement.next();
|
||||||
|
|
||||||
ASSERT_THAT(statement.text(0), "poo");
|
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);
|
SqliteReadStatement statement("SELECT name, number FROM test WHERE number=@number", database);
|
||||||
|
|
||||||
statement.bind("@number", qint64(40));
|
statement.bind("@number", int64_t(40));
|
||||||
statement.next();
|
statement.next();
|
||||||
|
|
||||||
ASSERT_THAT(statement.text(0), "poo");
|
ASSERT_THAT(statement.text(0), "poo");
|
||||||
@@ -315,14 +308,156 @@ TEST_F(SqliteStatement, ClosedDatabase)
|
|||||||
database.open(QDir::tempPath() + QStringLiteral("/SqliteStatementTest.db"));
|
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()
|
void SqliteStatement::SetUp()
|
||||||
{
|
{
|
||||||
database.setJournalMode(JournalMode::Memory);
|
database.setJournalMode(JournalMode::Memory);
|
||||||
database.open(":memory:");
|
database.open(":memory:");
|
||||||
database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC)");
|
database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)");
|
||||||
database.execute("INSERT INTO test VALUES ('bar', 'blah')");
|
database.execute("INSERT INTO test VALUES ('bar', 'blah', 1)");
|
||||||
database.execute("INSERT INTO test VALUES ('foo', 23.3)");
|
database.execute("INSERT INTO test VALUES ('foo', 23.3, 2)");
|
||||||
database.execute("INSERT INTO test VALUES ('poo', 40)");
|
database.execute("INSERT INTO test VALUES ('poo', 40, 3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SqliteStatement::TearDown()
|
void SqliteStatement::TearDown()
|
||||||
|
@@ -32,6 +32,9 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::JournalMode;
|
||||||
|
using Sqlite::OpenMode;
|
||||||
using Sqlite::SqliteColumn;
|
using Sqlite::SqliteColumn;
|
||||||
using Sqlite::SqliteDatabase;
|
using Sqlite::SqliteDatabase;
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
using namespace ::testing;
|
using namespace ::testing;
|
||||||
|
|
||||||
|
using Sqlite::ColumnType;
|
||||||
using Sqlite::SqlStatementBuilder;
|
using Sqlite::SqlStatementBuilder;
|
||||||
using Sqlite::SqlStatementBuilderException;
|
using Sqlite::SqlStatementBuilderException;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user