Skip to content

Commit d61bf1f

Browse files
committedDec 13, 2014
Add lazy evaluation support to expression functions
Add if(cond, true, false) function using lazy evaluation feature
1 parent fd15a16 commit d61bf1f

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed
 

‎src/core/qgsexpression.cpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,15 @@ static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
338338
return 0;
339339
}
340340

341+
static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
342+
{
343+
if ( value.canConvert<QgsExpression::Node*>() )
344+
return value.value<QgsExpression::Node*>();
345+
346+
parent->setEvalErrorString( "Cannot convert to Node" );
347+
return 0;
348+
}
349+
341350
// this handles also NULL values
342351
static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
343352
{
@@ -1355,6 +1364,27 @@ static QVariant fcnColorRgb( const QVariantList &values, const QgsFeature *, Qgs
13551364
return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
13561365
}
13571366

1367+
static QVariant fcnIf( const QVariantList &values, const QgsFeature *f, QgsExpression *parent )
1368+
{
1369+
QgsExpression::Node* node = getNode( values.at( 0 ), parent );
1370+
ENSURE_NO_EVAL_ERROR;
1371+
QVariant value = node->eval( parent, f );
1372+
ENSURE_NO_EVAL_ERROR;
1373+
if ( value.toBool() ) {
1374+
node = getNode( values.at( 1 ), parent );
1375+
ENSURE_NO_EVAL_ERROR;
1376+
value = node->eval( parent, f );
1377+
ENSURE_NO_EVAL_ERROR;
1378+
}
1379+
else {
1380+
node = getNode( values.at( 2 ), parent );
1381+
ENSURE_NO_EVAL_ERROR;
1382+
value = node->eval( parent, f );
1383+
ENSURE_NO_EVAL_ERROR;
1384+
}
1385+
return value;
1386+
}
1387+
13581388
static QVariant fncColorRgba( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
13591389
{
13601390
int red = getIntValue( values.at( 0 ), parent );
@@ -1660,6 +1690,7 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
16601690
<< new StaticFunction( "totime", 1, fcnToTime, "Conversions" )
16611691
<< new StaticFunction( "tointerval", 1, fcnToInterval, "Conversions" )
16621692
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals" )
1693+
<< new StaticFunction( "if", 3, fcnIf, "Conditionals", "", False, QStringList(), true )
16631694
<< new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
16641695
<< new StaticFunction( "$now", 0, fcnNow, "Date and Time" )
16651696
<< new StaticFunction( "age", 2, fcnAge, "Date and Time" )
@@ -2533,10 +2564,17 @@ QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, const QgsFeat
25332564
{
25342565
foreach ( Node* n, mArgs->list() )
25352566
{
2536-
QVariant v = n->eval( parent, f );
2537-
ENSURE_NO_EVAL_ERROR;
2538-
if ( isNull( v ) && fd->name() != "coalesce" )
2539-
return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
2567+
QVariant v;
2568+
if ( fd->lazyEval() ) {
2569+
// Pass in the node for the function to eval as it needs.
2570+
v = QVariant::fromValue( n );
2571+
}
2572+
else {
2573+
v = n->eval( parent, f );
2574+
ENSURE_NO_EVAL_ERROR;
2575+
if ( isNull( v ) && fd->name() != "coalesce" )
2576+
return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
2577+
}
25402578
argValues.append( v );
25412579
}
25422580
}

‎src/core/qgsexpression.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,15 +282,20 @@ class CORE_EXPORT QgsExpression
282282
class CORE_EXPORT Function
283283
{
284284
public:
285-
Function( QString fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList() )
286-
: mName( fnname ), mParams( params ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ), mReferencedColumns( referencedColumns ) {}
285+
Function( QString fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
286+
: mName( fnname ), mParams( params ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ), mReferencedColumns( referencedColumns ), mLazyEval( lazyEval ) {}
287287
/** The name of the function. */
288288
QString name() { return mName; }
289289
/** The number of parameters this function takes. */
290290
int params() { return mParams; }
291291
/** Does this function use a geometry object. */
292292
bool usesgeometry() { return mUsesGeometry; }
293293

294+
/** True if this function should use lazy evaluation. Lazy evaluation functions take QgsExpression::Node objects
295+
* rather than the node results when called. You can use node->eval(parent, feature) to evaluate the node and return the result
296+
* Functions are non lazy default and will be given the node return value when called **/
297+
bool lazyEval() { return mLazyEval; }
298+
294299
virtual QStringList referencedColumns() const { return mReferencedColumns; }
295300

296301
/** The group the function belongs to. */
@@ -315,13 +320,14 @@ class CORE_EXPORT QgsExpression
315320
QString mGroup;
316321
QString mHelpText;
317322
QStringList mReferencedColumns;
323+
bool mLazyEval;
318324
};
319325

320326
class StaticFunction : public Function
321327
{
322328
public:
323-
StaticFunction( QString fnname, int params, FcnEval fcn, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList() )
324-
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns ), mFnc( fcn ) {}
329+
StaticFunction( QString fnname, int params, FcnEval fcn, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
330+
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns, lazyEval ), mFnc( fcn ) {}
325331

326332
virtual QVariant func( const QVariantList& values, const QgsFeature* f, QgsExpression* parent )
327333
{
@@ -680,5 +686,6 @@ class CORE_EXPORT QgsExpression
680686
};
681687

682688
Q_DECLARE_METATYPE( QgsExpression::Interval );
689+
Q_DECLARE_METATYPE( QgsExpression::Node* );
683690

684691
#endif // QGSEXPRESSION_H

‎tests/src/core/testqgsexpression.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ class TestQgsExpression: public QObject
377377
QTest::newRow( "regexp match invalid" ) << "regexp_match('abc DEF','[[[')" << true << QVariant();
378378
QTest::newRow( "regexp match escaped" ) << "regexp_match('abc DEF','\\\\s[A-Z]+')" << false << QVariant( 1 );
379379
QTest::newRow( "regexp match false" ) << "regexp_match('abc DEF','\\\\s[a-z]+')" << false << QVariant( 0 );
380+
QTest::newRow( "if true" ) << "if(1=1, 1, 0)" << false << QVariant( 1 );
381+
QTest::newRow( "if false" ) << "if(1=2, 1, 0)" << false << QVariant( 0 );
380382

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

0 commit comments

Comments
 (0)
Please sign in to comment.