Skip to content
Permalink
Browse files
Add method to allow an existing history entry to be updated
Intended for use in storing the results of a long running operation.
E.g. a processing task would store the initial operation history
when the operation starts, and when it finishes it should update
that entry with the full log and output results.
  • Loading branch information
nyalldawson committed Dec 21, 2021
1 parent 8fef4e4 commit af03701ab88ae2b54f0574fc4a36feb408d98e80
@@ -125,24 +125,56 @@ Constructor for HistoryEntryOptions.
Qgis::HistoryProviderBackends storageBackends;
};

bool addEntry( const QString &providerId, const QVariantMap &entry, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
long long addEntry( const QString &providerId, const QVariantMap &entry, bool &ok /Out/, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
%Docstring
Adds an ``entry`` to the history logs.

The entry will be tagged with the current date/time as the timestamp.

The ``providerId`` specifies the history provider responsible for this entry.
Entry options are specified via the ``options`` argument.

:param providerId: associated :py:func:`QgsAbstractHistoryProvider.id()`
:param entry: entry to add
:param options: options

:return: - ID of newly added entry.
- ok: will be set to ``True`` if entry was successfully added
%End

bool addEntry( const QgsHistoryEntry &entry, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
long long addEntry( const QgsHistoryEntry &entry, bool &ok /Out/, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
%Docstring
Adds an ``entry`` to the history logs.

:param entry: entry to add
:param options: options

:return: - ID of newly added entry.
- ok: will be set to ``True`` if entry was successfully added
%End

bool addEntries( const QList< QgsHistoryEntry > &entries, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
%Docstring
Adds a list of ``entries`` to the history logs.
%End

QgsHistoryEntry entry( long long id, bool &ok, Qgis::HistoryProviderBackend backend = Qgis::HistoryProviderBackend::LocalProfile ) const;
%Docstring
Returns the entry with matching ID, from the specified ``backend``.

:param id: ID of entry to find
:param ok: will be set to ``True`` if entry was found
:param backend: associated backend

:return: matching entry if found
%End

bool updateEntry( long long id, const QVariantMap &entry, Qgis::HistoryProviderBackend backend = Qgis::HistoryProviderBackend::LocalProfile );
%Docstring
Updates the existing entry with matching ``id``.

This method allows the content of an entry to be updated, e.g. to add additional properties
to the content. (Such as recording the results of after a long-running operation completes).
%End

QList< QgsHistoryEntry > queryEntries( const QDateTime &start = QDateTime(), const QDateTime &end = QDateTime(),
@@ -111,13 +111,15 @@ QStringList QgsHistoryProviderRegistry::providerIds() const
return mProviders.keys();
}

bool QgsHistoryProviderRegistry::addEntry( const QString &providerId, const QVariantMap &entry, QgsHistoryProviderRegistry::HistoryEntryOptions options )
long long QgsHistoryProviderRegistry::addEntry( const QString &providerId, const QVariantMap &entry, bool &ok, QgsHistoryProviderRegistry::HistoryEntryOptions options )
{
return addEntry( QgsHistoryEntry( providerId, QDateTime::currentDateTime(), entry ), options );
return addEntry( QgsHistoryEntry( providerId, QDateTime::currentDateTime(), entry ), ok, options );
}

bool QgsHistoryProviderRegistry::addEntry( const QgsHistoryEntry &entry, HistoryEntryOptions options )
long long QgsHistoryProviderRegistry::addEntry( const QgsHistoryEntry &entry, bool &ok, HistoryEntryOptions options )
{
ok = true;
long long id = -1;
if ( options.storageBackends & Qgis::HistoryProviderBackend::LocalProfile )
{
QDomDocument xmlDoc;
@@ -130,24 +132,92 @@ bool QgsHistoryProviderRegistry::addEntry( const QgsHistoryEntry &entry, History
if ( !runEmptyQuery( query ) )
{
QgsDebugMsg( QStringLiteral( "Couldn't story history entry in database!" ) );
return false;
ok = false;
return -1;
}
id = static_cast< int >( sqlite3_last_insert_rowid( mLocalDB.get() ) );
}

return true;
return id;
}

bool QgsHistoryProviderRegistry::addEntries( const QList<QgsHistoryEntry> &entries, HistoryEntryOptions options )
{
bool ok = true;
if ( options.storageBackends & Qgis::HistoryProviderBackend::LocalProfile )
{
runEmptyQuery( QStringLiteral( "BEGIN TRANSACTION;" ) );
for ( const QgsHistoryEntry &entry : entries )
addEntry( entry, options );
addEntry( entry, ok, options );
runEmptyQuery( QStringLiteral( "COMMIT TRANSACTION;" ) );
}

return true;
return ok;
}

QgsHistoryEntry QgsHistoryProviderRegistry::entry( long long id, bool &ok, Qgis::HistoryProviderBackend backend ) const
{
ok = false;
switch ( backend )
{
case Qgis::HistoryProviderBackend::LocalProfile:
{
if ( !mLocalDB )
{
QgsDebugMsg( QStringLiteral( "Cannot open database to query history entries" ) );
return QgsHistoryEntry( QVariantMap() );
}

QString sql = QStringLiteral( "SELECT provider_id, xml, timestamp FROM history WHERE id=%1" ).arg( id );

int nErr;
sqlite3_statement_unique_ptr statement = mLocalDB.prepare( sql, nErr );

if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
{
QDomDocument doc;
if ( !doc.setContent( statement.columnAsText( 1 ) ) )
{
QgsDebugMsg( QStringLiteral( "Cannot read history entry" ) );
return QgsHistoryEntry( QVariantMap() );
}

ok = true;
return QgsHistoryEntry(
statement.columnAsText( 0 ),
QDateTime::fromString( statement.columnAsText( 2 ), QStringLiteral( "yyyy-MM-dd HH:mm:ss" ) ),
QgsXmlUtils::readVariant( doc.documentElement() ).toMap()
);
}

QgsDebugMsg( QStringLiteral( "Cannot find history item with matching ID" ) );
return QgsHistoryEntry( QVariantMap() );
}
}
BUILTIN_UNREACHABLE
}

bool QgsHistoryProviderRegistry::updateEntry( long long id, const QVariantMap &entry, Qgis::HistoryProviderBackend backend )
{
switch ( backend )
{
case Qgis::HistoryProviderBackend::LocalProfile:
{
QDomDocument xmlDoc;
xmlDoc.appendChild( QgsXmlUtils::writeVariant( entry, xmlDoc ) );
const QString entryXml = xmlDoc.toString();

QString query = qgs_sqlite3_mprintf( "UPDATE history SET xml='%q' WHERE id = %d;",
entryXml.toUtf8().constData(), id );
if ( !runEmptyQuery( query ) )
{
QgsDebugMsg( QStringLiteral( "Couldn't update history entry in database!" ) );
return false;
}
return true;
}
}
BUILTIN_UNREACHABLE
}

QList<QgsHistoryEntry> QgsHistoryProviderRegistry::queryEntries( const QDateTime &start, const QDateTime &end, const QString &providerId, Qgis::HistoryProviderBackends backends ) const
@@ -162,19 +162,51 @@ class GUI_EXPORT QgsHistoryProviderRegistry : public QObject
*
* The \a providerId specifies the history provider responsible for this entry.
* Entry options are specified via the \a options argument.
*
* \param providerId associated QgsAbstractHistoryProvider::id()
* \param entry entry to add
* \param ok will be set to TRUE if entry was successfully added
* \param options options
*
* \returns ID of newly added entry.
*/
bool addEntry( const QString &providerId, const QVariantMap &entry, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
long long addEntry( const QString &providerId, const QVariantMap &entry, bool &ok SIP_OUT, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );

/**
* Adds an \a entry to the history logs.
*
* \param entry entry to add
* \param ok will be set to TRUE if entry was successfully added
* \param options options
*
* \returns ID of newly added entry.
*/
bool addEntry( const QgsHistoryEntry &entry, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );
long long addEntry( const QgsHistoryEntry &entry, bool &ok SIP_OUT, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );

/**
* Adds a list of \a entries to the history logs.
*/
bool addEntries( const QList< QgsHistoryEntry > &entries, QgsHistoryProviderRegistry::HistoryEntryOptions options = QgsHistoryProviderRegistry::HistoryEntryOptions() );

/**
* Returns the entry with matching ID, from the specified \a backend.
*
* \param id ID of entry to find
* \param ok will be set to TRUE if entry was found
* \param backend associated backend
*
* \returns matching entry if found
*/
QgsHistoryEntry entry( long long id, bool &ok, Qgis::HistoryProviderBackend backend = Qgis::HistoryProviderBackend::LocalProfile ) const;

/**
* Updates the existing entry with matching \a id.
*
* This method allows the content of an entry to be updated, e.g. to add additional properties
* to the content. (Such as recording the results of after a long-running operation completes).
*/
bool updateEntry( long long id, const QVariantMap &entry, Qgis::HistoryProviderBackend backend = Qgis::HistoryProviderBackend::LocalProfile );

/**
* Queries history entries which occurred between the specified \a start and \a end times.
*
@@ -91,10 +91,12 @@ def test_registry_entries(self):
reg = QgsHistoryProviderRegistry(useMemoryDatabase=True)
self.assertFalse(reg.queryEntries())

reg.addEntry('my provider', {'some var': 5, 'other_var': [1, 2, 3], 'final_var': {'a': 'b'}},
QgsHistoryProviderRegistry.HistoryEntryOptions())
reg.addEntry('my provider 2', {'some var': 6},
QgsHistoryProviderRegistry.HistoryEntryOptions())
id_1, ok = reg.addEntry('my provider', {'some var': 5, 'other_var': [1, 2, 3], 'final_var': {'a': 'b'}},
QgsHistoryProviderRegistry.HistoryEntryOptions())
self.assertTrue(ok)
id_2, ok = reg.addEntry('my provider 2', {'some var': 6},
QgsHistoryProviderRegistry.HistoryEntryOptions())
self.assertTrue(ok)

self.assertEqual(len(reg.queryEntries()), 2)
self.assertEqual(reg.queryEntries()[0].providerId, 'my provider')
@@ -105,8 +107,22 @@ def test_registry_entries(self):
self.assertEqual(reg.queryEntries()[1].timestamp.date(), QDateTime.currentDateTime().date())
self.assertEqual(reg.queryEntries()[1].entry, {'some var': 6})

entry, ok = reg.entry(1111)
self.assertFalse(ok)
entry, ok = reg.entry(id_1)
self.assertTrue(ok)
self.assertEqual(entry.providerId, 'my provider')
self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date())
self.assertEqual(entry.entry, {'some var': 5, 'other_var': [1, 2, 3], 'final_var': {'a': 'b'}})
entry, ok = reg.entry(id_2)
self.assertTrue(ok)
self.assertEqual(entry.providerId, 'my provider 2')
self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date())
self.assertEqual(entry.entry, {'some var': 6})

entry = QgsHistoryEntry('my provider 3', QDateTime(2021, 1, 2, 3, 4, 5), {'var': 7})
reg.addEntry(entry)
id_3, ok = reg.addEntry(entry)
self.assertTrue(ok)
self.assertEqual(len(reg.queryEntries()), 3)
self.assertEqual(reg.queryEntries()[0].providerId, 'my provider')
self.assertEqual(reg.queryEntries()[0].timestamp.date(), QDateTime.currentDateTime().date())
@@ -144,6 +160,13 @@ def test_registry_entries(self):
self.assertEqual(len(entries), 1)
self.assertEqual(entries[0].providerId, 'my provider 3')

# update an entry
self.assertTrue(reg.updateEntry(id_1, {'new_props': 54}))
entry, ok = reg.entry(id_1)
self.assertEqual(entry.providerId, 'my provider')
self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date())
self.assertEqual(entry.entry, {'new_props': 54})

self.assertTrue(reg.clearHistory(Qgis.HistoryProviderBackend.LocalProfile))
self.assertFalse(reg.queryEntries())

0 comments on commit af03701

Please sign in to comment.