Skip to content

Commit

Permalink
[FEATURE][expressions] Simplified variant of "attribute" function
Browse files Browse the repository at this point in the history
This adds a second variant for the existing "attribute" function.
The current function requires both a target feature and attribute
name to be specified, while the NEW variant just uses the current
feature.

E.g.

NEW:

attribute( 'name' ) -> returns the value stored in 'name' attribute
for the current feature

EXISTING:

attribute( @atlas_feature, 'name' ) -> returns value stored in 'name'
attribute for the current atlas feature

It's just a faster shorthand version!
  • Loading branch information
nyalldawson committed Feb 22, 2019
1 parent 3433c9c commit db1a192
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 9 deletions.
16 changes: 12 additions & 4 deletions resources/function_help/json/attribute
@@ -1,8 +1,16 @@
{
"name": "attribute",
"type": "function",
"description": "Returns the value of a specified attribute from a feature.",
"arguments": [ {"arg":"feature","description":"a feature"},
{"arg":"attribute_name","description":"name of attribute to be returned"}],
"examples": [ { "expression":"attribute( $currentfeature, 'name' )", "returns":"value stored in 'name' attribute for the current feature"}]
"description": "Returns an attribute from a feature.",
"variants": [
{ "variant": "Variant 1",
"variant_description": "Returns the value of an attribute from the current feature.",
"arguments": [ {"arg":"attribute_name","description":"name of attribute to be returned"}],
"examples": [ { "expression":"attribute( 'name' )", "returns":"value stored in 'name' attribute for the current feature"}] },
{ "variant": "Variant 2",
"variant_description": "Allows the target feature and attribute name to be specified.",
"arguments": [ {"arg":"feature","description":"a feature"},
{"arg":"attribute_name","description":"name of attribute to be returned"}],
"examples": [ { "expression":"attribute( @atlas_feature, 'name' )", "returns":"value stored in 'name' attribute for the current atlas feature"}] }
]
}
45 changes: 40 additions & 5 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -1332,12 +1332,27 @@ static QVariant fcnFeature( const QVariantList &, const QgsExpressionContext *co

return context->feature();
}
static QVariant fcnAttribute( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
static QVariant fcnAttribute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsFeature feat = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
QString attr = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
QgsFeature feature;
QString attr;
if ( values.size() == 1 )
{
attr = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
feature = context->feature();
}
else if ( values.size() == 2 )
{
feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
attr = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
}
else
{
parent->setEvalErrorString( QObject::tr( "Function `attribute` requires one or two parameters. %1 given." ).arg( values.length() ) );
return QVariant();
}

return feat.attribute( attr );
return feature.attribute( attr );
}

static QVariant fcnIsSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
Expand Down Expand Up @@ -5319,10 +5334,30 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()

sFunctions << evalFunc;

QgsStaticExpressionFunction *attributeFunc = new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), -1, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
attributeFunc->setIsStaticFunction(
[]( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
{
const QList< QgsExpressionNode *> argList = node->args()->list();
for ( QgsExpressionNode *argNode : argList )
{
if ( !argNode->isStatic( parent, context ) )
return false;
}

if ( node->args()->count() == 1 )
{
// not static -- this is the variant which uses the current feature taken direct from the expression context
return false;
}

return true;
} );
sFunctions << attributeFunc;

sFunctions
<< new QgsStaticExpressionFunction( QStringLiteral( "env" ), 1, fcnEnvVar, QStringLiteral( "General" ), QString() )
<< new QgsWithVariableExpressionFunction()
<< new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), 2, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES )
<< new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )

// functions for arrays
Expand Down
14 changes: 14 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -1548,6 +1548,20 @@ class TestQgsExpression: public QObject
QgsExpression exp2( QStringLiteral( "attribute($currentfeature,'second'||'_column')" ) );
v = exp2.evaluate( &context );
QCOMPARE( v.toInt(), 5 );

QgsExpression exp3( QStringLiteral( "attribute()" ) );
v = exp3.evaluate( &context );
QVERIFY( v.isNull() );
QVERIFY( exp3.hasEvalError() );

QgsExpression exp4( QStringLiteral( "attribute('a','b','c')" ) );
v = exp4.evaluate( &context );
QVERIFY( v.isNull() );
QVERIFY( exp4.hasEvalError() );

QgsExpression exp5( QStringLiteral( "attribute('col1')" ) );
v = exp5.evaluate( &context );
QCOMPARE( v.toString(), QString( "test value" ) );
}

void eval_get_feature_data()
Expand Down

0 comments on commit db1a192

Please sign in to comment.