Skip to content

Commit f7b7254

Browse files
authoredApr 23, 2017
Merge pull request #4284 from arnaud-morvan/expression_compare_arrays
Add arrays comparison in QgsExpression
2 parents 268acab + 8385cd9 commit f7b7254

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed
 

‎src/core/qgsexpression.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ inline bool isNull( const QVariant &v )
176176
return v.isNull();
177177
}
178178

179+
inline bool isList( const QVariant &v )
180+
{
181+
return v.type() == QVariant::List;
182+
}
183+
179184
///////////////////////////////////////////////
180185
// evaluation error macros
181186

@@ -4257,6 +4262,16 @@ QString QgsExpression::quotedValue( const QVariant &value, QVariant::Type type )
42574262
case QVariant::Bool:
42584263
return value.toBool() ? "TRUE" : "FALSE";
42594264

4265+
case QVariant::List:
4266+
{
4267+
QStringList quotedValues;
4268+
Q_FOREACH ( const QVariant &v, value.toList() )
4269+
{
4270+
quotedValues += quotedValue( v );
4271+
}
4272+
return QStringLiteral( "array( %1 )" ).arg( quotedValues.join( ", " ) );
4273+
}
4274+
42604275
default:
42614276
case QVariant::String:
42624277
return quotedString( value.toString() );
@@ -4834,6 +4849,75 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression *parent, const Q
48344849
{
48354850
return TVL_Unknown;
48364851
}
4852+
else if ( isList( vL ) || isList( vR ) )
4853+
{
4854+
// verify that we have two lists
4855+
if ( !isList( vL ) || !isList( vR ) )
4856+
return TVL_Unknown;
4857+
4858+
// and search for not equal respective items
4859+
QVariantList lL = vL.toList();
4860+
QVariantList lR = vR.toList();
4861+
for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
4862+
{
4863+
if ( isNull( lL.at( i ) ) && isNull( lR.at( i ) ) )
4864+
continue; // same behavior as PostgreSQL
4865+
4866+
if ( isNull( lL.at( i ) ) || isNull( lR.at( i ) ) )
4867+
{
4868+
switch ( mOp )
4869+
{
4870+
case boEQ:
4871+
return false;
4872+
case boNE:
4873+
return true;
4874+
case boLT:
4875+
case boLE:
4876+
return isNull( lR.at( i ) );
4877+
case boGT:
4878+
case boGE:
4879+
return isNull( lL.at( i ) );
4880+
default:
4881+
Q_ASSERT( false );
4882+
return TVL_Unknown;
4883+
}
4884+
}
4885+
4886+
QgsExpression::NodeLiteral nL( lL.at( i ) );
4887+
QgsExpression::NodeLiteral nR( lR.at( i ) );
4888+
QgsExpression::NodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
4889+
QVariant eq = eqNode.eval( parent, context );
4890+
ENSURE_NO_EVAL_ERROR;
4891+
if ( eq == TVL_False )
4892+
{
4893+
// return the two items comparison
4894+
QgsExpression::NodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
4895+
QVariant v = node.eval( parent, context );
4896+
ENSURE_NO_EVAL_ERROR;
4897+
return v;
4898+
}
4899+
}
4900+
4901+
// default to length comparison
4902+
switch ( mOp )
4903+
{
4904+
case boEQ:
4905+
return lL.length() == lR.length();
4906+
case boNE:
4907+
return lL.length() != lR.length();
4908+
case boLT:
4909+
return lL.length() < lR.length();
4910+
case boGT:
4911+
return lL.length() > lR.length();
4912+
case boLE:
4913+
return lL.length() <= lR.length();
4914+
case boGE:
4915+
return lL.length() >= lR.length();
4916+
default:
4917+
Q_ASSERT( false );
4918+
return TVL_Unknown;
4919+
}
4920+
}
48374921
else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
48384922
( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
48394923
{

‎tests/src/core/testqgsexpression.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,48 @@ class TestQgsExpression: public QObject
24472447
QCOMPARE( badArray.evalErrorString(), QString( "Cannot convert 'not an array' to array" ) );
24482448
}
24492449

2450+
void compare_arrays()
2451+
{
2452+
QCOMPARE( QgsExpression( "array() = array()" ).evaluate(), QVariant( true ) );
2453+
QCOMPARE( QgsExpression( "array(NULL) = array(NULL)" ).evaluate(), QVariant( true ) );
2454+
QCOMPARE( QgsExpression( "array() = array(NULL)" ).evaluate(), QVariant( false ) );
2455+
QCOMPARE( QgsExpression( "array(1, NULL) = array(NULL, 1)" ).evaluate(), QVariant( false ) );
2456+
2457+
QCOMPARE( QgsExpression( "array('hello') = array('hello')" ).evaluate(), QVariant( true ) );
2458+
QCOMPARE( QgsExpression( "array('hello') = array('hello2')" ).evaluate(), QVariant( false ) );
2459+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') = array('h', 'e', 'l', 'l', 'o')" ).evaluate(), QVariant( true ) );
2460+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') = array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );
2461+
2462+
QCOMPARE( QgsExpression( "array('1') = array(1)" ).evaluate(), QVariant( true ) );
2463+
QCOMPARE( QgsExpression( "array('1.2') = array(1.2)" ).evaluate(), QVariant( true ) );
2464+
2465+
QCOMPARE( QgsExpression( "array() != array()" ).evaluate(), QVariant( false ) );
2466+
QCOMPARE( QgsExpression( "array(NULL) != array(NULL)" ).evaluate(), QVariant( false ) );
2467+
QCOMPARE( QgsExpression( "array() != array(NULL)" ).evaluate(), QVariant( true ) );
2468+
QCOMPARE( QgsExpression( "array('hello') != array('hello')" ).evaluate(), QVariant( false ) );
2469+
QCOMPARE( QgsExpression( "array('hello') != array('hello2')" ).evaluate(), QVariant( true ) );
2470+
2471+
QCOMPARE( QgsExpression( "array() < array(1)" ).evaluate(), QVariant( true ) );
2472+
QCOMPARE( QgsExpression( "array(1) < array(NULL)" ).evaluate(), QVariant( true ) );
2473+
QCOMPARE( QgsExpression( "array(1) < array(1)" ).evaluate(), QVariant( false ) );
2474+
QCOMPARE( QgsExpression( "array(1) < array(2)" ).evaluate(), QVariant( true ) );
2475+
QCOMPARE( QgsExpression( "array(2) < array(1)" ).evaluate(), QVariant( false ) );
2476+
QCOMPARE( QgsExpression( "array(1) < array(1, 2)" ).evaluate(), QVariant( true ) );
2477+
QCOMPARE( QgsExpression( "array(1, 2) < array(1)" ).evaluate(), QVariant( false ) );
2478+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') < array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );
2479+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') > array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( true ) );
2480+
2481+
QCOMPARE( QgsExpression( "array() <= array(1)" ).evaluate(), QVariant( true ) );
2482+
QCOMPARE( QgsExpression( "array(1) <= array(NULL)" ).evaluate(), QVariant( true ) );
2483+
QCOMPARE( QgsExpression( "array(1) <= array(1)" ).evaluate(), QVariant( true ) );
2484+
QCOMPARE( QgsExpression( "array(1) <= array(2)" ).evaluate(), QVariant( true ) );
2485+
QCOMPARE( QgsExpression( "array(2) <= array(1)" ).evaluate(), QVariant( false ) );
2486+
QCOMPARE( QgsExpression( "array(1) <= array(1, 2)" ).evaluate(), QVariant( true ) );
2487+
QCOMPARE( QgsExpression( "array(1, 2) <= array(1)" ).evaluate(), QVariant( false ) );
2488+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') <= array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );
2489+
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') >= array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( true ) );
2490+
}
2491+
24502492
void eval_map()
24512493
{
24522494
QgsFeature f( 100 );
@@ -2543,6 +2585,8 @@ class TestQgsExpression: public QObject
25432585
QCOMPARE( QgsExpression::quotedValue( QVariant( true ), QVariant::String ), QString( "'true'" ) );
25442586
QCOMPARE( QgsExpression::quotedValue( QVariant() ), QString( "NULL" ) );
25452587
QCOMPARE( QgsExpression::quotedValue( QVariant(), QVariant::String ), QString( "NULL" ) );
2588+
QVariantList array = QVariantList() << QVariant( 1 ) << QVariant( "a" ) << QVariant();
2589+
QCOMPARE( QgsExpression::quotedValue( array ), QString( "array( 1, 'a', NULL )" ) );
25462590
}
25472591

25482592
void reentrant()

0 commit comments

Comments
 (0)