mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
[FEATURE] Expose @parent variable in aggregate functions
This makes it possible to access attributes and geometry from the parent feature when in the filter of the "aggregate" expression function. With this in place aggregates can be calculated per feature. E.g. max "measurement" for each point_station per polygon_research_area. Or a default attribute value when digitizing features: aggregate(layer:='countries', aggregate:='max', expression:=\"code\", filter:=intersects( $geometry, geometry(@parent) ) )
This commit is contained in:
parent
fb4578131f
commit
f80a33be65
@ -45,14 +45,20 @@ class QgsExpression
|
||||
|
||||
/**
|
||||
* Get list of columns referenced by the expression.
|
||||
* @note if the returned list contains the QgsFeatureRequest::AllAttributes constant then
|
||||
*
|
||||
* @note If the returned list contains the QgsFeatureRequest::AllAttributes constant then
|
||||
* all attributes from the layer are required for evaluation of the expression.
|
||||
* QgsFeatureRequest::setSubsetOfAttributes automatically handles this case.
|
||||
*
|
||||
* TODO QGIS3: Return QSet<QString>
|
||||
* @see referencedAttributeIndexes()
|
||||
*/
|
||||
QSet<QString> referencedColumns() const;
|
||||
|
||||
/**
|
||||
* Return a list of all variables which are used in this expression.
|
||||
*/
|
||||
QSet<QString> referencedVariables() const;
|
||||
|
||||
/**
|
||||
* Return a list of field name indexes obtained from the provided fields.
|
||||
*
|
||||
@ -560,6 +566,11 @@ class QgsExpression
|
||||
*/
|
||||
virtual QSet<QString> referencedColumns() const = 0;
|
||||
|
||||
/**
|
||||
* Return a list of all variables which are used in this expression.
|
||||
*/
|
||||
virtual QSet<QString> referencedVariables() const = 0;
|
||||
|
||||
/**
|
||||
* Abstract virtual method which returns if the geometry is required to evaluate
|
||||
* this expression.
|
||||
@ -638,6 +649,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
};
|
||||
@ -658,6 +670,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
|
||||
@ -692,6 +705,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
};
|
||||
@ -712,6 +726,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
|
||||
@ -734,6 +749,7 @@ class QgsExpression
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
};
|
||||
|
||||
@ -751,6 +767,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
@ -783,6 +800,7 @@ class QgsExpression
|
||||
virtual QString dump() const;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const;
|
||||
virtual QSet<QString> referencedVariables() const;
|
||||
virtual bool needsGeometry() const;
|
||||
virtual QgsExpression::Node* clone() const;
|
||||
};
|
||||
|
@ -622,7 +622,7 @@ static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*,
|
||||
return QVariant( minVal );
|
||||
}
|
||||
|
||||
static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
|
||||
static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
|
||||
{
|
||||
//lazy eval, so we need to evaluate nodes now
|
||||
|
||||
@ -677,15 +677,28 @@ static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionCon
|
||||
parameters.delimiter = value.toString();
|
||||
}
|
||||
|
||||
QString cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( static_cast< int >( aggregate ) ), subExpression, parameters.filter );
|
||||
if ( context && context->hasCachedValue( cacheKey ) )
|
||||
return context->cachedValue( cacheKey );
|
||||
|
||||
QVariant result;
|
||||
if ( context )
|
||||
{
|
||||
QString cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter );
|
||||
|
||||
QgsExpression subExp( subExpression );
|
||||
if ( subExp.referencedVariables().contains( "parent" ) || subExp.referencedVariables().contains( QString() ) )
|
||||
{
|
||||
cacheKey += ':' + qHash( context->feature() );
|
||||
}
|
||||
|
||||
if ( context && context->hasCachedValue( cacheKey ) )
|
||||
return context->cachedValue( cacheKey );
|
||||
|
||||
QgsExpressionContext subContext( *context );
|
||||
QgsExpressionContextScope* subScope = new QgsExpressionContextScope();
|
||||
subScope->setVariable( "parent", context->feature() );
|
||||
subContext.appendScope( subScope );
|
||||
result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
|
||||
|
||||
if ( ok )
|
||||
context->setCachedValue( cacheKey, result );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -697,9 +710,6 @@ static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionCon
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// cache value
|
||||
if ( context )
|
||||
context->setCachedValue( cacheKey, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3991,6 +4001,14 @@ QSet<QString> QgsExpression::referencedColumns() const
|
||||
return d->mRootNode->referencedColumns();
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::referencedVariables() const
|
||||
{
|
||||
if ( !d->mRootNode )
|
||||
return QSet<QString>();
|
||||
|
||||
return d->mRootNode->referencedVariables();
|
||||
}
|
||||
|
||||
bool QgsExpression::NodeInOperator::needsGeometry() const
|
||||
{
|
||||
bool needs = false;
|
||||
@ -4303,6 +4321,16 @@ QString QgsExpression::NodeUnaryOperator::dump() const
|
||||
return QStringLiteral( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeUnaryOperator::referencedColumns() const
|
||||
{
|
||||
return mOperand->referencedColumns();
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeUnaryOperator::referencedVariables() const
|
||||
{
|
||||
return mOperand->referencedVariables();
|
||||
}
|
||||
|
||||
QgsExpression::Node*QgsExpression::NodeUnaryOperator::clone() const
|
||||
{
|
||||
return new NodeUnaryOperator( mOp, mOperand->clone() );
|
||||
@ -4790,6 +4818,11 @@ QSet<QString> QgsExpression::NodeBinaryOperator::referencedColumns() const
|
||||
return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeBinaryOperator::referencedVariables() const
|
||||
{
|
||||
return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
|
||||
}
|
||||
|
||||
bool QgsExpression::NodeBinaryOperator::needsGeometry() const
|
||||
{
|
||||
return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
|
||||
@ -4993,6 +5026,23 @@ QSet<QString> QgsExpression::NodeFunction::referencedColumns() const
|
||||
return functionColumns;
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeFunction::referencedVariables() const
|
||||
{
|
||||
Function* fd = Functions()[mFnIndex];
|
||||
if ( fd->name() == "var" )
|
||||
{
|
||||
if ( !mArgs->list().isEmpty() )
|
||||
{
|
||||
QgsExpression::NodeLiteral* var = dynamic_cast<QgsExpression::NodeLiteral*>( mArgs->list().first() );
|
||||
if ( var )
|
||||
return QSet<QString>() << var->value().toString();
|
||||
}
|
||||
return QSet<QString>() << QString();
|
||||
}
|
||||
else
|
||||
return QSet<QString>();
|
||||
}
|
||||
|
||||
bool QgsExpression::NodeFunction::needsGeometry() const
|
||||
{
|
||||
bool needs = Functions()[mFnIndex]->usesGeometry();
|
||||
@ -5119,6 +5169,16 @@ QString QgsExpression::NodeLiteral::dump() const
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeLiteral::referencedColumns() const
|
||||
{
|
||||
return QSet<QString>();
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeLiteral::referencedVariables() const
|
||||
{
|
||||
return QSet<QString>();
|
||||
}
|
||||
|
||||
QgsExpression::Node*QgsExpression::NodeLiteral::clone() const
|
||||
{
|
||||
return new NodeLiteral( mValue );
|
||||
@ -5177,6 +5237,16 @@ QString QgsExpression::NodeColumnRef::dump() const
|
||||
return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeColumnRef::referencedColumns() const
|
||||
{
|
||||
return QSet<QString>() << mName;
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeColumnRef::referencedVariables() const
|
||||
{
|
||||
return QSet<QString>();
|
||||
}
|
||||
|
||||
QgsExpression::Node*QgsExpression::NodeColumnRef::clone() const
|
||||
{
|
||||
return new NodeColumnRef( mName );
|
||||
@ -5253,6 +5323,20 @@ QSet<QString> QgsExpression::NodeCondition::referencedColumns() const
|
||||
return lst;
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeCondition::referencedVariables() const
|
||||
{
|
||||
QSet<QString> lst;
|
||||
Q_FOREACH ( WhenThen* cond, mConditions )
|
||||
{
|
||||
lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
|
||||
}
|
||||
|
||||
if ( mElseExp )
|
||||
lst += mElseExp->referencedVariables();
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
bool QgsExpression::NodeCondition::needsGeometry() const
|
||||
{
|
||||
Q_FOREACH ( WhenThen* cond, mConditions )
|
||||
@ -5619,6 +5703,14 @@ QSet<QString> QgsExpression::NodeInOperator::referencedColumns() const
|
||||
return lst;
|
||||
}
|
||||
|
||||
QSet<QString> QgsExpression::NodeInOperator::referencedVariables() const
|
||||
{
|
||||
QSet<QString> lst( mNode->referencedVariables() );
|
||||
Q_FOREACH ( const Node* n, mList->list() )
|
||||
lst.unite( n->referencedVariables() );
|
||||
return lst;
|
||||
}
|
||||
|
||||
bool QgsExpression::Function::operator==( const QgsExpression::Function& other ) const
|
||||
{
|
||||
if ( QString::compare( mName, other.mName, Qt::CaseInsensitive ) == 0 )
|
||||
|
@ -180,11 +180,18 @@ class CORE_EXPORT QgsExpression
|
||||
* QgsFeatureRequest::setSubsetOfAttributes automatically handles this case.
|
||||
*
|
||||
* @see referencedAttributeIndexes()
|
||||
*
|
||||
* TODO QGIS3: Return QSet<QString>
|
||||
*/
|
||||
QSet<QString> referencedColumns() const;
|
||||
|
||||
/**
|
||||
* Return a list of all variables which are used in this expression.
|
||||
* If the list contains a NULL QString, there is a variable name used
|
||||
* which is determined at runtime.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
QSet<QString> referencedVariables() const;
|
||||
|
||||
/**
|
||||
* Return a list of field name indexes obtained from the provided fields.
|
||||
*
|
||||
@ -857,6 +864,11 @@ class CORE_EXPORT QgsExpression
|
||||
*/
|
||||
virtual QSet<QString> referencedColumns() const = 0;
|
||||
|
||||
/**
|
||||
* Return a list of all variables which are used in this expression.
|
||||
*/
|
||||
virtual QSet<QString> referencedVariables() const = 0;
|
||||
|
||||
/**
|
||||
* Abstract virtual method which returns if the geometry is required to evaluate
|
||||
* this expression.
|
||||
@ -953,7 +965,8 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QVariant eval( QgsExpression* parent, const QgsExpressionContext* context ) override;
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override { return mOperand->referencedColumns(); }
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override { return mOperand->needsGeometry(); }
|
||||
virtual Node* clone() const override;
|
||||
|
||||
@ -984,6 +997,7 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override;
|
||||
virtual Node* clone() const override;
|
||||
|
||||
@ -1028,6 +1042,7 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override;
|
||||
virtual Node* clone() const override;
|
||||
|
||||
@ -1055,6 +1070,7 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override;
|
||||
virtual Node* clone() const override;
|
||||
|
||||
@ -1084,7 +1100,8 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QVariant eval( QgsExpression* parent, const QgsExpressionContext* context ) override;
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override { return QSet<QString>(); }
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override { return false; }
|
||||
virtual Node* clone() const override;
|
||||
|
||||
@ -1110,7 +1127,8 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QVariant eval( QgsExpression* parent, const QgsExpressionContext* context ) override;
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override { return QSet<QString>() << mName; }
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override { return false; }
|
||||
|
||||
virtual Node* clone() const override;
|
||||
@ -1162,6 +1180,7 @@ class CORE_EXPORT QgsExpression
|
||||
virtual QString dump() const override;
|
||||
|
||||
virtual QSet<QString> referencedColumns() const override;
|
||||
virtual QSet<QString> referencedVariables() const override;
|
||||
virtual bool needsGeometry() const override;
|
||||
virtual Node* clone() const override;
|
||||
|
||||
|
@ -313,3 +313,16 @@ QDataStream& operator>>( QDataStream& in, QgsFeature& feature )
|
||||
feature.setValid( valid );
|
||||
return in;
|
||||
}
|
||||
|
||||
uint qHash( const QgsFeature& key, uint seed )
|
||||
{
|
||||
uint hash = seed;
|
||||
Q_FOREACH ( const QVariant& attr, key.attributes() )
|
||||
{
|
||||
hash ^= qHash( attr.toString() );
|
||||
}
|
||||
|
||||
hash ^= qHash( key.geometry().exportToWkt() );
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
@ -349,6 +349,8 @@ typedef QMap<int, QString> QgsFieldNameMap;
|
||||
|
||||
typedef QList<QgsFeature> QgsFeatureList;
|
||||
|
||||
uint qHash( const QgsFeature& key, uint seed = 0 );
|
||||
|
||||
Q_DECLARE_METATYPE( QgsFeature )
|
||||
Q_DECLARE_METATYPE( QgsFeatureList )
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user