Merge pull request #4848 from nyalldawson/virtual_agg

Fix aggregate calculation in virtual fields
This commit is contained in:
Nyall Dawson 2017-07-17 12:49:47 +10:00 committed by GitHub
commit 4e5597ab72
4 changed files with 42 additions and 1 deletions

View File

@ -61,6 +61,7 @@ class QgsVectorLayerFeatureSource : QgsAbstractFeatureSource
};

View File

@ -79,6 +79,9 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
}
#endif
}
std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
mLayerScope = *layerScope;
}
QgsVectorLayerFeatureSource::~QgsVectorLayerFeatureSource()
@ -614,6 +617,15 @@ void QgsVectorLayerFeatureIterator::prepareExpression( int fieldIdx )
exp->setAreaUnits( QgsProject::instance()->areaUnits() );
exp->prepare( mExpressionContext.get() );
Q_FOREACH ( const QString &col, exp->referencedColumns() )
{
if ( mSource->fields().lookupField( col ) == fieldIdx )
{
// circular reference - expression depends on column itself
delete exp;
return;
}
}
mExpressionFieldInfo.insert( fieldIdx, exp );
Q_FOREACH ( const QString &col, exp->referencedColumns() )
@ -644,7 +656,7 @@ void QgsVectorLayerFeatureIterator::prepareFields()
mExpressionContext.reset( new QgsExpressionContext() );
mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
mExpressionContext->setFields( mSource->mFields );
mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();

View File

@ -84,6 +84,8 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
QgsFields mFields;
QgsExpressionContextScope mLayerScope;
bool mHasEditBuffer;
// A deep-copy is only performed, if the original maps change

View File

@ -1609,6 +1609,11 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
self.assertEqual(layer.pendingFields().count(), cnt)
# expression field which references itself
idx = layer.addExpressionField('sum(test2)', QgsField('test2', QVariant.LongLong))
fet = next(layer.getFeatures())
self.assertEqual(fet['test2'], NULL)
def test_ExpressionFieldEllipsoidLengthCalculation(self):
#create a temporary layer
temp_layer = QgsVectorLayer("LineString?crs=epsg:3111&field=pk:int", "vl", "memory")
@ -1829,6 +1834,27 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
self.assertTrue(ok)
self.assertEqual(val, 'this is a test')
def testAggregateInVirtualField(self):
"""
Test aggregates in a virtual field
"""
layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory")
pr = layer.dataProvider()
int_values = [4, 2, 3, 2, 5, None, 8]
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.Double)
layer.addExpressionField('sum(fldint*2)', field)
vals = [f['virtual'] for f in layer.getFeatures()]
self.assertEqual(vals, [48, 48, 48, 48, 48, 48, 48])
def onLayerOpacityChanged(self, tr):
self.opacityTest = tr