Skip to content

Commit

Permalink
Merge pull request #7698 from m-kuhn/wfsDateTimeNow
Browse files Browse the repository at this point in the history
Support for now() in WFS filters
  • Loading branch information
m-kuhn committed Aug 26, 2018
2 parents 504cd61 + 7a91b80 commit 3cd6899
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 35 deletions.
2 changes: 1 addition & 1 deletion resources/function_help/json/now
@@ -1,6 +1,6 @@
{
"name": "now",
"type": "function",
"description": "Returns the current date and time.",
"description": "Returns the current date and time. The function is static and will return consistent results while evaluating. The time returned is the time when the expression is prepared.",
"examples": [ { "expression":"now()", "returns":"2012-07-22T13:24:57"}]
}
78 changes: 51 additions & 27 deletions src/core/qgsogcutils.cpp
Expand Up @@ -2145,7 +2145,7 @@ QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &exp, QD
QStringLiteral( "geometry" ), QString(), false, false, errorMessage );
}

QDomElement QgsOgcUtils::expressionToOgcFilter( const QgsExpression &exp,
QDomElement QgsOgcUtils::expressionToOgcFilter( const QgsExpression &expression,
QDomDocument &doc,
GMLVersion gmlVersion,
FilterVersion filterVersion,
Expand All @@ -2155,11 +2155,15 @@ QDomElement QgsOgcUtils::expressionToOgcFilter( const QgsExpression &exp,
bool invertAxisOrientation,
QString *errorMessage )
{
if ( !exp.rootNode() )
if ( !expression.rootNode() )
return QDomElement();

QgsExpression exp = expression;

QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope();
QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, geometryName, srsName, honourAxisOrientation, invertAxisOrientation );
QDomElement exprRootElem = utils.expressionNodeToOgcFilter( exp.rootNode() );
QDomElement exprRootElem = utils.expressionNodeToOgcFilter( exp.rootNode(), &exp, &context );
if ( errorMessage )
*errorMessage = utils.errorMessage();
if ( exprRootElem.isNull() )
Expand All @@ -2182,7 +2186,7 @@ QDomElement QgsOgcUtils::expressionToOgcFilter( const QgsExpression &exp,
return filterElem;
}

QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &exp,
QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &expression,
QDomDocument &doc,
GMLVersion gmlVersion,
FilterVersion filterVersion,
Expand All @@ -2192,6 +2196,11 @@ QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &exp,
bool invertAxisOrientation,
QString *errorMessage )
{
QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope();

QgsExpression exp = expression;

const QgsExpressionNode *node = exp.rootNode();
if ( !node )
return QDomElement();
Expand All @@ -2203,7 +2212,7 @@ QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &exp,
case QgsExpressionNode::ntColumnRef:
{
QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, geometryName, srsName, honourAxisOrientation, invertAxisOrientation );
QDomElement exprRootElem = utils.expressionNodeToOgcFilter( node );
QDomElement exprRootElem = utils.expressionNodeToOgcFilter( node, &exp, &context );

if ( errorMessage )
*errorMessage = utils.errorMessage();
Expand Down Expand Up @@ -2266,34 +2275,32 @@ QDomElement QgsOgcUtils::SQLStatementToOgcFilter( const QgsSQLStatement &stateme
//


QDomElement QgsOgcUtilsExprToFilter::expressionNodeToOgcFilter( const QgsExpressionNode *node )
QDomElement QgsOgcUtilsExprToFilter::expressionNodeToOgcFilter( const QgsExpressionNode *node, QgsExpression *expression, const QgsExpressionContext *context )
{
switch ( node->nodeType() )
{
case QgsExpressionNode::ntUnaryOperator:
return expressionUnaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeUnaryOperator *>( node ) );
return expressionUnaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeUnaryOperator *>( node ), expression, context );
case QgsExpressionNode::ntBinaryOperator:
return expressionBinaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeBinaryOperator *>( node ) );
return expressionBinaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeBinaryOperator *>( node ), expression, context );
case QgsExpressionNode::ntInOperator:
return expressionInOperatorToOgcFilter( static_cast<const QgsExpressionNodeInOperator *>( node ) );
return expressionInOperatorToOgcFilter( static_cast<const QgsExpressionNodeInOperator *>( node ), expression, context );
case QgsExpressionNode::ntFunction:
return expressionFunctionToOgcFilter( static_cast<const QgsExpressionNodeFunction *>( node ) );
return expressionFunctionToOgcFilter( static_cast<const QgsExpressionNodeFunction *>( node ), expression, context );
case QgsExpressionNode::ntLiteral:
return expressionLiteralToOgcFilter( static_cast<const QgsExpressionNodeLiteral *>( node ) );
return expressionLiteralToOgcFilter( static_cast<const QgsExpressionNodeLiteral *>( node ), expression, context );
case QgsExpressionNode::ntColumnRef:
return expressionColumnRefToOgcFilter( static_cast<const QgsExpressionNodeColumnRef *>( node ) );
return expressionColumnRefToOgcFilter( static_cast<const QgsExpressionNodeColumnRef *>( node ), expression, context );

default:
mErrorMessage = QObject::tr( "Node type not supported: %1" ).arg( node->nodeType() );
return QDomElement();
}
}


QDomElement QgsOgcUtilsExprToFilter::expressionUnaryOperatorToOgcFilter( const QgsExpressionNodeUnaryOperator *node )
QDomElement QgsOgcUtilsExprToFilter::expressionUnaryOperatorToOgcFilter( const QgsExpressionNodeUnaryOperator *node, QgsExpression *expression, const QgsExpressionContext *context )
{

QDomElement operandElem = expressionNodeToOgcFilter( node->operand() );
QDomElement operandElem = expressionNodeToOgcFilter( node->operand(), expression, context );
if ( !mErrorMessage.isEmpty() )
return QDomElement();

Expand Down Expand Up @@ -2329,9 +2336,9 @@ QDomElement QgsOgcUtilsExprToFilter::expressionUnaryOperatorToOgcFilter( const Q
}


QDomElement QgsOgcUtilsExprToFilter::expressionBinaryOperatorToOgcFilter( const QgsExpressionNodeBinaryOperator *node )
QDomElement QgsOgcUtilsExprToFilter::expressionBinaryOperatorToOgcFilter( const QgsExpressionNodeBinaryOperator *node, QgsExpression *expression, const QgsExpressionContext *context )
{
QDomElement leftElem = expressionNodeToOgcFilter( node->opLeft() );
QDomElement leftElem = expressionNodeToOgcFilter( node->opLeft(), expression, context );
if ( !mErrorMessage.isEmpty() )
return QDomElement();

Expand Down Expand Up @@ -2365,7 +2372,7 @@ QDomElement QgsOgcUtilsExprToFilter::expressionBinaryOperatorToOgcFilter( const

}

QDomElement rightElem = expressionNodeToOgcFilter( node->opRight() );
QDomElement rightElem = expressionNodeToOgcFilter( node->opRight(), expression, context );
if ( !mErrorMessage.isEmpty() )
return QDomElement();

Expand Down Expand Up @@ -2401,8 +2408,10 @@ QDomElement QgsOgcUtilsExprToFilter::expressionBinaryOperatorToOgcFilter( const
}


QDomElement QgsOgcUtilsExprToFilter::expressionLiteralToOgcFilter( const QgsExpressionNodeLiteral *node )
QDomElement QgsOgcUtilsExprToFilter::expressionLiteralToOgcFilter( const QgsExpressionNodeLiteral *node, QgsExpression *expression, const QgsExpressionContext *context )
{
Q_UNUSED( expression )
Q_UNUSED( context )
QString value;
switch ( node->value().type() )
{
Expand All @@ -2415,6 +2424,12 @@ QDomElement QgsOgcUtilsExprToFilter::expressionLiteralToOgcFilter( const QgsExpr
case QVariant::String:
value = node->value().toString();
break;
case QVariant::Date:
value = node->value().toDate().toString( Qt::ISODate );
break;
case QVariant::DateTime:
value = node->value().toDateTime().toString( Qt::ISODate );
break;

default:
mErrorMessage = QObject::tr( "Literal type not supported: %1" ).arg( node->value().type() );
Expand All @@ -2427,26 +2442,28 @@ QDomElement QgsOgcUtilsExprToFilter::expressionLiteralToOgcFilter( const QgsExpr
}


QDomElement QgsOgcUtilsExprToFilter::expressionColumnRefToOgcFilter( const QgsExpressionNodeColumnRef *node )
QDomElement QgsOgcUtilsExprToFilter::expressionColumnRefToOgcFilter( const QgsExpressionNodeColumnRef *node, QgsExpression *expression, const QgsExpressionContext *context )
{
Q_UNUSED( expression )
Q_UNUSED( context )
QDomElement propElem = mDoc.createElement( mFilterPrefix + ":" + mPropertyName );
propElem.appendChild( mDoc.createTextNode( node->name() ) );
return propElem;
}



QDomElement QgsOgcUtilsExprToFilter::expressionInOperatorToOgcFilter( const QgsExpressionNodeInOperator *node )
QDomElement QgsOgcUtilsExprToFilter::expressionInOperatorToOgcFilter( const QgsExpressionNodeInOperator *node, QgsExpression *expression, const QgsExpressionContext *context )
{
if ( node->list()->list().size() == 1 )
return expressionNodeToOgcFilter( node->list()->list()[0] );
return expressionNodeToOgcFilter( node->list()->list()[0], expression, context );

QDomElement orElem = mDoc.createElement( mFilterPrefix + ":Or" );
QDomElement leftNode = expressionNodeToOgcFilter( node->node() );
QDomElement leftNode = expressionNodeToOgcFilter( node->node(), expression, context );

Q_FOREACH ( QgsExpressionNode *n, node->list()->list() )
{
QDomElement listNode = expressionNodeToOgcFilter( n );
QDomElement listNode = expressionNodeToOgcFilter( n, expression, context );
if ( !mErrorMessage.isEmpty() )
return QDomElement();

Expand Down Expand Up @@ -2521,7 +2538,7 @@ static QgsGeometry geometryFromConstExpr( const QgsExpressionNode *node )
}


QDomElement QgsOgcUtilsExprToFilter::expressionFunctionToOgcFilter( const QgsExpressionNodeFunction *node )
QDomElement QgsOgcUtilsExprToFilter::expressionFunctionToOgcFilter( const QgsExpressionNodeFunction *node, QgsExpression *expression, const QgsExpressionContext *context )
{
QgsExpressionFunction *fd = QgsExpression::Functions()[node->fnIndex()];

Expand Down Expand Up @@ -2633,6 +2650,13 @@ QDomElement QgsOgcUtilsExprToFilter::expressionFunctionToOgcFilter( const QgsExp
return funcElem;
}

if ( fd->isStatic( node, expression, context ) )
{
QVariant result = fd->run( node->args(), context, expression, node );
QgsExpressionNodeLiteral literal( result );
return expressionLiteralToOgcFilter( &literal, expression, context );
}

if ( fd->params() == 0 )
{
mErrorMessage = QObject::tr( "Special columns/constants are not supported." );
Expand All @@ -2644,7 +2668,7 @@ QDomElement QgsOgcUtilsExprToFilter::expressionFunctionToOgcFilter( const QgsExp
funcElem.setAttribute( QStringLiteral( "name" ), fd->name() );
Q_FOREACH ( QgsExpressionNode *n, node->args()->list() )
{
QDomElement childElem = expressionNodeToOgcFilter( n );
QDomElement childElem = expressionNodeToOgcFilter( n, expression, context );
if ( !mErrorMessage.isEmpty() )
return QDomElement();

Expand Down
14 changes: 7 additions & 7 deletions src/core/qgsogcutils.h
Expand Up @@ -338,7 +338,7 @@ class QgsOgcUtilsExprToFilter
bool invertAxisOrientation );

//! Convert an expression to a OGC filter
QDomElement expressionNodeToOgcFilter( const QgsExpressionNode *node );
QDomElement expressionNodeToOgcFilter( const QgsExpressionNode *node, QgsExpression *expression, const QgsExpressionContext *context );

//! Returns whether the gml: namespace is used
bool GMLNamespaceUsed() const { return mGMLUsed; }
Expand All @@ -359,12 +359,12 @@ class QgsOgcUtilsExprToFilter
QString mPropertyName;
int mGeomId;

QDomElement expressionUnaryOperatorToOgcFilter( const QgsExpressionNodeUnaryOperator *node );
QDomElement expressionBinaryOperatorToOgcFilter( const QgsExpressionNodeBinaryOperator *node );
QDomElement expressionLiteralToOgcFilter( const QgsExpressionNodeLiteral *node );
QDomElement expressionColumnRefToOgcFilter( const QgsExpressionNodeColumnRef *node );
QDomElement expressionInOperatorToOgcFilter( const QgsExpressionNodeInOperator *node );
QDomElement expressionFunctionToOgcFilter( const QgsExpressionNodeFunction *node );
QDomElement expressionUnaryOperatorToOgcFilter( const QgsExpressionNodeUnaryOperator *node, QgsExpression *expression, const QgsExpressionContext *context );
QDomElement expressionBinaryOperatorToOgcFilter( const QgsExpressionNodeBinaryOperator *node, QgsExpression *expression, const QgsExpressionContext *context );
QDomElement expressionLiteralToOgcFilter( const QgsExpressionNodeLiteral *node, QgsExpression *expression, const QgsExpressionContext *context );
QDomElement expressionColumnRefToOgcFilter( const QgsExpressionNodeColumnRef *node, QgsExpression *expression, const QgsExpressionContext *context );
QDomElement expressionInOperatorToOgcFilter( const QgsExpressionNodeInOperator *node, QgsExpression *expression, const QgsExpressionContext *context );
QDomElement expressionFunctionToOgcFilter( const QgsExpressionNodeFunction *node, QgsExpression *expression, const QgsExpressionContext *context );
};

/**
Expand Down
12 changes: 12 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -3133,6 +3133,18 @@ class TestQgsExpression: public QObject
QCOMPARE( QgsExpression::formatPreviewString( QVariant( stringList ) ),
QStringLiteral( "[ 'One', 'Two', 'A very long string that is going to be tr… ]" ) );
}

void test_nowStatic()
{
QgsExpression e( QStringLiteral( "now()" ) );
QgsExpressionContext ctx;
e.prepare( &ctx );
QVariant v = e.evaluate();
QTest::qSleep( 1000 );
QVariant v2 = e.evaluate();

QCOMPARE( v.toDateTime().toMSecsSinceEpoch(), v2.toDateTime().toMSecsSinceEpoch() );
}
};

QGSTEST_MAIN( TestQgsExpression )
Expand Down

0 comments on commit 3cd6899

Please sign in to comment.