Skip to content

Commit eb0c301

Browse files
committedJul 13, 2017
Push minimumValues/maximumValues up to QgsFeatureSource base class
Allows these methods to be called on feature sources
1 parent cfbed91 commit eb0c301

13 files changed

+205
-6
lines changed
 

‎python/core/processing/qgsprocessingutils.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ class QgsProcessingFeatureSource : QgsFeatureSource
232232

233233
virtual QString sourceName() const;
234234

235+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
236+
237+
virtual QVariant minimumValue( int fieldIndex ) const;
238+
239+
virtual QVariant maximumValue( int fieldIndex ) const;
240+
235241

236242
};
237243

‎python/core/qgsfeaturesource.sip

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,31 @@ class QgsFeatureSource
8181
If specified, the ``limit`` option can be used to limit the number of returned values.
8282
The base class implementation uses a non-optimised approach of looping through
8383
all features in the source.
84+
.. seealso:: minimumValue()
85+
.. seealso:: maximumValue()
8486
:rtype: set of QVariant
8587
%End
8688

89+
virtual QVariant minimumValue( int fieldIndex ) const;
90+
%Docstring
91+
Returns the minimum value for an attribute column or an invalid variant in case of error.
92+
The base class implementation uses a non-optimised approach of looping through
93+
all features in the source.
94+
.. seealso:: maximumValue()
95+
.. seealso:: uniqueValues()
96+
:rtype: QVariant
97+
%End
98+
99+
virtual QVariant maximumValue( int fieldIndex ) const;
100+
%Docstring
101+
Returns the maximum value for an attribute column or an invalid variant in case of error.
102+
The base class implementation uses a non-optimised approach of looping through
103+
all features in the source.
104+
.. seealso:: minimumValue()
105+
.. seealso:: uniqueValues()
106+
:rtype: QVariant
107+
%End
108+
87109
virtual QgsRectangle sourceExtent() const;
88110
%Docstring
89111
Returns the extent of all geometries from the source.

‎python/core/qgsvectorlayer.sip

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,8 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
15371537
:rtype: list of str
15381538
%End
15391539

1540-
QVariant minimumValue( int index ) const;
1540+
virtual QVariant minimumValue( int index ) const;
1541+
15411542
%Docstring
15421543
Returns the minimum value for an attribute column or an invalid variant in case of error.
15431544
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
15481549
:rtype: QVariant
15491550
%End
15501551

1551-
QVariant maximumValue( int index ) const;
1552+
virtual QVariant maximumValue( int index ) const;
1553+
15521554
%Docstring
15531555
Returns the maximum value for an attribute column or an invalid variant in case of error.
15541556
Note that in some circumstances when unsaved changes are present for the layer then the

‎src/core/processing/qgsprocessingutils.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,18 @@ QString QgsProcessingFeatureSource::sourceName() const
566566
return mSource->sourceName();
567567

568568
}
569+
570+
QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
571+
{
572+
return mSource->uniqueValues( fieldIndex, limit );
573+
}
574+
575+
QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
576+
{
577+
return mSource->minimumValue( fieldIndex );
578+
}
579+
580+
QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
581+
{
582+
return mSource->maximumValue( fieldIndex );
583+
}

‎src/core/processing/qgsprocessingutils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource
282282
QgsWkbTypes::Type wkbType() const override;
283283
long featureCount() const override;
284284
QString sourceName() const override;
285+
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;
286+
QVariant minimumValue( int fieldIndex ) const override;
287+
QVariant maximumValue( int fieldIndex ) const override;
285288

286289
private:
287290

‎src/core/qgsfeaturesource.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,52 @@ QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
4040
return values;
4141
}
4242

43+
QVariant QgsFeatureSource::minimumValue( int fieldIndex ) const
44+
{
45+
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
46+
return QVariant();
47+
48+
QgsFeatureRequest req;
49+
req.setFlags( QgsFeatureRequest::NoGeometry );
50+
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
51+
52+
QVariant min;
53+
QgsFeatureIterator it = getFeatures( req );
54+
QgsFeature f;
55+
while ( it.nextFeature( f ) )
56+
{
57+
QVariant v = f.attribute( fieldIndex );
58+
if ( v.isValid() && qgsVariantLessThan( v, min ) )
59+
{
60+
min = v;
61+
}
62+
}
63+
return min;
64+
}
65+
66+
QVariant QgsFeatureSource::maximumValue( int fieldIndex ) const
67+
{
68+
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
69+
return QVariant();
70+
71+
QgsFeatureRequest req;
72+
req.setFlags( QgsFeatureRequest::NoGeometry );
73+
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
74+
75+
QVariant max;
76+
QgsFeatureIterator it = getFeatures( req );
77+
QgsFeature f;
78+
while ( it.nextFeature( f ) )
79+
{
80+
QVariant v = f.attribute( fieldIndex );
81+
if ( v.isValid() && qgsVariantGreaterThan( v, max ) )
82+
{
83+
max = v;
84+
}
85+
}
86+
return max;
87+
}
88+
4389
QgsRectangle QgsFeatureSource::sourceExtent() const
4490
{
4591
QgsRectangle r;

‎src/core/qgsfeaturesource.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,27 @@ class CORE_EXPORT QgsFeatureSource
8989
* If specified, the \a limit option can be used to limit the number of returned values.
9090
* The base class implementation uses a non-optimised approach of looping through
9191
* all features in the source.
92+
* \see minimumValue()
93+
* \see maximumValue()
9294
*/
9395
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
9496

97+
/** Returns the minimum value for an attribute column or an invalid variant in case of error.
98+
* The base class implementation uses a non-optimised approach of looping through
99+
* all features in the source.
100+
* \see maximumValue()
101+
* \see uniqueValues()
102+
*/
103+
virtual QVariant minimumValue( int fieldIndex ) const;
104+
105+
/** Returns the maximum value for an attribute column or an invalid variant in case of error.
106+
* The base class implementation uses a non-optimised approach of looping through
107+
* all features in the source.
108+
* \see minimumValue()
109+
* \see uniqueValues()
110+
*/
111+
virtual QVariant maximumValue( int fieldIndex ) const;
112+
95113
/**
96114
* Returns the extent of all geometries from the source.
97115
* The base class implementation uses a non-optimised approach of looping through

‎src/core/qgsvectordataprovider.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
177177
* and maximal values. If provider has facilities to retrieve minimal
178178
* value directly, override this function.
179179
*/
180-
virtual QVariant minimumValue( int index ) const;
180+
virtual QVariant minimumValue( int index ) const override;
181181

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

192192
/**
193193
* Returns unique string values of an attribute which contain a specified subset string. Subset

‎src/core/qgsvectorlayer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,7 +1452,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
14521452
* \see maximumValue()
14531453
* \see uniqueValues()
14541454
*/
1455-
QVariant minimumValue( int index ) const;
1455+
QVariant minimumValue( int index ) const override;
14561456

14571457
/** Returns the maximum value for an attribute column or an invalid variant in case of error.
14581458
* 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
14611461
* \see minimumValue()
14621462
* \see uniqueValues()
14631463
*/
1464-
QVariant maximumValue( int index ) const;
1464+
QVariant maximumValue( int index ) const override;
14651465

14661466
/** Calculates an aggregated value from the layer's features.
14671467
* \param aggregate aggregate to calculate

‎tests/src/python/featuresourcetestbase.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,15 @@ def testGetFeaturesWithGeometry(self):
635635

636636
assert f.hasGeometry(), 'Expected geometry, got none'
637637
self.assertTrue(f.isValid())
638+
639+
def testUniqueValues(self):
640+
self.assertEqual(set(self.source.uniqueValues(1)), set([-200, 100, 200, 300, 400]))
641+
assert set(['Apple', 'Honey', 'Orange', 'Pear', NULL]) == set(self.source.uniqueValues(2)), 'Got {}'.format(set(self.source.uniqueValues(2)))
642+
643+
def testMinimumValue(self):
644+
self.assertEqual(self.source.minimumValue(1), -200)
645+
self.assertEqual(self.source.minimumValue(2), 'Apple')
646+
647+
def testMaximumValue(self):
648+
self.assertEqual(self.source.maximumValue(1), 400)
649+
self.assertEqual(self.source.maximumValue(2), 'Pear')

‎tests/src/python/test_qgsfeaturesource.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ def testUniqueValues(self):
6262
self.assertEqual(layer.dataProvider().uniqueValues(0), {'test', 'test2', 'test3', 'test4'})
6363
self.assertEqual(layer.dataProvider().uniqueValues(1), {1, 3, 3, 4})
6464

65+
def testMinValues(self):
66+
"""
67+
Test retrieving min values using base class method
68+
"""
69+
70+
# memory provider uses base class method
71+
layer = createLayerWithFivePoints()
72+
self.assertFalse(layer.dataProvider().minimumValue(-1))
73+
self.assertFalse(layer.dataProvider().minimumValue(100))
74+
self.assertEqual(layer.dataProvider().minimumValue(0), 'test')
75+
self.assertEqual(layer.dataProvider().minimumValue(1), 1)
76+
77+
def testMaxValues(self):
78+
"""
79+
Test retrieving min values using base class method
80+
"""
81+
82+
# memory provider uses base class method
83+
layer = createLayerWithFivePoints()
84+
self.assertFalse(layer.dataProvider().maximumValue(-1))
85+
self.assertFalse(layer.dataProvider().maximumValue(100))
86+
self.assertEqual(layer.dataProvider().maximumValue(0), 'test4')
87+
self.assertEqual(layer.dataProvider().maximumValue(1), 4)
88+
6589

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

‎tests/src/python/test_qgsvectorlayer.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,6 +2511,12 @@ def testOrderBy(self):
25112511
"""
25122512
pass
25132513

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

25152521
class TestQgsVectorLayerSourceChangedGeometriesInBuffer(unittest.TestCase, FeatureSourceTestCase):
25162522

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

2670+
def testUniqueValues(self):
2671+
""" Skip unique values test - as noted in the docs this is unreliable when features are in the buffer
2672+
"""
2673+
pass
2674+
2675+
def testMinimumValue(self):
2676+
""" Skip min values test - as noted in the docs this is unreliable when features are in the buffer
2677+
"""
2678+
pass
2679+
2680+
def testMaximumValue(self):
2681+
""" Skip max values test - as noted in the docs this is unreliable when features are in the buffer
2682+
"""
2683+
pass
2684+
26642685

26652686
class TestQgsVectorLayerSourceDeletedFeaturesInBuffer(unittest.TestCase, FeatureSourceTestCase):
26662687

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

2770+
def testUniqueValues(self):
2771+
""" Skip unique values test - as noted in the docs this is unreliable when features are in the buffer
2772+
"""
2773+
pass
2774+
2775+
def testMinimumValue(self):
2776+
""" Skip min values test - as noted in the docs this is unreliable when features are in the buffer
2777+
"""
2778+
pass
2779+
2780+
def testMaximumValue(self):
2781+
""" Skip max values test - as noted in the docs this is unreliable when features are in the buffer
2782+
"""
2783+
pass
2784+
27492785
# TODO:
27502786
# - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect
27512787
# - more join tests

‎tests/src/python/test_qgsvectorlayercache.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,21 @@ def testGetFeaturesNoGeometry(self):
9090
"""
9191
pass
9292

93+
def testUniqueValues(self):
94+
""" Skip unique values test - not implemented by the cache (yet)
95+
"""
96+
pass
97+
98+
def testMinimumValue(self):
99+
""" Skip min values test - not implemented by the cache (yet)
100+
"""
101+
pass
102+
103+
def testMaximumValue(self):
104+
""" Skip max values test - not implemented by the cache (yet)
105+
"""
106+
pass
107+
93108

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

0 commit comments

Comments
 (0)
Please sign in to comment.