Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Expression variables are more often than not static
  • Loading branch information
m-kuhn committed May 1, 2017
1 parent 1711a41 commit 8031ac4
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 7 deletions.
5 changes: 5 additions & 0 deletions python/core/qgsexpression.sip
Expand Up @@ -574,6 +574,11 @@ Does this function use a geometry object.
:rtype: bool
%End

virtual bool isStatic( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const;
%Docstring
:rtype: bool
%End

virtual QSet<QString> referencedColumns( const QgsExpression::NodeFunction *node ) const;
%Docstring
Returns a set of field names which are required for this function.
Expand Down
60 changes: 53 additions & 7 deletions src/core/qgsexpression.cpp
Expand Up @@ -4212,9 +4212,29 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
<< new StaticFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
<< new StaticFunction( QStringLiteral( "raster_statistic" ), ParameterList() << Parameter( QStringLiteral( "layer" ) )
<< Parameter( QStringLiteral( "band" ) )
<< Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "General" ) )
<< new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
<< Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "General" ) );

// **var** function
StaticFunction *varFunction = new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) );
varFunction->setIsStaticFunction(
[]( const NodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
{
if ( node->args()->count() > 0 )
{
Node *argNode = node->args()->at( 0 );

if ( !argNode->isStatic( parent, context ) )
return false;

if ( fcnGetVariable( QVariantList() << argNode->eval( parent, context ), context, parent ).isValid() )
return true;
}
return false;
}
);

sFunctions
<< varFunction
//return all attributes string for referencedColumns - this is caught by
// QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
// feature request
Expand Down Expand Up @@ -5590,10 +5610,7 @@ QgsExpression::Node *QgsExpression::NodeFunction::clone() const

bool QgsExpression::NodeFunction::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
{
Q_UNUSED( parent )
Q_UNUSED( context )
// TODO some functions are static!
return false;
return Functions()[mFnIndex]->isStatic( this, parent, context );
}

bool QgsExpression::NodeFunction::validateParams( int fnIndex, QgsExpression::NodeList *args, QString &error )
Expand Down Expand Up @@ -6299,6 +6316,14 @@ bool QgsExpression::Function::usesGeometry( const QgsExpression::NodeFunction *n
return true;
}

bool QgsExpression::Function::isStatic( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
{
Q_UNUSED( parent )
Q_UNUSED( context )
Q_UNUSED( node )
return false;
}

QSet<QString> QgsExpression::Function::referencedColumns( const NodeFunction *node ) const
{
Q_UNUSED( node )
Expand All @@ -6310,7 +6335,15 @@ bool QgsExpression::Function::operator==( const QgsExpression::Function &other )
return ( QString::compare( mName, other.mName, Qt::CaseInsensitive ) == 0 );
}

QgsExpression::StaticFunction::StaticFunction( const QString &fnname, const QgsExpression::ParameterList &params, QgsExpression::FcnEval fcn, const QString &group, const QString &helpText, std::function < bool ( const QgsExpression::NodeFunction *node ) > usesGeometry, std::function < QSet<QString>( const QgsExpression::NodeFunction *node ) > referencedColumns, bool lazyEval, const QStringList &aliases, bool handlesNull )
QgsExpression::StaticFunction::StaticFunction( const QString &fnname, const QgsExpression::ParameterList &params,
QgsExpression::FcnEval fcn,
const QString &group,
const QString &helpText,
std::function < bool ( const QgsExpression::NodeFunction *node ) > usesGeometry,
std::function < QSet<QString>( const QgsExpression::NodeFunction *node ) > referencedColumns,
bool lazyEval,
const QStringList &aliases,
bool handlesNull )
: Function( fnname, params, group, helpText, lazyEval, handlesNull )
, mFnc( fcn )
, mAliases( aliases )
Expand All @@ -6336,6 +6369,19 @@ QSet<QString> QgsExpression::StaticFunction::referencedColumns( const NodeFuncti
return mReferencedColumns;
}

bool QgsExpression::StaticFunction::isStatic( const NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
{
if ( mIsStaticFunc )
return mIsStaticFunc( node, parent, context );
else
return false;
}

void QgsExpression::StaticFunction::setIsStaticFunction( std::function<bool ( const NodeFunction *, QgsExpression *, const QgsExpressionContext * )> isStatic )
{
mIsStaticFunc = isStatic;
}

QVariant QgsExpression::Node::eval( QgsExpression *parent, const QgsExpressionContext *context )
{
if ( mHasCachedValue )
Expand Down
31 changes: 31 additions & 0 deletions src/core/qgsexpression.h
Expand Up @@ -578,6 +578,8 @@ class CORE_EXPORT QgsExpression
* Functions are non lazy default and will be given the node return value when called **/
bool lazyEval() const { return mLazyEval; }

virtual bool isStatic( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const;

/**
* Returns a set of field names which are required for this function.
* May contain QgsFeatureRequest::AllAttributes to signal that all
Expand Down Expand Up @@ -705,6 +707,30 @@ class CORE_EXPORT QgsExpression
const QStringList &aliases = QStringList(),
bool handlesNull = false );


/**
* Static function for evaluation against a QgsExpressionContext, using a named list of parameter values.
*
* Lambda functions can be provided that will be called to determine if a geometry is used an which
* columns are referenced.
* This is only required if this cannot be determined by calling each parameter node's usesGeometry() or
* referencedColumns() method. For example, an aggregate expression requires the geometry and all columns
* if the parent variable is used.
* If a nullptr is passed as a node to these functions, they should stay on the safe side and return if they
* could potentially require a geometry or columns.
*/
StaticFunction( const QString &fnname,
const QgsExpression::ParameterList &params,
FcnEval fcn,
const QString &group,
const QString &helpText,
std::function < bool ( const QgsExpression::NodeFunction *node ) > usesGeometry,
std::function < QSet<QString>( const QgsExpression::NodeFunction *node ) > referencedColumns,
std::function < bool( const NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) > isStatic,
bool lazyEval = false,
const QStringList &aliases = QStringList(),
bool handlesNull = false );

/** Static function for evaluation against a QgsExpressionContext, using a named list of parameter values and list
* of groups.
*/
Expand Down Expand Up @@ -742,12 +768,17 @@ class CORE_EXPORT QgsExpression

virtual QSet<QString> referencedColumns( const QgsExpression::NodeFunction *node ) const override;

virtual bool isStatic( const NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const override;

void setIsStaticFunction( std::function < bool( const NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) > isStatic );

private:
FcnEval mFnc;
QStringList mAliases;
bool mUsesGeometry;
std::function < bool( const QgsExpression::NodeFunction *node ) > mUsesGeometryFunc;
std::function < QSet<QString>( const QgsExpression::NodeFunction *node ) > mReferencedColumnsFunc;
std::function < bool( const NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) > mIsStaticFunc;
QSet<QString> mReferencedColumns;
};
#endif
Expand Down

0 comments on commit 8031ac4

Please sign in to comment.