Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[expression] Add try() function to provide a way to detect and handle
expressions which can intermittently fail.
  • Loading branch information
nirvn committed Feb 20, 2019
1 parent 8f46862 commit 506aaa0
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 0 deletions.
14 changes: 14 additions & 0 deletions resources/function_help/json/try
@@ -0,0 +1,14 @@
{
"name": "try",
"type": "function",
"description": "Tries an expression and returns its value if error-free. If the expression returns an error, an alternative value will be returned when provided otherwise the function will return null.",
"arguments": [
{"arg":"expression","description":"the expression which should be run"},
{"arg":"alternative","optional":true,"description":"the result which will be returned if the expression returns an error."}
],
"examples": [
{ "expression":"try( to_int( '1' ), 0 )", "returns":"1"},
{ "expression":"try( to_int( 'a' ), 0 )", "returns":"0"},
{ "expression":"try( to_date( 'invalid_date' ) )", "returns":"NULL"}
]
}
16 changes: 16 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -3445,6 +3445,21 @@ static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionCont
return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
}

static QVariant fcnTry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
QVariant value = node->eval( parent, context );
if ( parent->hasEvalError() )
{
parent->setEvalErrorString( QString() );
node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
ENSURE_NO_EVAL_ERROR;
value = node->eval( parent, context );
ENSURE_NO_EVAL_ERROR;
}
return value;
}

static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
Expand Down Expand Up @@ -4462,6 +4477,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "to_dms" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinuteSecond, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todms" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
<< new QgsStaticExpressionFunction( QStringLiteral( "if" ), 3, fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
<< new QgsStaticExpressionFunction( QStringLiteral( "try" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "alternative" ), true, QVariant() ), fcnTry, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )

<< new QgsStaticExpressionFunction( QStringLiteral( "aggregate" ),
QgsExpressionFunction::ParameterList()
Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -1129,6 +1129,9 @@ class TestQgsExpression: public QObject
QTest::newRow( "regexp match false" ) << "regexp_match('abc DEF','\\\\s[a-z]+')" << false << QVariant( 0 );
QTest::newRow( "if true" ) << "if(1=1, 1, 0)" << false << QVariant( 1 );
QTest::newRow( "if false" ) << "if(1=2, 1, 0)" << false << QVariant( 0 );
QTest::newRow( "try valid" ) << "try(to_int('1'),0)" << false << QVariant( 1 );
QTest::newRow( "try invalid with alternative" ) << "try(to_int('a'),0)" << false << QVariant( 0 );
QTest::newRow( "try invalid without alternative" ) << "try(to_int('a'))" << false << QVariant();

// Datetime functions
QTest::newRow( "to date" ) << "todate('2012-06-28')" << false << QVariant( QDate( 2012, 6, 28 ) );
Expand Down

0 comments on commit 506aaa0

Please sign in to comment.