Skip to content
Permalink
Browse files

Push minimumValues/maximumValues up to QgsFeatureSource base class

Allows these methods to be called on feature sources
  • Loading branch information
nyalldawson committed Jul 13, 2017
1 parent cfbed91 commit eb0c3015f96c4a4048dc1e4be470b875d16b95fa
@@ -232,6 +232,12 @@ class QgsProcessingFeatureSource : QgsFeatureSource

virtual QString sourceName() const;

virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;

virtual QVariant minimumValue( int fieldIndex ) const;

virtual QVariant maximumValue( int fieldIndex ) const;


};

@@ -81,9 +81,31 @@ class QgsFeatureSource
If specified, the ``limit`` option can be used to limit the number of returned values.
The base class implementation uses a non-optimised approach of looping through
all features in the source.
.. seealso:: minimumValue()
.. seealso:: maximumValue()
:rtype: set of QVariant
%End

virtual QVariant minimumValue( int fieldIndex ) const;
%Docstring
Returns the minimum value for an attribute column or an invalid variant in case of error.
The base class implementation uses a non-optimised approach of looping through
all features in the source.
.. seealso:: maximumValue()
.. seealso:: uniqueValues()
:rtype: QVariant
%End

virtual QVariant maximumValue( int fieldIndex ) const;
%Docstring
Returns the maximum value for an attribute column or an invalid variant in case of error.
The base class implementation uses a non-optimised approach of looping through
all features in the source.
.. seealso:: minimumValue()
.. seealso:: uniqueValues()
:rtype: QVariant
%End

virtual QgsRectangle sourceExtent() const;
%Docstring
Returns the extent of all geometries from the source.
@@ -1537,7 +1537,8 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
:rtype: list of str
%End

QVariant minimumValue( int index ) const;
virtual QVariant minimumValue( int index ) const;

%Docstring
Returns the minimum value for an attribute column or an invalid variant in case of error.
Note that in some circumstances when unsaved changes are present for the layer then the
@@ -1548,7 +1549,8 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
:rtype: QVariant
%End

QVariant maximumValue( int index ) const;
virtual QVariant maximumValue( int index ) const;

%Docstring
Returns the maximum value for an attribute column or an invalid variant in case of error.
Note that in some circumstances when unsaved changes are present for the layer then the
@@ -566,3 +566,18 @@ QString QgsProcessingFeatureSource::sourceName() const
return mSource->sourceName();

}

QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
{
return mSource->uniqueValues( fieldIndex, limit );
}

QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
{
return mSource->minimumValue( fieldIndex );
}

QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
{
return mSource->maximumValue( fieldIndex );
}
@@ -282,6 +282,9 @@ class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource
QgsWkbTypes::Type wkbType() const override;
long featureCount() const override;
QString sourceName() const override;
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;
QVariant minimumValue( int fieldIndex ) const override;
QVariant maximumValue( int fieldIndex ) const override;

private:

@@ -40,6 +40,52 @@ QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
return values;
}

QVariant QgsFeatureSource::minimumValue( int fieldIndex ) const
{
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
return QVariant();

QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );

QVariant min;
QgsFeatureIterator it = getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
QVariant v = f.attribute( fieldIndex );
if ( v.isValid() && qgsVariantLessThan( v, min ) )
{
min = v;
}
}
return min;
}

QVariant QgsFeatureSource::maximumValue( int fieldIndex ) const
{
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
return QVariant();

QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );

QVariant max;
QgsFeatureIterator it = getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
QVariant v = f.attribute( fieldIndex );
if ( v.isValid() && qgsVariantGreaterThan( v, max ) )
{
max = v;
}
}
return max;
}

QgsRectangle QgsFeatureSource::sourceExtent() const
{
QgsRectangle r;
@@ -89,9 +89,27 @@ class CORE_EXPORT QgsFeatureSource
* If specified, the \a limit option can be used to limit the number of returned values.
* The base class implementation uses a non-optimised approach of looping through
* all features in the source.
* \see minimumValue()
* \see maximumValue()
*/
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;

/** Returns the minimum value for an attribute column or an invalid variant in case of error.
* The base class implementation uses a non-optimised approach of looping through
* all features in the source.
* \see maximumValue()
* \see uniqueValues()
*/
virtual QVariant minimumValue( int fieldIndex ) const;

/** Returns the maximum value for an attribute column or an invalid variant in case of error.
* The base class implementation uses a non-optimised approach of looping through
* all features in the source.
* \see minimumValue()
* \see uniqueValues()
*/
virtual QVariant maximumValue( int fieldIndex ) const;

/**
* Returns the extent of all geometries from the source.
* The base class implementation uses a non-optimised approach of looping through
@@ -177,7 +177,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
* and maximal values. If provider has facilities to retrieve minimal
* value directly, override this function.
*/
virtual QVariant minimumValue( int index ) const;
virtual QVariant minimumValue( int index ) const override;

/**
* Returns the maximum value of an attribute
@@ -187,7 +187,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
* and maximal values. If provider has facilities to retrieve maximal
* value directly, override this function.
*/
virtual QVariant maximumValue( int index ) const;
virtual QVariant maximumValue( int index ) const override;

/**
* Returns unique string values of an attribute which contain a specified subset string. Subset
@@ -1452,7 +1452,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* \see maximumValue()
* \see uniqueValues()
*/
QVariant minimumValue( int index ) const;
QVariant minimumValue( int index ) const override;

/** Returns the maximum value for an attribute column or an invalid variant in case of error.
* Note that in some circumstances when unsaved changes are present for the layer then the
@@ -1461,7 +1461,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* \see minimumValue()
* \see uniqueValues()
*/
QVariant maximumValue( int index ) const;
QVariant maximumValue( int index ) const override;

/** Calculates an aggregated value from the layer's features.
* \param aggregate aggregate to calculate
@@ -635,3 +635,15 @@ def testGetFeaturesWithGeometry(self):

assert f.hasGeometry(), 'Expected geometry, got none'
self.assertTrue(f.isValid())

def testUniqueValues(self):
self.assertEqual(set(self.source.uniqueValues(1)), set([-200, 100, 200, 300, 400]))
assert set(['Apple', 'Honey', 'Orange', 'Pear', NULL]) == set(self.source.uniqueValues(2)), 'Got {}'.format(set(self.source.uniqueValues(2)))

def testMinimumValue(self):
self.assertEqual(self.source.minimumValue(1), -200)
self.assertEqual(self.source.minimumValue(2), 'Apple')

def testMaximumValue(self):
self.assertEqual(self.source.maximumValue(1), 400)
self.assertEqual(self.source.maximumValue(2), 'Pear')
@@ -62,6 +62,30 @@ def testUniqueValues(self):
self.assertEqual(layer.dataProvider().uniqueValues(0), {'test', 'test2', 'test3', 'test4'})
self.assertEqual(layer.dataProvider().uniqueValues(1), {1, 3, 3, 4})

def testMinValues(self):
"""
Test retrieving min values using base class method
"""

# memory provider uses base class method
layer = createLayerWithFivePoints()
self.assertFalse(layer.dataProvider().minimumValue(-1))
self.assertFalse(layer.dataProvider().minimumValue(100))
self.assertEqual(layer.dataProvider().minimumValue(0), 'test')
self.assertEqual(layer.dataProvider().minimumValue(1), 1)

def testMaxValues(self):
"""
Test retrieving min values using base class method
"""

# memory provider uses base class method
layer = createLayerWithFivePoints()
self.assertFalse(layer.dataProvider().maximumValue(-1))
self.assertFalse(layer.dataProvider().maximumValue(100))
self.assertEqual(layer.dataProvider().maximumValue(0), 'test4')
self.assertEqual(layer.dataProvider().maximumValue(1), 4)


if __name__ == '__main__':
unittest.main()
@@ -2511,6 +2511,12 @@ def testOrderBy(self):
"""
pass

def testMinimumValue(self):
""" Skip min values test - due to inconsistencies in how null values are treated by providers.
They are included here, but providers don't include them.... which is right?
"""
pass


class TestQgsVectorLayerSourceChangedGeometriesInBuffer(unittest.TestCase, FeatureSourceTestCase):

@@ -2661,6 +2667,21 @@ def testOrderBy(self):
"""
pass

def testUniqueValues(self):
""" Skip unique values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass

def testMinimumValue(self):
""" Skip min values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass

def testMaximumValue(self):
""" Skip max values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass


class TestQgsVectorLayerSourceDeletedFeaturesInBuffer(unittest.TestCase, FeatureSourceTestCase):

@@ -2746,6 +2767,21 @@ def testOrderBy(self):
"""
pass

def testUniqueValues(self):
""" Skip unique values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass

def testMinimumValue(self):
""" Skip min values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass

def testMaximumValue(self):
""" Skip max values test - as noted in the docs this is unreliable when features are in the buffer
"""
pass

# TODO:
# - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect
# - more join tests
@@ -90,6 +90,21 @@ def testGetFeaturesNoGeometry(self):
"""
pass

def testUniqueValues(self):
""" Skip unique values test - not implemented by the cache (yet)
"""
pass

def testMinimumValue(self):
""" Skip min values test - not implemented by the cache (yet)
"""
pass

def testMaximumValue(self):
""" Skip max values test - not implemented by the cache (yet)
"""
pass


if __name__ == '__main__':
unittest.main()

0 comments on commit eb0c301

Please sign in to comment.
You can’t perform that action at this time.