forked from qt-creator/qt-creator
Sqlite: Add change set iterator
Task-number: QDS-2998 Change-Id: I7bfa8af51d9d7e6122902ee132ad51019e20afb5 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -37,12 +37,15 @@ namespace Sqlite {
|
|||||||
class SQLITE_EXPORT Exception : public std::exception
|
class SQLITE_EXPORT Exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Exception(const char *whatErrorHasHappen,
|
Exception(const char *whatErrorHasHappen, Utils::SmallString &&sqliteErrorMessage)
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
|
||||||
: m_whatErrorHasHappen(whatErrorHasHappen)
|
: m_whatErrorHasHappen(whatErrorHasHappen)
|
||||||
, m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
, m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Exception(const char *whatErrorHasHappen)
|
||||||
|
: m_whatErrorHasHappen(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
|
||||||
const char *what() const noexcept override { return m_whatErrorHasHappen; }
|
const char *what() const noexcept override { return m_whatErrorHasHappen; }
|
||||||
|
|
||||||
void printWarning() const;
|
void printWarning() const;
|
||||||
@@ -58,8 +61,7 @@ public:
|
|||||||
StatementIsBusy(const char *whatErrorHasHappen,
|
StatementIsBusy(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseIsBusy : public Exception
|
class DatabaseIsBusy : public Exception
|
||||||
@@ -67,8 +69,7 @@ class DatabaseIsBusy : public Exception
|
|||||||
public:
|
public:
|
||||||
DatabaseIsBusy(const char *whatErrorHasHappen)
|
DatabaseIsBusy(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class StatementHasError : public Exception
|
class StatementHasError : public Exception
|
||||||
@@ -77,8 +78,7 @@ public:
|
|||||||
StatementHasError(const char *whatErrorHasHappen,
|
StatementHasError(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class StatementIsMisused : public Exception
|
class StatementIsMisused : public Exception
|
||||||
@@ -87,8 +87,7 @@ public:
|
|||||||
StatementIsMisused(const char *whatErrorHasHappen,
|
StatementIsMisused(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InputOutputError : public Exception
|
class InputOutputError : public Exception
|
||||||
@@ -96,8 +95,7 @@ class InputOutputError : public Exception
|
|||||||
public:
|
public:
|
||||||
InputOutputError(const char *whatErrorHasHappen)
|
InputOutputError(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConstraintPreventsModification : public Exception
|
class ConstraintPreventsModification : public Exception
|
||||||
@@ -106,8 +104,7 @@ public:
|
|||||||
ConstraintPreventsModification(const char *whatErrorHasHappen,
|
ConstraintPreventsModification(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoValuesToFetch : public Exception
|
class NoValuesToFetch : public Exception
|
||||||
@@ -115,8 +112,7 @@ class NoValuesToFetch : public Exception
|
|||||||
public:
|
public:
|
||||||
NoValuesToFetch(const char *whatErrorHasHappen)
|
NoValuesToFetch(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ColumnCountDoesNotMatch : public Exception
|
class ColumnCountDoesNotMatch : public Exception
|
||||||
@@ -133,8 +129,7 @@ public:
|
|||||||
BindingIndexIsOutOfRange(const char *whatErrorHasHappen,
|
BindingIndexIsOutOfRange(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WrongBindingName : public Exception
|
class WrongBindingName : public Exception
|
||||||
@@ -142,8 +137,7 @@ class WrongBindingName : public Exception
|
|||||||
public:
|
public:
|
||||||
WrongBindingName(const char *whatErrorHasHappen)
|
WrongBindingName(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseIsNotOpen : public Exception
|
class DatabaseIsNotOpen : public Exception
|
||||||
@@ -151,8 +145,7 @@ class DatabaseIsNotOpen : public Exception
|
|||||||
public:
|
public:
|
||||||
DatabaseIsNotOpen(const char *whatErrorHasHappen)
|
DatabaseIsNotOpen(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseCannotBeOpened : public Exception
|
class DatabaseCannotBeOpened : public Exception
|
||||||
@@ -161,8 +154,7 @@ public:
|
|||||||
DatabaseCannotBeOpened(const char *whatErrorHasHappen,
|
DatabaseCannotBeOpened(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
|
class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
|
||||||
@@ -170,8 +162,7 @@ class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
|
|||||||
public:
|
public:
|
||||||
DatabaseFilePathIsEmpty(const char *whatErrorHasHappen)
|
DatabaseFilePathIsEmpty(const char *whatErrorHasHappen)
|
||||||
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
|
class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
|
||||||
@@ -179,8 +170,7 @@ class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
|
|||||||
public:
|
public:
|
||||||
DatabaseIsAlreadyOpen(const char *whatErrorHasHappen)
|
DatabaseIsAlreadyOpen(const char *whatErrorHasHappen)
|
||||||
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseCannotBeClosed : public Exception
|
class DatabaseCannotBeClosed : public Exception
|
||||||
@@ -188,8 +178,7 @@ class DatabaseCannotBeClosed : public Exception
|
|||||||
public:
|
public:
|
||||||
DatabaseCannotBeClosed(const char *whatErrorHasHappen)
|
DatabaseCannotBeClosed(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
|
class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
|
||||||
@@ -197,8 +186,7 @@ class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
|
|||||||
public:
|
public:
|
||||||
DatabaseIsAlreadyClosed(const char *whatErrorHasHappen)
|
DatabaseIsAlreadyClosed(const char *whatErrorHasHappen)
|
||||||
: DatabaseCannotBeClosed(whatErrorHasHappen)
|
: DatabaseCannotBeClosed(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WrongFilePath : public DatabaseCannotBeOpened
|
class WrongFilePath : public DatabaseCannotBeOpened
|
||||||
@@ -207,8 +195,7 @@ public:
|
|||||||
WrongFilePath(const char *whatErrorHasHappen,
|
WrongFilePath(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||||
: DatabaseCannotBeOpened(whatErrorHasHappen, std::move(errorMessage))
|
: DatabaseCannotBeOpened(whatErrorHasHappen, std::move(errorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PragmaValueNotSet : public Exception
|
class PragmaValueNotSet : public Exception
|
||||||
@@ -216,8 +203,7 @@ class PragmaValueNotSet : public Exception
|
|||||||
public:
|
public:
|
||||||
PragmaValueNotSet(const char *whatErrorHasHappen)
|
PragmaValueNotSet(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NotReadOnlySqlStatement : public Exception
|
class NotReadOnlySqlStatement : public Exception
|
||||||
@@ -225,8 +211,7 @@ class NotReadOnlySqlStatement : public Exception
|
|||||||
public:
|
public:
|
||||||
NotReadOnlySqlStatement(const char *whatErrorHasHappen)
|
NotReadOnlySqlStatement(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NotWriteSqlStatement : public Exception
|
class NotWriteSqlStatement : public Exception
|
||||||
@@ -234,8 +219,7 @@ class NotWriteSqlStatement : public Exception
|
|||||||
public:
|
public:
|
||||||
NotWriteSqlStatement(const char *whatErrorHasHappen)
|
NotWriteSqlStatement(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeadLock : public Exception
|
class DeadLock : public Exception
|
||||||
@@ -243,8 +227,7 @@ class DeadLock : public Exception
|
|||||||
public:
|
public:
|
||||||
DeadLock(const char *whatErrorHasHappen)
|
DeadLock(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnknowError : public Exception
|
class UnknowError : public Exception
|
||||||
@@ -253,8 +236,7 @@ public:
|
|||||||
UnknowError(const char *whatErrorHasHappen,
|
UnknowError(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BindingTooBig : public Exception
|
class BindingTooBig : public Exception
|
||||||
@@ -263,8 +245,7 @@ public:
|
|||||||
BindingTooBig(const char *whatErrorHasHappen,
|
BindingTooBig(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TooBig : public Exception
|
class TooBig : public Exception
|
||||||
@@ -387,4 +368,46 @@ public:
|
|||||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CannotCreateChangeSetIterator : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CannotCreateChangeSetIterator(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CannotGetChangeSetOperation : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CannotGetChangeSetOperation(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChangeSetTupleIsOutOfRange : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangeSetTupleIsOutOfRange(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChangeSetTupleIsMisused : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangeSetTupleIsMisused(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnknownError : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnknownError(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "sqlitesessionchangeset.h"
|
#include "sqlitesessionchangeset.h"
|
||||||
|
#include "sqliteexception.h"
|
||||||
#include "sqlitesessions.h"
|
#include "sqlitesessions.h"
|
||||||
|
|
||||||
#include <utils/smallstringio.h>
|
#include <utils/smallstringio.h>
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void checkResultCode(int resultCode)
|
void checkSessionChangeSetCreation(int resultCode)
|
||||||
{
|
{
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case SQLITE_NOMEM:
|
case SQLITE_NOMEM:
|
||||||
@@ -44,29 +45,183 @@ void checkResultCode(int resultCode)
|
|||||||
throw UnknowError("Unknow exception");
|
throw UnknowError("Unknow exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkIteratorCreation(int resultCode)
|
||||||
|
{
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
throw Sqlite::CannotCreateChangeSetIterator{
|
||||||
|
"SessionChangeSet: Cannot create iterator from blob."};
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkIteratorOperation(int resultCode)
|
||||||
|
{
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
throw Sqlite::CannotGetChangeSetOperation{
|
||||||
|
"SessionChangeSet: Cannot create iterator from blob."};
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkChangeSetValue(int resultCode)
|
||||||
|
{
|
||||||
|
switch (resultCode) {
|
||||||
|
case SQLITE_OK:
|
||||||
|
return;
|
||||||
|
case SQLITE_RANGE:
|
||||||
|
throw Sqlite::ChangeSetTupleIsOutOfRange{
|
||||||
|
"SessionChangeSet: You tried to access a non existing column."};
|
||||||
|
case SQLITE_MISUSE:
|
||||||
|
throw Sqlite::ChangeSetIsMisused{
|
||||||
|
"SessionChangeSet: Some misuse happened as you tried to access."};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Sqlite::UnknownError{"SessionChangeSet: Some unknown error happened."};
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueView convertSqliteValue(sqlite3_value *value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
int type = sqlite3_value_type(value);
|
||||||
|
switch (type) {
|
||||||
|
case SQLITE_INTEGER:
|
||||||
|
return ValueView::create(sqlite3_value_int64(value));
|
||||||
|
case SQLITE_FLOAT:
|
||||||
|
return ValueView::create(sqlite3_value_double(value));
|
||||||
|
case SQLITE_TEXT:
|
||||||
|
return ValueView::create(
|
||||||
|
Utils::SmallStringView{reinterpret_cast<const char *const>(sqlite3_value_text(value)),
|
||||||
|
static_cast<std::size_t>(sqlite3_value_bytes(value))});
|
||||||
|
case SQLITE_NULL:
|
||||||
|
return ValueView::create(NullValue{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValueView::create(NullValue{});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SessionChangeSet::SessionChangeSet(BlobView blob)
|
SessionChangeSet::SessionChangeSet(BlobView blob)
|
||||||
: data(sqlite3_malloc64(blob.size()))
|
: m_data(sqlite3_malloc64(blob.size()))
|
||||||
, size(int(blob.size()))
|
, m_size(int(blob.size()))
|
||||||
{
|
{
|
||||||
std::memcpy(data, blob.data(), blob.size());
|
std::memcpy(m_data, blob.data(), blob.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionChangeSet::SessionChangeSet(Sessions &session)
|
SessionChangeSet::SessionChangeSet(Sessions &session)
|
||||||
{
|
{
|
||||||
int resultCode = sqlite3session_changeset(session.session.get(), &size, &data);
|
int resultCode = sqlite3session_changeset(session.session.get(), &m_size, &m_data);
|
||||||
checkResultCode(resultCode);
|
checkSessionChangeSetCreation(resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionChangeSet::~SessionChangeSet()
|
SessionChangeSet::~SessionChangeSet()
|
||||||
{
|
{
|
||||||
sqlite3_free(data);
|
sqlite3_free(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlobView SessionChangeSet::asBlobView() const
|
BlobView SessionChangeSet::asBlobView() const
|
||||||
{
|
{
|
||||||
return {static_cast<const byte *>(data), static_cast<std::size_t>(size)};
|
return {static_cast<const byte *>(m_data), static_cast<std::size_t>(m_size)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionChangeSetInternal::ConstIterator SessionChangeSet::begin() const
|
||||||
|
{
|
||||||
|
sqlite3_changeset_iter *sessionIterator;
|
||||||
|
int resultCode = sqlite3changeset_start(&sessionIterator, m_size, m_data);
|
||||||
|
|
||||||
|
checkIteratorCreation(resultCode);
|
||||||
|
|
||||||
|
SessionChangeSetInternal::ConstIterator iterator{sessionIterator};
|
||||||
|
|
||||||
|
++iterator;
|
||||||
|
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
namespace SessionChangeSetInternal {
|
||||||
|
ConstIterator::~ConstIterator()
|
||||||
|
{
|
||||||
|
sqlite3changeset_finalize(m_sessionIterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
State convertState(int state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case SQLITE_ROW:
|
||||||
|
return State::Row;
|
||||||
|
case SQLITE_DONE:
|
||||||
|
return State::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return State::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operation convertOperation(int operation)
|
||||||
|
{
|
||||||
|
switch (operation) {
|
||||||
|
case SQLITE_INSERT:
|
||||||
|
return Operation::Insert;
|
||||||
|
case SQLITE_UPDATE:
|
||||||
|
return Operation::Update;
|
||||||
|
case SQLITE_DELETE:
|
||||||
|
return Operation::Delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Operation::Invalid;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ConstIterator &ConstIterator::operator++()
|
||||||
|
{
|
||||||
|
int state = sqlite3changeset_next(m_sessionIterator);
|
||||||
|
|
||||||
|
m_state = convertState(state);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple ConstIterator::operator*() const
|
||||||
|
{
|
||||||
|
const char *table;
|
||||||
|
int columnCount;
|
||||||
|
int operation;
|
||||||
|
int isIndirect;
|
||||||
|
|
||||||
|
int resultCode = sqlite3changeset_op(m_sessionIterator, &table, &columnCount, &operation, &isIndirect);
|
||||||
|
|
||||||
|
checkIteratorOperation(resultCode);
|
||||||
|
|
||||||
|
return {table, m_sessionIterator, columnCount, convertOperation(operation)};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
ValueViews fetchValues(sqlite3_changeset_iter *sessionIterator, int column, Operation operation)
|
||||||
|
{
|
||||||
|
sqlite3_value *newValue = nullptr;
|
||||||
|
|
||||||
|
if (operation == Operation::Insert || operation == Operation::Update) {
|
||||||
|
int resultCode = sqlite3changeset_new(sessionIterator, column, &newValue);
|
||||||
|
|
||||||
|
checkChangeSetValue(resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_value *oldValue = nullptr;
|
||||||
|
if (operation == Operation::Delete || operation == Operation::Update) {
|
||||||
|
int resultCode = sqlite3changeset_old(sessionIterator, column, &oldValue);
|
||||||
|
|
||||||
|
checkChangeSetValue(resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {convertSqliteValue(newValue), convertSqliteValue(oldValue)};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ValueViews ConstTupleIterator::operator*() const
|
||||||
|
{
|
||||||
|
return fetchValues(m_sessionIterator, m_column, m_operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueViews Tuple::operator[](int column) const
|
||||||
|
{
|
||||||
|
return fetchValues(sessionIterator, column, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SessionChangeSetInternal
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|||||||
@@ -27,17 +27,173 @@
|
|||||||
|
|
||||||
#include "sqliteblob.h"
|
#include "sqliteblob.h"
|
||||||
#include "sqliteglobal.h"
|
#include "sqliteglobal.h"
|
||||||
|
#include "sqlitevalue.h"
|
||||||
|
|
||||||
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
|
struct sqlite3_changeset_iter;
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
class Sessions;
|
class Sessions;
|
||||||
|
|
||||||
class SessionChangeSet
|
namespace SessionChangeSetInternal {
|
||||||
|
enum class Operation : char { Invalid, Insert, Update, Delete };
|
||||||
|
|
||||||
|
class SentinelIterator
|
||||||
|
{};
|
||||||
|
|
||||||
|
class ValueViews
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ValueView newValue;
|
||||||
|
ValueView oldValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstTupleIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = int;
|
||||||
|
using value_type = ValueView;
|
||||||
|
using pointer = const ValueView *;
|
||||||
|
using reference = const ValueView &;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
|
||||||
|
ConstTupleIterator(sqlite3_changeset_iter *sessionIterator, int index, Operation operation)
|
||||||
|
: m_sessionIterator{sessionIterator}
|
||||||
|
, m_column{index}
|
||||||
|
, m_operation{operation}
|
||||||
|
{}
|
||||||
|
|
||||||
|
ConstTupleIterator operator++()
|
||||||
|
{
|
||||||
|
++m_column;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const ConstTupleIterator &first, const ConstTupleIterator &second)
|
||||||
|
{
|
||||||
|
return first.m_column == second.m_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const ConstTupleIterator &first, const ConstTupleIterator &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueViews operator*() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3_changeset_iter *m_sessionIterator = {};
|
||||||
|
int m_column = 0;
|
||||||
|
Operation m_operation = Operation::Invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Tuple
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = int;
|
||||||
|
using value_type = ValueView;
|
||||||
|
using reference = ValueView &;
|
||||||
|
using const_reference = const ValueView &;
|
||||||
|
using iterator = ConstTupleIterator;
|
||||||
|
using const_iterator = ConstTupleIterator;
|
||||||
|
using size_type = int;
|
||||||
|
|
||||||
|
Utils::SmallStringView table;
|
||||||
|
sqlite3_changeset_iter *sessionIterator = {};
|
||||||
|
int columnCount = 0;
|
||||||
|
Operation operation = Operation::Invalid;
|
||||||
|
|
||||||
|
ValueViews operator[](int column) const;
|
||||||
|
ConstTupleIterator begin() const { return {sessionIterator, 0, operation}; }
|
||||||
|
ConstTupleIterator end() const { return {sessionIterator, columnCount, operation}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State : char { Invalid, Row, Done };
|
||||||
|
|
||||||
|
class ConstIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = long;
|
||||||
|
using value_type = Tuple;
|
||||||
|
using pointer = const Tuple *;
|
||||||
|
using reference = const Tuple &;
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
|
||||||
|
ConstIterator(sqlite3_changeset_iter *sessionIterator)
|
||||||
|
: m_sessionIterator(sessionIterator)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ConstIterator(const ConstIterator &) = delete;
|
||||||
|
void operator=(const ConstIterator &) = delete;
|
||||||
|
|
||||||
|
ConstIterator(ConstIterator &&other)
|
||||||
|
: m_sessionIterator(other.m_sessionIterator)
|
||||||
|
, m_state(other.m_state)
|
||||||
|
{
|
||||||
|
other.m_sessionIterator = {};
|
||||||
|
other.m_state = State::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstIterator &operator=(ConstIterator &&other)
|
||||||
|
{
|
||||||
|
auto tmp = std::move(other);
|
||||||
|
std::swap(tmp, *this);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConstIterator();
|
||||||
|
|
||||||
|
ConstIterator &operator++();
|
||||||
|
|
||||||
|
friend bool operator==(const ConstIterator &first, const ConstIterator &second)
|
||||||
|
{
|
||||||
|
return first.m_sessionIterator == second.m_sessionIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const ConstIterator &first, const ConstIterator &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const ConstIterator &first, SentinelIterator)
|
||||||
|
{
|
||||||
|
return first.m_state == State::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const ConstIterator &first, SentinelIterator)
|
||||||
|
{
|
||||||
|
return first.m_state == State::Row;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(SentinelIterator first, const ConstIterator &second)
|
||||||
|
{
|
||||||
|
return second == first;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(SentinelIterator first, const ConstIterator &second)
|
||||||
|
{
|
||||||
|
return second != first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple operator*() const;
|
||||||
|
|
||||||
|
State state() const { return m_state; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3_changeset_iter *m_sessionIterator = {};
|
||||||
|
State m_state = State::Invalid;
|
||||||
|
};
|
||||||
|
} // namespace SessionChangeSetInternal
|
||||||
|
|
||||||
|
class SQLITE_EXPORT SessionChangeSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SessionChangeSet(BlobView blob);
|
SessionChangeSet(BlobView blob);
|
||||||
@@ -58,20 +214,27 @@ public:
|
|||||||
friend void swap(SessionChangeSet &first, SessionChangeSet &second) noexcept
|
friend void swap(SessionChangeSet &first, SessionChangeSet &second) noexcept
|
||||||
{
|
{
|
||||||
SessionChangeSet temp;
|
SessionChangeSet temp;
|
||||||
std::swap(temp.data, first.data);
|
std::swap(temp.m_data, first.m_data);
|
||||||
std::swap(temp.size, first.size);
|
std::swap(temp.m_size, first.m_size);
|
||||||
std::swap(first.data, second.data);
|
std::swap(first.m_data, second.m_data);
|
||||||
std::swap(first.size, second.size);
|
std::swap(first.m_size, second.m_size);
|
||||||
std::swap(temp.data, second.data);
|
std::swap(temp.m_data, second.m_data);
|
||||||
std::swap(temp.size, second.size);
|
std::swap(temp.m_size, second.m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionChangeSetInternal::ConstIterator begin() const;
|
||||||
|
SessionChangeSetInternal::SentinelIterator end() const { return {}; }
|
||||||
|
|
||||||
|
void *data() const { return m_data; }
|
||||||
|
|
||||||
|
int size() const { return m_size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SessionChangeSet() = default;
|
SessionChangeSet() = default;
|
||||||
|
|
||||||
public:
|
private:
|
||||||
void *data = nullptr;
|
void *m_data = nullptr;
|
||||||
int size = {};
|
int m_size = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
using SessionChangeSets = std::vector<SessionChangeSet>;
|
using SessionChangeSets = std::vector<SessionChangeSet>;
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ void Sessions::revert()
|
|||||||
|
|
||||||
for (auto &changeSet : changeSets) {
|
for (auto &changeSet : changeSets) {
|
||||||
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
||||||
changeSet.size,
|
changeSet.size(),
|
||||||
changeSet.data,
|
changeSet.data(),
|
||||||
nullptr,
|
nullptr,
|
||||||
xConflict,
|
xConflict,
|
||||||
nullptr,
|
nullptr,
|
||||||
@@ -160,8 +160,8 @@ void Sessions::apply()
|
|||||||
|
|
||||||
for (auto &changeSet : changeSets) {
|
for (auto &changeSet : changeSets) {
|
||||||
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
||||||
changeSet.size,
|
changeSet.size(),
|
||||||
changeSet.data,
|
changeSet.data(),
|
||||||
nullptr,
|
nullptr,
|
||||||
xConflict,
|
xConflict,
|
||||||
nullptr,
|
nullptr,
|
||||||
@@ -185,4 +185,14 @@ void Sessions::deleteAll()
|
|||||||
WriteStatement{Utils::SmallString{"DELETE FROM ", sessionsTableName}, database}.execute();
|
WriteStatement{Utils::SmallString{"DELETE FROM ", sessionsTableName}, database}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionChangeSets Sessions::changeSets() const
|
||||||
|
{
|
||||||
|
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
|
||||||
|
sessionsTableName,
|
||||||
|
" ORDER BY id DESC"},
|
||||||
|
database};
|
||||||
|
|
||||||
|
return selectChangeSets.values<SessionChangeSet>(1024);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sqlitedatabase.h"
|
#include "sqlitedatabase.h"
|
||||||
|
#include "sqlitesessionchangeset.h"
|
||||||
#include "sqlitewritestatement.h"
|
#include "sqlitewritestatement.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -81,6 +82,8 @@ public:
|
|||||||
void applyAndUpdateSessions();
|
void applyAndUpdateSessions();
|
||||||
void deleteAll();
|
void deleteAll();
|
||||||
|
|
||||||
|
SessionChangeSets changeSets() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void attachTables(const Utils::SmallStringVector &tables);
|
void attachTables(const Utils::SmallStringVector &tables);
|
||||||
|
|
||||||
|
|||||||
@@ -331,6 +331,28 @@ std::ostream &operator<<(std::ostream &out, const Value &value)
|
|||||||
return out << ")";
|
return out << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ValueView &value)
|
||||||
|
{
|
||||||
|
out << "(";
|
||||||
|
|
||||||
|
switch (value.type()) {
|
||||||
|
case Sqlite::ValueType::Integer:
|
||||||
|
out << value.toInteger();
|
||||||
|
break;
|
||||||
|
case Sqlite::ValueType::Float:
|
||||||
|
out << value.toFloat();
|
||||||
|
break;
|
||||||
|
case Sqlite::ValueType::String:
|
||||||
|
out << "\"" << value.toStringView() << "\"";
|
||||||
|
break;
|
||||||
|
case Sqlite::ValueType::Null:
|
||||||
|
out << "null";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out << ")";
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Utils::SmallStringView operationText(int operation)
|
Utils::SmallStringView operationText(int operation)
|
||||||
{
|
{
|
||||||
@@ -398,7 +420,7 @@ std::ostream &operator<<(std::ostream &out, sqlite3_changeset_iter *iter)
|
|||||||
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
||||||
{
|
{
|
||||||
sqlite3_changeset_iter *iter = nullptr;
|
sqlite3_changeset_iter *iter = nullptr;
|
||||||
sqlite3changeset_start(&iter, changeset.size, const_cast<void *>(changeset.data));
|
sqlite3changeset_start(&iter, changeset.size(), const_cast<void *>(changeset.data()));
|
||||||
|
|
||||||
out << "ChangeSets([";
|
out << "ChangeSets([";
|
||||||
|
|
||||||
@@ -414,6 +436,79 @@ std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace SessionChangeSetInternal {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char *toText(Operation operation)
|
||||||
|
{
|
||||||
|
switch (operation) {
|
||||||
|
case Operation::Invalid:
|
||||||
|
return "Invalid";
|
||||||
|
case Operation::Insert:
|
||||||
|
return "Invalid";
|
||||||
|
case Operation::Update:
|
||||||
|
return "Invalid";
|
||||||
|
case Operation::Delete:
|
||||||
|
return "Invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *toText(State state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case State::Invalid:
|
||||||
|
return "Invalid";
|
||||||
|
case State::Row:
|
||||||
|
return "Row";
|
||||||
|
case State::Done:
|
||||||
|
return "Done";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, SentinelIterator)
|
||||||
|
{
|
||||||
|
return out << "sentinel";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, Operation operation)
|
||||||
|
{
|
||||||
|
return out << toText(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, State state)
|
||||||
|
{
|
||||||
|
return out << toText(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const Tuple &tuple)
|
||||||
|
{
|
||||||
|
return out << "(" << tuple.operation << ", " << tuple.columnCount << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ValueViews &valueViews)
|
||||||
|
{
|
||||||
|
return out << "(" << valueViews.newValue << ", " << valueViews.oldValue << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ConstIterator &iterator)
|
||||||
|
{
|
||||||
|
return out << "(" << (*iterator) << ", " << iterator.state() << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ConstTupleIterator &iterator)
|
||||||
|
{
|
||||||
|
auto value = *iterator;
|
||||||
|
|
||||||
|
return out << "(" << value.newValue << ", " << value.newValue << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SessionChangeSetInternal
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|||||||
@@ -66,10 +66,30 @@ void PrintTo(const TextRange &range, ::std::ostream *os);
|
|||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
class Value;
|
class Value;
|
||||||
|
class ValueView;
|
||||||
class SessionChangeSet;
|
class SessionChangeSet;
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const Value &value);
|
std::ostream &operator<<(std::ostream &out, const Value &value);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ValueView &value);
|
||||||
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
|
std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
|
||||||
|
namespace SessionChangeSetInternal {
|
||||||
|
class ConstIterator;
|
||||||
|
class ConstTupleIterator;
|
||||||
|
class SentinelIterator;
|
||||||
|
class Tuple;
|
||||||
|
class ValueViews;
|
||||||
|
enum class Operation : char;
|
||||||
|
enum class State : char;
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, SentinelIterator iterator);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ConstIterator &iterator);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ConstTupleIterator &iterator);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const Tuple &tuple);
|
||||||
|
std::ostream &operator<<(std::ostream &out, Operation operation);
|
||||||
|
std::ostream &operator<<(std::ostream &out, State operation);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ValueViews &valueViews);
|
||||||
|
|
||||||
|
} // namespace SessionChangeSetInternal
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace {
|
|||||||
|
|
||||||
using Sqlite::SessionChangeSet;
|
using Sqlite::SessionChangeSet;
|
||||||
using Sqlite::SessionChangeSets;
|
using Sqlite::SessionChangeSets;
|
||||||
|
using Sqlite::SessionChangeSetInternal::Operation;
|
||||||
|
using Sqlite::SessionChangeSetInternal::ValueViews;
|
||||||
|
|
||||||
class DatabaseExecute
|
class DatabaseExecute
|
||||||
{
|
{
|
||||||
@@ -79,6 +81,17 @@ MATCHER_P3(HasData,
|
|||||||
return data.name == name && data.number == number && data.value == value;
|
return data.name == name && data.number == number && data.value == value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MATCHER_P2(HasValues,
|
||||||
|
newValue,
|
||||||
|
oldValue,
|
||||||
|
std::string(negation ? "hasn't " : "has ") + PrintToString(newValue) + ", "
|
||||||
|
+ PrintToString(oldValue))
|
||||||
|
{
|
||||||
|
const ValueViews &values = arg;
|
||||||
|
|
||||||
|
return values.newValue == newValue && values.oldValue == oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
class Tag
|
class Tag
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -113,7 +126,6 @@ protected:
|
|||||||
|
|
||||||
std::vector<Data> fetchData() { return selectData.values<Data, 3>(8); }
|
std::vector<Data> fetchData() { return selectData.values<Data, 3>(8); }
|
||||||
std::vector<Tag> fetchTags() { return selectTags.values<Tag, 2>(8); }
|
std::vector<Tag> fetchTags() { return selectTags.values<Tag, 2>(8); }
|
||||||
SessionChangeSets fetchChangeSets() { return selectChangeSets.values<SessionChangeSet>(8); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||||
@@ -128,6 +140,9 @@ protected:
|
|||||||
Sqlite::WriteStatement insertData{"INSERT INTO data(name, number, value) VALUES (?1, ?2, ?3) "
|
Sqlite::WriteStatement insertData{"INSERT INTO data(name, number, value) VALUES (?1, ?2, ?3) "
|
||||||
"ON CONFLICT (name) DO UPDATE SET (number, value) = (?2, ?3)",
|
"ON CONFLICT (name) DO UPDATE SET (number, value) = (?2, ?3)",
|
||||||
database};
|
database};
|
||||||
|
Sqlite::WriteStatement insertOneDatum{"INSERT INTO data(value, name) VALUES (?1, ?2) "
|
||||||
|
"ON CONFLICT (name) DO UPDATE SET (value) = (?2)",
|
||||||
|
database};
|
||||||
Sqlite::WriteStatement updateNumber{"UPDATE data SET number = ?002 WHERE name=?001", database};
|
Sqlite::WriteStatement updateNumber{"UPDATE data SET number = ?002 WHERE name=?001", database};
|
||||||
Sqlite::WriteStatement updateValue{"UPDATE data SET value = ?002 WHERE name=?001", database};
|
Sqlite::WriteStatement updateValue{"UPDATE data SET value = ?002 WHERE name=?001", database};
|
||||||
Sqlite::WriteStatement deleteData{"DELETE FROM data WHERE name=?", database};
|
Sqlite::WriteStatement deleteData{"DELETE FROM data WHERE name=?", database};
|
||||||
@@ -151,7 +166,7 @@ TEST_F(Sessions, CreateEmptySession)
|
|||||||
sessions.create();
|
sessions.create();
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), IsEmpty());
|
ASSERT_THAT(sessions.changeSets(), IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, CreateSessionWithInsert)
|
TEST_F(Sessions, CreateSessionWithInsert)
|
||||||
@@ -160,7 +175,7 @@ TEST_F(Sessions, CreateSessionWithInsert)
|
|||||||
insertData.write("foo", 22, 3.14);
|
insertData.write("foo", 22, 3.14);
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(1));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, CreateSessionWithUpdate)
|
TEST_F(Sessions, CreateSessionWithUpdate)
|
||||||
@@ -171,7 +186,7 @@ TEST_F(Sessions, CreateSessionWithUpdate)
|
|||||||
updateNumber.write("foo", "bar");
|
updateNumber.write("foo", "bar");
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(1));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, CreateSessionWithDelete)
|
TEST_F(Sessions, CreateSessionWithDelete)
|
||||||
@@ -182,7 +197,7 @@ TEST_F(Sessions, CreateSessionWithDelete)
|
|||||||
deleteData.write("foo");
|
deleteData.write("foo");
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(1));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, CreateSessionWithInsertAndUpdate)
|
TEST_F(Sessions, CreateSessionWithInsertAndUpdate)
|
||||||
@@ -195,7 +210,7 @@ TEST_F(Sessions, CreateSessionWithInsertAndUpdate)
|
|||||||
updateNumber.write("foo", "bar");
|
updateNumber.write("foo", "bar");
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(2));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, CreateSession)
|
TEST_F(Sessions, CreateSession)
|
||||||
@@ -205,7 +220,7 @@ TEST_F(Sessions, CreateSession)
|
|||||||
|
|
||||||
sessions.commit();
|
sessions.commit();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(1));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Sessions, RevertSession)
|
TEST_F(Sessions, RevertSession)
|
||||||
@@ -437,7 +452,261 @@ TEST_F(Sessions, ApplyAndUpdateSessionsHasOnlyOneChangeSet)
|
|||||||
|
|
||||||
sessions.applyAndUpdateSessions();
|
sessions.applyAndUpdateSessions();
|
||||||
|
|
||||||
ASSERT_THAT(fetchChangeSets(), SizeIs(1));
|
ASSERT_THAT(sessions.changeSets(), SizeIs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, ForEmptySessionBeginEqualsEnd)
|
||||||
|
{
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
|
||||||
|
auto begin = changeSets.begin();
|
||||||
|
|
||||||
|
ASSERT_THAT(begin, Eq(changeSets.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, IteratorBeginUnequalsEndIfChangeSetHasContent)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
ASSERT_THAT(begin, Ne(changeSet.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, NextIteratorUnequalsBeginIfChangeSetHasContent)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
|
||||||
|
auto next = std::next(changeSet.begin());
|
||||||
|
|
||||||
|
ASSERT_NE(next, changeSet.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, NextIteratorEqualsEndIfChangeSetHasContent)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
|
||||||
|
auto next = std::next(changeSet.begin());
|
||||||
|
|
||||||
|
ASSERT_THAT(next, Eq(changeSet.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, NextIteratorNotUnqualsEndIfChangeSetHasContent)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
|
||||||
|
auto next = std::next(changeSet.begin());
|
||||||
|
|
||||||
|
ASSERT_THAT(next, Not(Ne(changeSet.end())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, BeginIteratorHasInsertOperation)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ASSERT_THAT(tuple.operation, Eq(Operation::Insert));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, BeginIteratorHasUpdateOperation)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
updateValue.write("foo", 99);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ASSERT_THAT(tuple.operation, Eq(Operation::Update));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, BeginIteratorHasDeleteOperation)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
deleteData.write("foo");
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ASSERT_THAT(tuple.operation, Eq(Operation::Delete));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, BeginIteratorHasDataTableName)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ASSERT_THAT(tuple.table, Eq("data"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, ConvertAllValueTypesInChangeSet)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
std::vector<ValueViews> values{tuple.begin(), tuple.end()};
|
||||||
|
|
||||||
|
ASSERT_THAT(values,
|
||||||
|
ElementsAre(HasValues(1, nullptr),
|
||||||
|
HasValues("foo", nullptr),
|
||||||
|
HasValues("bar", nullptr),
|
||||||
|
HasValues(3.14, nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, InsertOneValueChangeSet)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertOneDatum.write("foo");
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
std::vector<ValueViews> values{tuple.begin(), tuple.end()};
|
||||||
|
|
||||||
|
ASSERT_THAT(values,
|
||||||
|
ElementsAre(HasValues(1, nullptr),
|
||||||
|
HasValues(nullptr, nullptr),
|
||||||
|
HasValues(nullptr, nullptr),
|
||||||
|
HasValues("foo", nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, UpdateOneValueChangeSet)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
updateValue.write("foo", 99);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
std::vector<ValueViews> values{tuple.begin(), tuple.end()};
|
||||||
|
|
||||||
|
ASSERT_THAT(values,
|
||||||
|
ElementsAre(HasValues(nullptr, 1),
|
||||||
|
HasValues(nullptr, nullptr),
|
||||||
|
HasValues(nullptr, nullptr),
|
||||||
|
HasValues(99, 3.14)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, DeleteRowChangeSet)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
deleteData.write("foo");
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
std::vector<ValueViews> values{tuple.begin(), tuple.end()};
|
||||||
|
|
||||||
|
ASSERT_THAT(values,
|
||||||
|
ElementsAre(HasValues(nullptr, 1),
|
||||||
|
HasValues(nullptr, "foo"),
|
||||||
|
HasValues(nullptr, "bar"),
|
||||||
|
HasValues(nullptr, 3.14)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, EmptyChangeSet)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
sessions.commit();
|
||||||
|
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
|
||||||
|
ASSERT_THAT(changeSets, ElementsAre());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, AccessInsertOneValueChangeSet)
|
||||||
|
{
|
||||||
|
sessions.create();
|
||||||
|
insertOneDatum.write("foo");
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ValueViews value = tuple[3];
|
||||||
|
|
||||||
|
ASSERT_THAT(value, HasValues("foo", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, AccessUpdateOneValueChangeSet)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
updateValue.write("foo", 99);
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ValueViews value = tuple[3];
|
||||||
|
|
||||||
|
ASSERT_THAT(value, HasValues(99, 3.14));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Sessions, AccessDeleteRowChangeSet)
|
||||||
|
{
|
||||||
|
insertData.write("foo", "bar", 3.14);
|
||||||
|
sessions.create();
|
||||||
|
deleteData.write("foo");
|
||||||
|
sessions.commit();
|
||||||
|
auto changeSets = sessions.changeSets();
|
||||||
|
auto &&changeSet = changeSets.front();
|
||||||
|
auto begin = changeSet.begin();
|
||||||
|
auto tuple = (*begin);
|
||||||
|
|
||||||
|
ValueViews value = tuple[0];
|
||||||
|
|
||||||
|
ASSERT_THAT(value, HasValues(nullptr, 1));
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user