Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[feature][processing] Add a last_value function to the aggregate algo…
…rithm
  • Loading branch information
nirvn committed Mar 31, 2021
1 parent 7715a12 commit bbe9e89
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
20 changes: 15 additions & 5 deletions src/analysis/processing/qgsalgorithmaggregate.cpp
Expand Up @@ -83,7 +83,7 @@ bool QgsAggregateAlgorithm::prepareAlgorithm( const QVariantMap &parameters, Qgs
mGeometryExpression = createExpression( QStringLiteral( "collect($geometry, %1)" ).arg( mGroupBy ), context );

const QVariantList aggregates = parameters.value( QStringLiteral( "AGGREGATES" ) ).toList();

int currentAttributeIndex = 0;
for ( const QVariant &aggregate : aggregates )
{
const QVariantMap aggregateDef = aggregate.toMap();
Expand All @@ -109,6 +109,11 @@ bool QgsAggregateAlgorithm::prepareAlgorithm( const QVariantMap &parameters, Qgs
{
expression = source;
}
else if ( aggregateType == QLatin1String( "last_value" ) )
{
expression = source;
mAttributesRequireLastFeature << currentAttributeIndex;
}
else if ( aggregateType == QLatin1String( "concatenate" ) || aggregateType == QLatin1String( "concatenate_unique" ) )
{
expression = QStringLiteral( "%1(%2, %3, %4, \'%5\')" ).arg( aggregateType,
Expand All @@ -122,6 +127,7 @@ bool QgsAggregateAlgorithm::prepareAlgorithm( const QVariantMap &parameters, Qgs
expression = QStringLiteral( "%1(%2, %3)" ).arg( aggregateType, source, mGroupBy );
}
mExpressions.append( createExpression( expression, context ) );
currentAttributeIndex++;
}

return true;
Expand Down Expand Up @@ -157,8 +163,8 @@ QVariantMap QgsAggregateAlgorithm::processAlgorithm( const QVariantMap &paramete
// upgrade group by value to a list, so that we get correct behavior with the QHash
const QVariantList key = groupByValue.type() == QVariant::List ? groupByValue.toList() : ( QVariantList() << groupByValue );

auto groupIt = groups.constFind( key );
if ( groupIt == groups.constEnd() )
auto groupIt = groups.find( key );
if ( groupIt == groups.end() )
{
QString id = QStringLiteral( "memory:" );
std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( id,
Expand All @@ -176,13 +182,14 @@ QVariantMap QgsAggregateAlgorithm::processAlgorithm( const QVariantMap &paramete
//store ownership of sink in groupSinks, so that these get deleted automatically if an exception is raised later..
groupSinks.emplace_back( std::move( sink ) );
group.layer = layer;
group.feature = feature;
group.firstFeature = feature;
groups[key] = group;
keys.append( key );
}
else
{
groupIt->sink->addFeature( feature, QgsFeatureSink::FastInsert );
groupIt->lastFeature = feature;
}

current++;
Expand Down Expand Up @@ -210,7 +217,7 @@ QVariantMap QgsAggregateAlgorithm::processAlgorithm( const QVariantMap &paramete

QgsExpressionContext exprContext = createExpressionContext( parameters, context );
exprContext.appendScope( QgsExpressionContextUtils::layerScope( group.layer ) );
exprContext.setFeature( group.feature );
exprContext.setFeature( group.firstFeature );

QgsGeometry geometry = mGeometryExpression.evaluate( &exprContext ).value< QgsGeometry >();
if ( mGeometryExpression.hasEvalError() )
Expand All @@ -234,8 +241,10 @@ QVariantMap QgsAggregateAlgorithm::processAlgorithm( const QVariantMap &paramete

QgsAttributes attributes;
attributes.reserve( mExpressions.size() );
int currentAttributeIndex = 0;
for ( auto it = mExpressions.begin(); it != mExpressions.end(); ++it )
{
exprContext.setFeature( mAttributesRequireLastFeature.contains( currentAttributeIndex ) ? group.lastFeature : group.firstFeature );
if ( it->isValid() )
{
const QVariant value = it->evaluate( &exprContext );
Expand All @@ -249,6 +258,7 @@ QVariantMap QgsAggregateAlgorithm::processAlgorithm( const QVariantMap &paramete
{
attributes.append( QVariant() );
}
currentAttributeIndex++;
}

// Write output feature
Expand Down
4 changes: 3 additions & 1 deletion src/analysis/processing/qgsalgorithmaggregate.h
Expand Up @@ -62,13 +62,15 @@ class QgsAggregateAlgorithm : public QgsProcessingAlgorithm

QgsFields mFields;
QList< QgsExpression > mExpressions;
QList< int > mAttributesRequireLastFeature;
QgsDistanceArea mDa;

struct Group
{
QgsFeatureSink *sink = nullptr;
QgsMapLayer *layer = nullptr;
QgsFeature feature;
QgsFeature firstFeature;
QgsFeature lastFeature;
};

};
Expand Down
3 changes: 2 additions & 1 deletion src/gui/processing/qgsprocessingaggregatewidgets.cpp
Expand Up @@ -566,7 +566,8 @@ const QStringList QgsAggregateMappingWidget::AggregateDelegate::aggregates()
static std::once_flag initialized;
std::call_once( initialized, [ = ]( )
{
sAggregates << QStringLiteral( "first_value" );
sAggregates << QStringLiteral( "first_value" )
<< QStringLiteral( "last_value" );

const QList<QgsExpressionFunction *> functions = QgsExpression::Functions();
for ( const QgsExpressionFunction *function : functions )
Expand Down

0 comments on commit bbe9e89

Please sign in to comment.