Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[vector layer] Fix minimumValue/maximumValue for joined and virtual f…
…ields
  • Loading branch information
github-actions[bot] authored and nyalldawson committed May 11, 2020
1 parent 805112b commit bffd20c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 17 deletions.
23 changes: 17 additions & 6 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -4159,21 +4159,32 @@ QVariant QgsVectorLayer::minimumOrMaximumValue( int index, bool minimum ) const
.setSubsetOfAttributes( attList ) );

QgsFeature f;
double value = minimum ? std::numeric_limits<double>::max() : -std::numeric_limits<double>::max();
double currentValue = 0;
QVariant value;
QVariant currentValue;
bool firstValue = true;
while ( fit.nextFeature( f ) )
{
currentValue = f.attribute( index ).toDouble();
if ( ( minimum && currentValue < value ) || ( !minimum && currentValue > value ) )
currentValue = f.attribute( index );
if ( currentValue.isNull() )
continue;
if ( firstValue )
{
value = currentValue;
firstValue = false;
}
else
{
if ( ( minimum && qgsVariantLessThan( currentValue, value ) ) || ( !minimum && qgsVariantGreaterThan( currentValue, value ) ) )
{
value = currentValue;
}
}
}
return QVariant( value );
return value;
}
}

Q_ASSERT_X( false, "QgsVectorLayer::minOrMax()", "Unknown source of the field!" );
Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximum()", "Unknown source of the field!" );
return QVariant();
}

Expand Down
55 changes: 44 additions & 11 deletions tests/src/python/test_qgsvectorlayer.py
Expand Up @@ -16,7 +16,7 @@
import tempfile
import shutil

from qgis.PyQt.QtCore import QVariant, Qt
from qgis.PyQt.QtCore import QDate, QDateTime, QVariant, Qt
from qgis.PyQt.QtGui import QPainter, QColor
from qgis.PyQt.QtXml import QDomDocument

Expand Down Expand Up @@ -137,20 +137,20 @@ def createLayerWithFivePoints():

def createJoinLayer():
joinLayer = QgsVectorLayer(
"Point?field=x:string&field=y:integer&field=z:integer",
"Point?field=x:string&field=y:integer&field=z:integer&field=date:datetime",
"joinlayer", "memory")
pr = joinLayer.dataProvider()
f1 = QgsFeature()
f1.setAttributes(["foo", 123, 321])
f1.setAttributes(["foo", 123, 321, QDateTime(QDate(2010, 1, 1))])
f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 1)))
f2 = QgsFeature()
f2.setAttributes(["bar", 456, 654])
f2.setAttributes(["bar", 456, 654, QDateTime(QDate(2020, 1, 1))])
f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
f3 = QgsFeature()
f3.setAttributes(["qar", 457, 111])
f3.setAttributes(["qar", 457, 111, None])
f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
f4 = QgsFeature()
f4.setAttributes(["a", 458, 19])
f4.setAttributes(["a", 458, 19, QDateTime(QDate(2012, 1, 1))])
f4.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2, 2)))
assert pr.addFeatures([f1, f2, f3, f4])
assert joinLayer.featureCount() == 4
Expand Down Expand Up @@ -1611,11 +1611,11 @@ def test_join(self):
layer.addJoin(join2)

flds = layer.fields()
self.assertEqual(len(flds), 6)
self.assertEqual(len(flds), 8)
self.assertEqual(flds[2].name(), "joinlayer_x")
self.assertEqual(flds[3].name(), "joinlayer_z")
self.assertEqual(flds[4].name(), "custom-prefix_x")
self.assertEqual(flds[5].name(), "custom-prefix_z")
self.assertEqual(flds[5].name(), "custom-prefix_x")
self.assertEqual(flds[6].name(), "custom-prefix_z")
self.assertEqual(flds.fieldOrigin(0), QgsFields.OriginProvider)
self.assertEqual(flds.fieldOrigin(2), QgsFields.OriginJoin)
self.assertEqual(flds.fieldOrigin(3), QgsFields.OriginJoin)
Expand All @@ -1627,15 +1627,15 @@ def test_join(self):
fi = layer.getFeatures()
self.assertTrue(fi.nextFeature(f))
attrs = f.attributes()
self.assertEqual(len(attrs), 6)
self.assertEqual(len(attrs), 8)
self.assertEqual(attrs[0], "test")
self.assertEqual(attrs[1], 123)
self.assertEqual(attrs[2], "foo")
self.assertEqual(attrs[3], 321)
self.assertFalse(fi.nextFeature(f))

f2 = next(layer.getFeatures(QgsFeatureRequest(f.id())))
self.assertEqual(len(f2.attributes()), 6)
self.assertEqual(len(f2.attributes()), 8)
self.assertEqual(f2[2], "foo")
self.assertEqual(f2[3], 321)

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

# stats on joined fields should only include values present by join

# strings
self.assertEqual(layer.minimumValue(2), "foo")
self.assertEqual(layer.maximumValue(2), "qar")

# numbers
self.assertEqual(layer.minimumValue(3), 111)
self.assertEqual(layer.maximumValue(3), 321)

# dates (maximumValue also tests we properly handle null values by skipping those)
self.assertEqual(layer.minimumValue(4), QDateTime(QDate(2010, 1, 1)))
self.assertEqual(layer.maximumValue(4), QDateTime(QDate(2010, 1, 1)))

self.assertEqual(set(layer.uniqueValues(3)), set([111, 321]))

def test_valid_join_when_opening_project(self):
Expand Down Expand Up @@ -1872,6 +1883,28 @@ def testMaxValue(self):
self.assertTrue(layer.changeAttributeValue(f1_id, 1, 1001))
self.assertEqual(layer.maximumValue(1), 1001)

def testMinMaxInVirtualField(self):
"""
Test minimum and maximum values in a virtual field
"""
layer = QgsVectorLayer("Point?field=fldstr:string", "layer", "memory")
pr = layer.dataProvider()

int_values = ['2010-01-01', None, '2020-01-01']
features = []
for i in int_values:
f = QgsFeature()
f.setFields(layer.fields())
f.setAttributes([i])
features.append(f)
assert pr.addFeatures(features)

field = QgsField('virtual', QVariant.Date)
layer.addExpressionField('to_date("fldstr")', field)
self.assertEqual(len(layer.getFeature(1).attributes()), 2)
self.assertEqual(layer.minimumValue(1), QDate(2010, 1, 1))
self.assertEqual(layer.maximumValue(1), QDate(2020, 1, 1))

def test_InvalidOperations(self):
layer = createLayerWithOnePoint()

Expand Down
Binary file modified tests/testdata/polys_overlapping_with_id.dbf
Binary file not shown.

0 comments on commit bffd20c

Please sign in to comment.