Skip to content

Commit bffd20c

Browse files
github-actions[bot]nyalldawson
authored andcommittedMay 11, 2020
[vector layer] Fix minimumValue/maximumValue for joined and virtual fields
1 parent 805112b commit bffd20c

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed
 

‎src/core/qgsvectorlayer.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,21 +4159,32 @@ QVariant QgsVectorLayer::minimumOrMaximumValue( int index, bool minimum ) const
41594159
.setSubsetOfAttributes( attList ) );
41604160

41614161
QgsFeature f;
4162-
double value = minimum ? std::numeric_limits<double>::max() : -std::numeric_limits<double>::max();
4163-
double currentValue = 0;
4162+
QVariant value;
4163+
QVariant currentValue;
4164+
bool firstValue = true;
41644165
while ( fit.nextFeature( f ) )
41654166
{
4166-
currentValue = f.attribute( index ).toDouble();
4167-
if ( ( minimum && currentValue < value ) || ( !minimum && currentValue > value ) )
4167+
currentValue = f.attribute( index );
4168+
if ( currentValue.isNull() )
4169+
continue;
4170+
if ( firstValue )
41684171
{
41694172
value = currentValue;
4173+
firstValue = false;
4174+
}
4175+
else
4176+
{
4177+
if ( ( minimum && qgsVariantLessThan( currentValue, value ) ) || ( !minimum && qgsVariantGreaterThan( currentValue, value ) ) )
4178+
{
4179+
value = currentValue;
4180+
}
41704181
}
41714182
}
4172-
return QVariant( value );
4183+
return value;
41734184
}
41744185
}
41754186

4176-
Q_ASSERT_X( false, "QgsVectorLayer::minOrMax()", "Unknown source of the field!" );
4187+
Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximum()", "Unknown source of the field!" );
41774188
return QVariant();
41784189
}
41794190

‎tests/src/python/test_qgsvectorlayer.py

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import tempfile
1717
import shutil
1818

19-
from qgis.PyQt.QtCore import QVariant, Qt
19+
from qgis.PyQt.QtCore import QDate, QDateTime, QVariant, Qt
2020
from qgis.PyQt.QtGui import QPainter, QColor
2121
from qgis.PyQt.QtXml import QDomDocument
2222

@@ -137,20 +137,20 @@ def createLayerWithFivePoints():
137137

138138
def createJoinLayer():
139139
joinLayer = QgsVectorLayer(
140-
"Point?field=x:string&field=y:integer&field=z:integer",
140+
"Point?field=x:string&field=y:integer&field=z:integer&field=date:datetime",
141141
"joinlayer", "memory")
142142
pr = joinLayer.dataProvider()
143143
f1 = QgsFeature()
144-
f1.setAttributes(["foo", 123, 321])
144+
f1.setAttributes(["foo", 123, 321, QDateTime(QDate(2010, 1, 1))])
145145
f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 1)))
146146
f2 = QgsFeature()
147-
f2.setAttributes(["bar", 456, 654])
147+
f2.setAttributes(["bar", 456, 654, QDateTime(QDate(2020, 1, 1))])
148148
f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
149149
f3 = QgsFeature()
150-
f3.setAttributes(["qar", 457, 111])
150+
f3.setAttributes(["qar", 457, 111, None])
151151
f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
152152
f4 = QgsFeature()
153-
f4.setAttributes(["a", 458, 19])
153+
f4.setAttributes(["a", 458, 19, QDateTime(QDate(2012, 1, 1))])
154154
f4.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
155155
assert pr.addFeatures([f1, f2, f3, f4])
156156
assert joinLayer.featureCount() == 4
@@ -1611,11 +1611,11 @@ def test_join(self):
16111611
layer.addJoin(join2)
16121612

16131613
flds = layer.fields()
1614-
self.assertEqual(len(flds), 6)
1614+
self.assertEqual(len(flds), 8)
16151615
self.assertEqual(flds[2].name(), "joinlayer_x")
16161616
self.assertEqual(flds[3].name(), "joinlayer_z")
1617-
self.assertEqual(flds[4].name(), "custom-prefix_x")
1618-
self.assertEqual(flds[5].name(), "custom-prefix_z")
1617+
self.assertEqual(flds[5].name(), "custom-prefix_x")
1618+
self.assertEqual(flds[6].name(), "custom-prefix_z")
16191619
self.assertEqual(flds.fieldOrigin(0), QgsFields.OriginProvider)
16201620
self.assertEqual(flds.fieldOrigin(2), QgsFields.OriginJoin)
16211621
self.assertEqual(flds.fieldOrigin(3), QgsFields.OriginJoin)
@@ -1627,15 +1627,15 @@ def test_join(self):
16271627
fi = layer.getFeatures()
16281628
self.assertTrue(fi.nextFeature(f))
16291629
attrs = f.attributes()
1630-
self.assertEqual(len(attrs), 6)
1630+
self.assertEqual(len(attrs), 8)
16311631
self.assertEqual(attrs[0], "test")
16321632
self.assertEqual(attrs[1], 123)
16331633
self.assertEqual(attrs[2], "foo")
16341634
self.assertEqual(attrs[3], 321)
16351635
self.assertFalse(fi.nextFeature(f))
16361636

16371637
f2 = next(layer.getFeatures(QgsFeatureRequest(f.id())))
1638-
self.assertEqual(len(f2.attributes()), 6)
1638+
self.assertEqual(len(f2.attributes()), 8)
16391639
self.assertEqual(f2[2], "foo")
16401640
self.assertEqual(f2[3], 321)
16411641

@@ -1653,8 +1653,19 @@ def test_JoinStats(self):
16531653
layer.addJoin(join)
16541654

16551655
# stats on joined fields should only include values present by join
1656+
1657+
# strings
1658+
self.assertEqual(layer.minimumValue(2), "foo")
1659+
self.assertEqual(layer.maximumValue(2), "qar")
1660+
1661+
# numbers
16561662
self.assertEqual(layer.minimumValue(3), 111)
16571663
self.assertEqual(layer.maximumValue(3), 321)
1664+
1665+
# dates (maximumValue also tests we properly handle null values by skipping those)
1666+
self.assertEqual(layer.minimumValue(4), QDateTime(QDate(2010, 1, 1)))
1667+
self.assertEqual(layer.maximumValue(4), QDateTime(QDate(2010, 1, 1)))
1668+
16581669
self.assertEqual(set(layer.uniqueValues(3)), set([111, 321]))
16591670

16601671
def test_valid_join_when_opening_project(self):
@@ -1872,6 +1883,28 @@ def testMaxValue(self):
18721883
self.assertTrue(layer.changeAttributeValue(f1_id, 1, 1001))
18731884
self.assertEqual(layer.maximumValue(1), 1001)
18741885

1886+
def testMinMaxInVirtualField(self):
1887+
"""
1888+
Test minimum and maximum values in a virtual field
1889+
"""
1890+
layer = QgsVectorLayer("Point?field=fldstr:string", "layer", "memory")
1891+
pr = layer.dataProvider()
1892+
1893+
int_values = ['2010-01-01', None, '2020-01-01']
1894+
features = []
1895+
for i in int_values:
1896+
f = QgsFeature()
1897+
f.setFields(layer.fields())
1898+
f.setAttributes([i])
1899+
features.append(f)
1900+
assert pr.addFeatures(features)
1901+
1902+
field = QgsField('virtual', QVariant.Date)
1903+
layer.addExpressionField('to_date("fldstr")', field)
1904+
self.assertEqual(len(layer.getFeature(1).attributes()), 2)
1905+
self.assertEqual(layer.minimumValue(1), QDate(2010, 1, 1))
1906+
self.assertEqual(layer.maximumValue(1), QDate(2020, 1, 1))
1907+
18751908
def test_InvalidOperations(self):
18761909
layer = createLayerWithOnePoint()
18771910

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.