Skip to content

Commit 6ed078c

Browse files
authored
Merge pull request #5946 from DelazJ/nullMinMax
[needs-docs] Update min and max functions
2 parents d047bc8 + cdbb0df commit 6ed078c

4 files changed

Lines changed: 46 additions & 24 deletions

File tree

resources/function_help/json/max

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
{"arg":"value1", "syntaxOnly": true},
88
{"arg":"value2", "syntaxOnly": true},
99
{"arg":"value", "descOnly": true, "description":"a number"}],
10-
"examples": [ { "expression":"max(2,10.2,5.5)", "returns":"10.2"}
11-
]
10+
"examples": [
11+
{ "expression":"max(2,10.2,5.5)", "returns":"10.2"},
12+
{ "expression":"max(20.5,NULL,6.2)", "returns":"20.5"}]
1213
}

resources/function_help/json/min

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
"arguments": [ {"arg":"value1", "syntaxOnly": true},
77
{"arg":"value2", "syntaxOnly": true},
88
{"arg":"value", "descOnly": true, "description":"a number"}],
9-
"examples": [ { "expression":"min(20.5,10,6.2)", "returns":"6.2"}
10-
]
9+
"examples": [ { "expression":"min(20.5,10,6.2)", "returns":"6.2"},
10+
{ "expression":"min(2,-10.3,NULL)", "returns":"-10.3"}]
1111
}

src/core/expression/qgsexpressionfunction.cpp

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -415,38 +415,50 @@ static QVariant fcnExpScale( const QVariantList &values, const QgsExpressionCont
415415

416416
static QVariant fcnMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
417417
{
418-
//initially set max as first value
419-
double maxVal = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
420-
421-
//check against all other values
422-
for ( int i = 1; i < values.length(); ++i )
418+
QVariant result( QVariant::Double );
419+
double maxVal = std::numeric_limits<double>::quiet_NaN();
420+
for ( const QVariant &val : values )
423421
{
424-
double testVal = QgsExpressionUtils::getDoubleValue( values[i], parent );
425-
if ( testVal > maxVal )
422+
double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
423+
if ( std::isnan( maxVal ) )
426424
{
427425
maxVal = testVal;
428426
}
427+
else if ( !std::isnan( testVal ) )
428+
{
429+
maxVal = std::max( maxVal, testVal );
430+
}
429431
}
430432

431-
return QVariant( maxVal );
433+
if ( !std::isnan( maxVal ) )
434+
{
435+
result = QVariant( maxVal );
436+
}
437+
return result;
432438
}
433439

434440
static QVariant fcnMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
435441
{
436-
//initially set min as first value
437-
double minVal = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
438-
439-
//check against all other values
440-
for ( int i = 1; i < values.length(); ++i )
442+
QVariant result( QVariant::Double );
443+
double minVal = std::numeric_limits<double>::quiet_NaN();
444+
for ( const QVariant &val : values )
441445
{
442-
double testVal = QgsExpressionUtils::getDoubleValue( values[i], parent );
443-
if ( testVal < minVal )
446+
double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
447+
if ( std::isnan( minVal ) )
444448
{
445449
minVal = testVal;
446450
}
451+
else if ( !std::isnan( testVal ) )
452+
{
453+
minVal = std::min( minVal, testVal );
454+
}
447455
}
448456

449-
return QVariant( minVal );
457+
if ( !std::isnan( minVal ) )
458+
{
459+
result = QVariant( minVal );
460+
}
461+
return result;
450462
}
451463

452464
static QVariant fcnAggregate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
@@ -3937,8 +3949,8 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
39373949
sFunctions << randfFunc;
39383950

39393951
sFunctions
3940-
<< new QgsStaticExpressionFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ) )
3941-
<< new QgsStaticExpressionFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ) )
3952+
<< new QgsStaticExpressionFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
3953+
<< new QgsStaticExpressionFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
39423954
<< new QgsStaticExpressionFunction( QStringLiteral( "clamp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ) ), fcnClamp, QStringLiteral( "Math" ) )
39433955
<< new QgsStaticExpressionFunction( QStringLiteral( "scale_linear" ), 5, fcnLinearScale, QStringLiteral( "Math" ) )
39443956
<< new QgsStaticExpressionFunction( QStringLiteral( "scale_exp" ), 6, fcnExpScale, QStringLiteral( "Math" ) )

tests/src/core/testqgsexpression.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,12 +623,21 @@ class TestQgsExpression: public QObject
623623
QTest::newRow( "round(1234.557,2) - round up" ) << "round(1234.557,2)" << false << QVariant( 1234.56 );
624624
QTest::newRow( "round(1234.554,2) - round down" ) << "round(1234.554,2)" << false << QVariant( 1234.55 );
625625
QTest::newRow( "round(1234.6) - round up to int" ) << "round(1234.6)" << false << QVariant( 1235 );
626-
QTest::newRow( "round(1234.6) - round down to int" ) << "round(1234.4)" << false << QVariant( 1234 );
626+
QTest::newRow( "round(1234.4) - round down to int" ) << "round(1234.4)" << false << QVariant( 1234 );
627627
QTest::newRow( "max(1)" ) << "max(1)" << false << QVariant( 1. );
628628
QTest::newRow( "max(1,3.5,-2.1)" ) << "max(1,3.5,-2.1)" << false << QVariant( 3.5 );
629+
QTest::newRow( "max(3.5,-2.1,1)" ) << "max(3.5,-2.1,1)" << false << QVariant( 3.5 );
630+
QTest::newRow( "max with null value" ) << "max(1,3.5,null)" << false << QVariant( 3.5 );
631+
QTest::newRow( "max with null value first" ) << "max(null,-3.5,2)" << false << QVariant( 2. );
632+
QTest::newRow( "max with no params" ) << "max()" << false << QVariant( QVariant::Double );
633+
QTest::newRow( "max with only null value" ) << "max(null)" << false << QVariant( QVariant::Double );
629634
QTest::newRow( "min(-1.5)" ) << "min(-1.5)" << false << QVariant( -1.5 );
630635
QTest::newRow( "min(-16.6,3.5,-2.1)" ) << "min(-16.6,3.5,-2.1)" << false << QVariant( -16.6 );
631636
QTest::newRow( "min(5,3.5,-2.1)" ) << "min(5,3.5,-2.1)" << false << QVariant( -2.1 );
637+
QTest::newRow( "min with null value" ) << "min(5,null,-2.1)" << false << QVariant( -2.1 );
638+
QTest::newRow( "min with null value first" ) << "min(null,3.2,6.5)" << false << QVariant( 3.2 );
639+
QTest::newRow( "min with no params" ) << "min()" << false << QVariant( QVariant::Double );
640+
QTest::newRow( "min with only null value" ) << "min(null)" << false << QVariant( QVariant::Double );
632641
QTest::newRow( "clamp(-2,1,5)" ) << "clamp(-2,1,5)" << false << QVariant( 1.0 );
633642
QTest::newRow( "clamp(min:=-2,value:=1,max:=5)" ) << "clamp(min:=-2,value:=1,max:=5)" << false << QVariant( 1.0 );
634643
QTest::newRow( "clamp(-2,-10,5)" ) << "clamp(-2,-10,5)" << false << QVariant( -2.0 );
@@ -1226,7 +1235,7 @@ class TestQgsExpression: public QObject
12261235
qDebug() << exp.evalErrorString();
12271236
if ( result.type() != expected.type() )
12281237
{
1229-
qDebug() << "got " << result.typeName() << " instead of " << expected.typeName();
1238+
qDebug() << "got type " << result.typeName() << "(" << result.type() << ") instead of " << expected.typeName() << "(" << expected.type() << ")";
12301239
}
12311240
//qDebug() << res.type() << " " << result.type();
12321241
//qDebug() << "type " << res.typeName();

0 commit comments

Comments
 (0)