[api] Add compare methods to QgsFeatureRequest

This will allow to reduce unnecessary expensive calls
when the request has not really changed.
This commit is contained in:
Alessandro Pasotti 2024-05-31 11:38:05 +02:00
parent 92f182568f
commit f681cd459e
5 changed files with 177 additions and 0 deletions

View File

@ -204,6 +204,10 @@ Create a new empty order by
Create a new order by from a list of clauses
%End
bool operator==( const OrderBy &v ) const;
bool operator!=( const OrderBy &v ) const;
QList<QgsFeatureRequest::OrderByClause> list() const;
%Docstring
Gets a copy as a list of OrderByClauses
@ -275,6 +279,17 @@ construct a request with a filter expression
QgsFeatureRequest( const QgsFeatureRequest &rh );
%Docstring
copy constructor
%End
bool compare( const QgsFeatureRequest &other ) const;
%Docstring
Compare two requests for equality, ignoring Expression Context, Transform Error Callback, Feedback and Invalid Geometry Callback
:param other: the other request
:return: true if the requests are equal in all respects but without checking for Expression Context, Transform Error, Feedback and Invalid Geometry Callback
.. versionadded:: 3.38
%End
~QgsFeatureRequest();

View File

@ -204,6 +204,10 @@ Create a new empty order by
Create a new order by from a list of clauses
%End
bool operator==( const OrderBy &v ) const;
bool operator!=( const OrderBy &v ) const;
QList<QgsFeatureRequest::OrderByClause> list() const;
%Docstring
Gets a copy as a list of OrderByClauses
@ -275,6 +279,17 @@ construct a request with a filter expression
QgsFeatureRequest( const QgsFeatureRequest &rh );
%Docstring
copy constructor
%End
bool compare( const QgsFeatureRequest &other ) const;
%Docstring
Compare two requests for equality, ignoring Expression Context, Transform Error Callback, Feedback and Invalid Geometry Callback
:param other: the other request
:return: true if the requests are equal in all respects but without checking for Expression Context, Transform Error, Feedback and Invalid Geometry Callback
.. versionadded:: 3.38
%End
~QgsFeatureRequest();

View File

@ -98,6 +98,34 @@ QgsFeatureRequest &QgsFeatureRequest::operator=( const QgsFeatureRequest &rh )
return *this;
}
// Relaxed Equality operator
bool QgsFeatureRequest::compare( const QgsFeatureRequest &rh ) const
{
if ( &rh == this )
return true;
return mFlags == rh.mFlags &&
mFilter == rh.mFilter &&
mSpatialFilter == rh.mSpatialFilter &&
mFilterRect == rh.mFilterRect &&
( ( mReferenceGeometry.isNull() && rh.mReferenceGeometry.isNull() ) || mReferenceGeometry.equals( rh.mReferenceGeometry ) ) &&
mDistanceWithin == rh.mDistanceWithin &&
mFilterFid == rh.mFilterFid &&
mFilterFids == rh.mFilterFids &&
( mFilterExpression ? rh.mFilterExpression && *mFilterExpression == *rh.mFilterExpression : !rh.mFilterExpression ) &&
mInvalidGeometryFilter == rh.mInvalidGeometryFilter &&
mAttrs == rh.mAttrs &&
mSimplifyMethod == rh.mSimplifyMethod &&
mLimit == rh.mLimit &&
mOrderBy == rh.mOrderBy &&
mCrs == rh.mCrs &&
mTransformContext == rh.mTransformContext &&
mTimeout == rh.mTimeout &&
mRequestMayBeNested == rh.mRequestMayBeNested;
}
QgsFeatureRequest &QgsFeatureRequest::setFilterRect( const QgsRectangle &rect )
{
mFilterRect = rect;
@ -515,6 +543,25 @@ QgsFeatureRequest::OrderBy::OrderBy( const QList<QgsFeatureRequest::OrderByClaus
}
}
bool QgsFeatureRequest::OrderBy::operator== ( const QgsFeatureRequest::OrderBy &other ) const
{
if ( this == &other )
return true;
if ( size() != other.size() )
return false;
for ( int i = 0; i < size(); ++i )
{
if ( at( i ) != other.at( i ) )
return false;
}
return true;
}
bool QgsFeatureRequest::OrderBy::operator!= ( const QgsFeatureRequest::OrderBy &other ) const
{
return !operator==( other );
}
QList<QgsFeatureRequest::OrderByClause> QgsFeatureRequest::OrderBy::list() const
{
return *this;

View File

@ -230,6 +230,18 @@ class CORE_EXPORT QgsFeatureRequest
*/
CORE_EXPORT OrderBy( const QList<QgsFeatureRequest::OrderByClause> &other );
/**
* Equality operator
* \since QGIS 3.8
*/
CORE_EXPORT bool operator==( const OrderBy &v ) const;
/**
* Inequality operator
* \since QGIS 3.8
*/
CORE_EXPORT bool operator!=( const OrderBy &v ) const;
/**
* Gets a copy as a list of OrderByClauses
*
@ -294,6 +306,14 @@ class CORE_EXPORT QgsFeatureRequest
//! Assignment operator
QgsFeatureRequest &operator=( const QgsFeatureRequest &rh );
/**
* Compare two requests for equality, ignoring Expression Context, Transform Error Callback, Feedback and Invalid Geometry Callback
* \param other the other request
* \return true if the requests are equal in all respects but without checking for Expression Context, Transform Error, Feedback and Invalid Geometry Callback
* \since QGIS 3.38
*/
bool compare( const QgsFeatureRequest &other ) const;
~QgsFeatureRequest();
/**

View File

@ -410,6 +410,86 @@ class TestQgsFeatureRequest(QgisTestCase):
self.assertEqual(req2.distanceWithin(), 1.2)
self.assertEqual(req2.filterRect(), QgsRectangle(-1.2, -1.2, 12.2, 3.2))
def test_compare(self):
req1 = QgsFeatureRequest().setFilterFids([8, 9]).setFilterRect(QgsRectangle(1, 2, 3, 4)).setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid).setLimit(6).setFlags(QgsFeatureRequest.Flag.ExactIntersect).setSubsetOfAttributes([1, 4]).setTimeout(6).setRequestMayBeNested(True)
req2 = QgsFeatureRequest(req1)
self.assertTrue(req1.compare(req1))
self.assertTrue(req1.compare(req2))
req3 = QgsFeatureRequest(req2)
self.assertTrue(req3.compare(req2))
self.assertTrue(req3.compare(req1))
req3.setFilterFids([8, 9, 10])
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setFilterRect(QgsRectangle(1, 2, 3, 5))
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck)
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setLimit(7)
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setFlags(QgsFeatureRequest.Flag.NoGeometry)
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setSubsetOfAttributes([1, 4, 5])
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setTimeout(7)
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
req3.setRequestMayBeNested(False)
self.assertFalse(req3.compare(req1))
req3 = QgsFeatureRequest(req2)
orderClause = QgsFeatureRequest.OrderByClause('a', False)
order = QgsFeatureRequest.OrderBy([orderClause])
req3.setOrderBy(order)
self.assertFalse(req3.compare(req1))
req4 = QgsFeatureRequest(req2)
orderClause = QgsFeatureRequest.OrderByClause('a', False)
order2 = QgsFeatureRequest.OrderBy([orderClause])
req4.setOrderBy(order2)
self.assertTrue(req4.compare(req3))
self.assertTrue(order == order2)
# Expression Context is not checked
req3 = QgsFeatureRequest(req2)
context = QgsExpressionContext()
scope = QgsExpressionContextScope()
scope.setVariable('a', 6)
context.appendScope(scope)
req3.setExpressionContext(context)
self.assertTrue(req3.compare(req1))
def test_order_by_equality(self):
orderClause1 = QgsFeatureRequest.OrderByClause('a', False)
orderClause2 = QgsFeatureRequest.OrderByClause('a', False)
self.assertTrue(orderClause1 == orderClause2)
orderClause2 = QgsFeatureRequest.OrderByClause('b', False)
self.assertFalse(orderClause1 == orderClause2)
orderClause2 = QgsFeatureRequest.OrderByClause('a', True)
self.assertFalse(orderClause1 == orderClause2)
order1 = QgsFeatureRequest.OrderBy([orderClause1])
order2 = QgsFeatureRequest.OrderBy([orderClause1])
self.assertTrue(order1 == order2)
order2 = QgsFeatureRequest.OrderBy([orderClause2])
self.assertFalse(order1 == order2)
order2 = QgsFeatureRequest.OrderBy([orderClause1, orderClause2])
self.assertFalse(order1 == order2)
if __name__ == '__main__':
unittest.main()