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.
This commit is contained in:
Nyall Dawson 2021-12-18 14:12:01 +10:00
parent 8fef4e4131
commit af03701ab8
4 changed files with 173 additions and 16 deletions

View File

@ -125,7 +125,7 @@ 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.
@ -133,16 +133,48 @@ 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(),

View File

@ -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

View File

@ -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.
*

View File

@ -91,10 +91,12 @@ class TestQgsHistoryProviderRegistry(unittest.TestCase):
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 @@ class TestQgsHistoryProviderRegistry(unittest.TestCase):
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 @@ class TestQgsHistoryProviderRegistry(unittest.TestCase):
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())