From 7599d4f8d58b97b01f6f38e5c45c722f9b3d1f6f Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Wed, 20 Feb 2019 06:27:43 +0700 Subject: [PATCH] [expression] Add try() function to provide a way to detect and handle expressions which can intermittently fail. --- resources/function_help/json/try | 14 ++++++++++++++ src/core/expression/qgsexpressionfunction.cpp | 16 ++++++++++++++++ tests/src/core/testqgsexpression.cpp | 3 +++ 3 files changed, 33 insertions(+) create mode 100644 resources/function_help/json/try diff --git a/resources/function_help/json/try b/resources/function_help/json/try new file mode 100644 index 00000000000..fc97a8b5552 --- /dev/null +++ b/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"} + ] +} diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index 95136dac3d3..e47d6c0dc65 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -3688,6 +3688,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 ); @@ -4763,6 +4778,7 @@ const QList &QgsExpression::Functions() << new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet(), false, QStringList(), true ) << new QgsStaticExpressionFunction( QStringLiteral( "nullif" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value2" ) ), fcnNullIf, QStringLiteral( "Conditionals" ) ) << new QgsStaticExpressionFunction( QStringLiteral( "if" ), 3, fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet(), true ) + << new QgsStaticExpressionFunction( QStringLiteral( "try" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "alternative" ), true, QVariant() ), fcnTry, QStringLiteral( "Conditionals" ), QString(), false, QSet(), true ) << new QgsStaticExpressionFunction( QStringLiteral( "aggregate" ), QgsExpressionFunction::ParameterList() diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index 006bb0d6bf1..b2620ef25f1 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -1177,6 +1177,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 ) );