Navigation Menu

Skip to content

Commit

Permalink
Merge pull request #4848 from nyalldawson/virtual_agg
Browse files Browse the repository at this point in the history
Fix aggregate calculation in virtual fields
  • Loading branch information
nyalldawson committed Jul 17, 2017
2 parents 3a2710e + 8711473 commit 4e5597a
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 1 deletion.
1 change: 1 addition & 0 deletions python/core/qgsvectorlayerfeatureiterator.sip
Expand Up @@ -61,6 +61,7 @@ class QgsVectorLayerFeatureSource : QgsAbstractFeatureSource




};


Expand Down
14 changes: 13 additions & 1 deletion src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -79,6 +79,9 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
}
#endif
}

std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
mLayerScope = *layerScope;
}

QgsVectorLayerFeatureSource::~QgsVectorLayerFeatureSource()
Expand Down Expand Up @@ -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() )
Expand Down Expand Up @@ -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();

Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions tests/src/python/test_qgsvectorlayer.py
Expand Up @@ -1609,6 +1609,11 @@ def test_ExpressionField(self):

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")
Expand Down Expand Up @@ -1829,6 +1834,27 @@ def testAggregate(self):
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

Expand Down

0 comments on commit 4e5597a

Please sign in to comment.