Skip to content

Commit

Permalink
[FEATURE] Add a flag to dirty edit buffer when using executeSql in tr…
Browse files Browse the repository at this point in the history
…ansactions
  • Loading branch information
pblottiere committed Oct 25, 2017
1 parent 6297d19 commit 32ff78b
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 16 deletions.
13 changes: 12 additions & 1 deletion python/core/qgstransaction.sip
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,16 @@ class QgsTransaction : QObject /Abstract/
:rtype: bool
%End

virtual bool executeSql( const QString &sql, QString &error /Out/ ) = 0;
virtual bool executeSql( const QString &sql, QString &error /Out/, bool isDirty = false ) = 0;
%Docstring
Execute the ``sql`` string. The result must not be a tuple, so running a
``SELECT`` query will return an error.

\param sql The sql query to execute
\param error The error message
\param isDirty Flag to indicate if the underlying data will be modified

:return: true if everything is OK, false otherwise
:rtype: bool
%End

Expand Down Expand Up @@ -161,6 +167,11 @@ class QgsTransaction : QObject /Abstract/
Emitted after a rollback
%End

void dirty( const QString &sql );
%Docstring
Emitted if a sql query is executed and the underlying data is modified
%End

protected:


Expand Down
13 changes: 13 additions & 0 deletions python/core/qgsvectorlayereditpassthrough.sip
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ class QgsVectorLayerEditPassthrough : QgsVectorLayerEditBuffer
virtual void rollBack();


bool update( QgsTransaction *transaction, const QString &sql );
%Docstring
Update underlying data with a SQL query embedded in a transaction.

\param transaction Transaction in which the sql query has been run
\param sql The SQL query updating data

:return: true if the undo/redo command is well added to the stack, false otherwise

.. versionadded:: 3.0
:rtype: bool
%End

};

/************************************************************************
Expand Down
32 changes: 31 additions & 1 deletion python/core/qgsvectorlayerundopassthroughcommand.sip
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ class QgsVectorLayerUndoPassthroughCommand : QgsVectorLayerUndoCommand
%End
public:

QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text );
QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text, bool autocreate = true );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommand
\param buffer associated edit buffer
\param text text associated with command
\param autocreate flag allowing to automatically create a savepoint if necessary
%End

bool hasError() const;
Expand Down Expand Up @@ -58,6 +59,9 @@ class QgsVectorLayerUndoPassthroughCommand : QgsVectorLayerUndoCommand
Set error flag and append "failed" to text
%End


protected:

};


Expand Down Expand Up @@ -246,6 +250,32 @@ class QgsVectorLayerUndoPassthroughCommandRenameAttribute : QgsVectorLayerUndoPa

};


class QgsVectorLayerUndoPassthroughCommandUpdate : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for running a specific sql query in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandUpdate( QgsVectorLayerEditBuffer *buffer /Transfer/, QgsTransaction *transaction, const QString &sql );
%Docstring
Constructor for QgsVectorLayerUndoCommandUpdate
\param buffer associated edit buffer
\param transaction transaction running the sql query
\param sql the query
%End

virtual void undo();
virtual void redo();

};

/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgstransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ QString QgsTransaction::createSavepoint( QString &error SIP_OUT )
if ( !mTransactionActive )
return QString();

if ( !mLastSavePointIsDirty )
if ( !mLastSavePointIsDirty && !mSavepoints.isEmpty() )
return mSavepoints.top();

const QString name( QUuid::createUuid().toString() );
Expand Down
13 changes: 12 additions & 1 deletion src/core/qgstransaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,14 @@ class CORE_EXPORT QgsTransaction : public QObject SIP_ABSTRACT
/**
* Execute the \a sql string. The result must not be a tuple, so running a
* ``SELECT`` query will return an error.
*
* \param sql The sql query to execute
* \param error The error message
* \param isDirty Flag to indicate if the underlying data will be modified
*
* \returns true if everything is OK, false otherwise
*/
virtual bool executeSql( const QString &sql, QString &error SIP_OUT ) = 0;
virtual bool executeSql( const QString &sql, QString &error SIP_OUT, bool isDirty = false ) = 0;

/**
* Checks if a the provider of a given \a layer supports transactions.
Expand Down Expand Up @@ -165,6 +171,11 @@ class CORE_EXPORT QgsTransaction : public QObject SIP_ABSTRACT
*/
void afterRollback();

/**
* Emitted if a sql query is executed and the underlying data is modified
*/
void dirty( const QString &sql );

protected:
QgsTransaction( const QString &connString ) SIP_SKIP;

Expand Down
10 changes: 10 additions & 0 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,8 @@ bool QgsVectorLayer::startEditing()
if ( mDataProvider->transaction() )
{
mEditBuffer = new QgsVectorLayerEditPassthrough( this );

connect( mDataProvider->transaction(), &QgsTransaction::dirty, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
}
else
{
Expand Down Expand Up @@ -4575,3 +4577,11 @@ bool QgsVectorLayer::readExtentFromXml() const
return mReadExtentFromXml;
}

void QgsVectorLayer::onDirtyTransaction( const QString &sql )
{
QgsTransaction *tr = dataProvider()->transaction();
if ( tr && mEditBuffer )
{
dynamic_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql );
}
}
1 change: 1 addition & 0 deletions src/core/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
void onFeatureDeleted( QgsFeatureId fid );
void onRelationsLoaded();
void onSymbolsCounted();
void onDirtyTransaction( const QString &sql );

protected:
//! Set the extent
Expand Down
1 change: 1 addition & 0 deletions src/core/qgsvectorlayereditbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject
friend class QgsVectorLayerUndoPassthroughCommandAddAttribute;
friend class QgsVectorLayerUndoPassthroughCommandDeleteAttribute;
friend class QgsVectorLayerUndoPassthroughCommandRenameAttribute;
friend class QgsVectorLayerUndoPassthroughCommandUpdate;

/**
* Deleted feature IDs which are not committed. Note a feature can be added and then deleted
Expand Down
13 changes: 12 additions & 1 deletion src/core/qgsvectorlayereditpassthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayerundopassthroughcommand.h"
#include "qgstransaction.h"

QgsVectorLayerEditPassthrough::QgsVectorLayerEditPassthrough( QgsVectorLayer *layer )
: mModified( false )
Expand All @@ -35,7 +36,12 @@ bool QgsVectorLayerEditPassthrough::modify( QgsVectorLayerUndoPassthroughCommand
if ( cmd->hasError() )
return false;

mModified = true;
if ( !mModified )
{
mModified = true;
emit layerModified();
}

return true;
}

Expand Down Expand Up @@ -105,3 +111,8 @@ void QgsVectorLayerEditPassthrough::rollBack()
{
mModified = false;
}

bool QgsVectorLayerEditPassthrough::update( QgsTransaction *tr, const QString &sql )
{
return modify( new QgsVectorLayerUndoPassthroughCommandUpdate( this, tr, sql ) );
}
13 changes: 13 additions & 0 deletions src/core/qgsvectorlayereditpassthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

class QgsVectorLayer;
class QgsVectorLayerUndoPassthroughCommand;
class QgsTransaction;

/**
* \ingroup core
Expand All @@ -43,6 +44,18 @@ class CORE_EXPORT QgsVectorLayerEditPassthrough : public QgsVectorLayerEditBuffe
bool commitChanges( QStringList &commitErrors ) override;
void rollBack() override;

/**
* Update underlying data with a SQL query embedded in a transaction.
*
* \param transaction Transaction in which the sql query has been run
* \param sql The SQL query updating data
*
* \returns true if the undo/redo command is well added to the stack, false otherwise
*
* \since QGIS 3.0
*/
bool update( QgsTransaction *transaction, const QString &sql );

private:
bool mModified;

Expand Down
50 changes: 48 additions & 2 deletions src/core/qgsvectorlayerundopassthroughcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
//@todo use setObsolete instead of mHasError when upgrading qt version, this will allow auto removal of the command
// for the moment a errored command is left on the stack

QgsVectorLayerUndoPassthroughCommand::QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text )
QgsVectorLayerUndoPassthroughCommand::QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text, bool autocreate )
: QgsVectorLayerUndoCommand( buffer )
, mSavePointId( mBuffer->L->isEditCommandActive()
, mSavePointId( mBuffer->L->isEditCommandActive() || !autocreate
? mBuffer->L->dataProvider()->transaction()->savePoints().last()
: mBuffer->L->dataProvider()->transaction()->createSavepoint( mError ) )
, mHasError( !mError.isEmpty() )
Expand Down Expand Up @@ -333,3 +333,49 @@ void QgsVectorLayerUndoPassthroughCommandRenameAttribute::redo()
setError();
}
}

QgsVectorLayerUndoPassthroughCommandUpdate::QgsVectorLayerUndoPassthroughCommandUpdate( QgsVectorLayerEditBuffer *buffer, QgsTransaction *transaction, const QString &sql )
: QgsVectorLayerUndoPassthroughCommand( buffer, QObject::tr( "custom transaction" ), false )
, mTransaction( transaction )
, mSql( sql )
{
}

void QgsVectorLayerUndoPassthroughCommandUpdate::undo()
{
if ( rollBackToSavePoint() )
{
mUndone = true;
emit mBuffer->L->layerModified();
}
else
{
setError();
}
}

void QgsVectorLayerUndoPassthroughCommandUpdate::redo()
{
// the first time that the sql query is execute is within QgsTransaction
// itself. So the redo has to be executed only after an undo action.
if ( mUndone )
{
mSavePointId = mTransaction->createSavepoint( mError );

if ( mError.isEmpty() )
{
if ( mTransaction->executeSql( mSql, mError ) )
{
mUndone = false;
}
else
{
setError();
}
}
else
{
setError();
}
}
}
45 changes: 38 additions & 7 deletions src/core/qgsvectorlayerundopassthroughcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,15 @@ class CORE_EXPORT QgsVectorLayerUndoPassthroughCommand : public QgsVectorLayerUn
* Constructor for QgsVectorLayerUndoPassthroughCommand
* \param buffer associated edit buffer
* \param text text associated with command
* \param autocreate flag allowing to automatically create a savepoint if necessary
*/
QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text );
QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text, bool autocreate = true );

/**
* Returns error status
*/
bool hasError() const { return mHasError; }

private:
QString mError;
QString mSavePointId;
bool mHasError;
bool mRecreateSavePoint;

protected:

/**
Expand All @@ -70,6 +65,14 @@ class CORE_EXPORT QgsVectorLayerUndoPassthroughCommand : public QgsVectorLayerUn
*/
void setError();

QString mSavePointId;

protected:
QString mError;

private:
bool mHasError;
bool mRecreateSavePoint;
};

/**
Expand Down Expand Up @@ -265,4 +268,32 @@ class CORE_EXPORT QgsVectorLayerUndoPassthroughCommandRenameAttribute : public Q
const QString mOldName;
};

/**
* \ingroup core
* \class QgsVectorLayerUndoPassthroughCommandUpdate
* \brief Undo command for running a specific sql query in transaction group.
* \since QGIS 3.0
*/

class CORE_EXPORT QgsVectorLayerUndoPassthroughCommandUpdate : public QgsVectorLayerUndoPassthroughCommand
{
public:

/**
* Constructor for QgsVectorLayerUndoCommandUpdate
* \param buffer associated edit buffer
* \param transaction transaction running the sql query
* \param sql the query
*/
QgsVectorLayerUndoPassthroughCommandUpdate( QgsVectorLayerEditBuffer *buffer SIP_TRANSFER, QgsTransaction *transaction, const QString &sql );

virtual void undo() override;
virtual void redo() override;

private:
QgsTransaction *mTransaction = nullptr;
QString mSql;
bool mUndone = false;
};

#endif
Loading

0 comments on commit 32ff78b

Please sign in to comment.