Skip to content

Commit

Permalink
[Backport release-3_40] [WFS] Fix filtering by QGIS expression in ord…
Browse files Browse the repository at this point in the history
…er to support "@geometry" (Fix #60094) (#60118)

Fix #60094
  • Loading branch information
qgis-bot authored Jan 12, 2025
1 parent 225fbc6 commit 8ac2db8
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 32 deletions.
4 changes: 2 additions & 2 deletions python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ Also note:

- You can use various functions available in the QGIS Expression list,
however the function must exist server side and have the same name and arguments to work.
- Use the special $geometry parameter to provide the layer geometry column as input
into the spatial binary operators e.g intersects($geometry, geomFromWKT('POINT (5 6)'))
- Use the special ``@geometry`` parameter to provide the layer geometry column as input
into the spatial binary operators e.g ``intersects(@geometry, geomFromWKT('POINT (5 6)'))``

OGC API Features data provider (oapif)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions python/core/auto_generated/vector/qgsvectorlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ Also note:

- You can use various functions available in the QGIS Expression list,
however the function must exist server side and have the same name and arguments to work.
- Use the special $geometry parameter to provide the layer geometry column as input
into the spatial binary operators e.g intersects($geometry, geomFromWKT('POINT (5 6)'))
- Use the special ``@geometry`` parameter to provide the layer geometry column as input
into the spatial binary operators e.g ``intersects(@geometry, geomFromWKT('POINT (5 6)'))``

OGC API Features data provider (oapif)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsogcutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2318,7 +2318,7 @@ static bool isGeometryColumn( const QgsExpressionNode *node )

const QgsExpressionNodeFunction *fn = static_cast<const QgsExpressionNodeFunction *>( node );
QgsExpressionFunction *fd = QgsExpression::Functions()[fn->fnIndex()];
return fd->name() == QLatin1String( "$geometry" );
return fd->name() == QLatin1String( "$geometry" ) || ( fd->name() == QLatin1String( "var" ) && fn->referencedVariables().contains( QLatin1String( "geometry" ) ) );
}

static QgsGeometry geometryFromConstExpr( const QgsExpressionNode *node )
Expand Down Expand Up @@ -2382,7 +2382,7 @@ QDomElement QgsOgcUtilsExprToFilter::expressionFunctionToOgcFilter( const QgsExp
}
else
{
mErrorMessage = QObject::tr( "<BBOX> is currently supported only in form: bbox($geometry, geomFromWKT('…'))" );
mErrorMessage = QObject::tr( "<BBOX> is currently supported only in form: bbox(@geometry, geomFromWKT('…'))" );
return QDomElement();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/vector/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ typedef QSet<int> QgsAttributeIds;
*
* - You can use various functions available in the QGIS Expression list,
* however the function must exist server side and have the same name and arguments to work.
* - Use the special $geometry parameter to provide the layer geometry column as input
* into the spatial binary operators e.g intersects($geometry, geomFromWKT('POINT (5 6)'))
* - Use the special ``@geometry`` parameter to provide the layer geometry column as input
* into the spatial binary operators e.g ``intersects(@geometry, geomFromWKT('POINT (5 6)'))``
*
* \subsection oapif OGC API Features data provider (oapif)
*
Expand Down
135 changes: 111 additions & 24 deletions tests/src/core/testqgsogcutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,26 +733,47 @@ void TestQgsOgcUtils::testExpressionToOgcFilter_data()
"</ogc:Not>"
"</ogc:Filter>" );

QTest::newRow( "intersects_bbox" ) << QStringLiteral( "intersects_bbox($geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:BBOX>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Box><gml:coordinates ts=\" \" cs=\",\">5,6 5,6</gml:coordinates></gml:Box>"
"</ogc:BBOX>"
"</ogc:Filter>" );

QTest::newRow( "intersects + wkt" ) << QStringLiteral( "intersects($geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Intersects>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Point><gml:coordinates ts=\" \" cs=\",\">5,6</gml:coordinates></gml:Point>"
"</ogc:Intersects>"
"</ogc:Filter>" );

QTest::newRow( "contains + gml" ) << QStringLiteral( "contains($geometry, geomFromGML('<Point><coordinates cs=\",\" ts=\" \">5,6</coordinates></Point>'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Contains>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<Point><coordinates ts=\" \" cs=\",\">5,6</coordinates></Point>"
"</ogc:Contains>"
"</ogc:Filter>" );
QTest::newRow( "intersects_bbox $geometry" ) << QStringLiteral( "intersects_bbox($geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:BBOX>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Box><gml:coordinates ts=\" \" cs=\",\">5,6 5,6</gml:coordinates></gml:Box>"
"</ogc:BBOX>"
"</ogc:Filter>" );

QTest::newRow( "intersects + wkt $geometry" ) << QStringLiteral( "intersects($geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Intersects>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Point><gml:coordinates ts=\" \" cs=\",\">5,6</gml:coordinates></gml:Point>"
"</ogc:Intersects>"
"</ogc:Filter>" );

QTest::newRow( "contains + gml $geometry" ) << QStringLiteral( "contains($geometry, geomFromGML('<Point><coordinates cs=\",\" ts=\" \">5,6</coordinates></Point>'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Contains>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<Point><coordinates ts=\" \" cs=\",\">5,6</coordinates></Point>"
"</ogc:Contains>"
"</ogc:Filter>" );

QTest::newRow( "intersects_bbox @geometry" ) << QStringLiteral( "intersects_bbox(@geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:BBOX>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Box><gml:coordinates ts=\" \" cs=\",\">5,6 5,6</gml:coordinates></gml:Box>"
"</ogc:BBOX>"
"</ogc:Filter>" );

QTest::newRow( "intersects + wkt @geometry" ) << QStringLiteral( "intersects(@geometry, geomFromWKT('POINT (5 6)'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Intersects>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<gml:Point><gml:coordinates ts=\" \" cs=\",\">5,6</gml:coordinates></gml:Point>"
"</ogc:Intersects>"
"</ogc:Filter>" );

QTest::newRow( "contains + gml @geometry" ) << QStringLiteral( "contains(@geometry, geomFromGML('<Point><coordinates cs=\",\" ts=\" \">5,6</coordinates></Point>'))" ) << QString( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:Contains>"
"<ogc:PropertyName>geometry</ogc:PropertyName>"
"<Point><coordinates ts=\" \" cs=\",\">5,6</coordinates></Point>"
"</ogc:Contains>"
"</ogc:Filter>" );
}

void TestQgsOgcUtils::testExpressionToOgcFilterWFS11()
Expand Down Expand Up @@ -791,7 +812,7 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS11_data()
QTest::addColumn<QString>( "srsName" );
QTest::addColumn<QString>( "xmlText" );

QTest::newRow( "bbox" )
QTest::newRow( "bbox $geometry" )
<< QStringLiteral( "intersects_bbox($geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
Expand All @@ -805,6 +826,21 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS11_data()
"</ogc:BBOX>"
"</ogc:Filter>"
);

QTest::newRow( "bbox @geometry" )
<< QStringLiteral( "intersects_bbox(@geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
"<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:gml=\"http://www.opengis.net/gml\">"
"<ogc:BBOX>"
"<ogc:PropertyName>my_geometry_name</ogc:PropertyName>"
"<gml:Envelope srsName=\"urn:ogc:def:crs:EPSG::4326\">"
"<gml:lowerCorner>49 2</gml:lowerCorner>"
"<gml:upperCorner>50 3</gml:upperCorner>"
"</gml:Envelope>"
"</ogc:BBOX>"
"</ogc:Filter>"
);
}

void TestQgsOgcUtils::testExpressionToOgcFilterWFS20()
Expand Down Expand Up @@ -860,7 +896,7 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS20_data()
"</fes:PropertyIsEqualTo></fes:Filter>" )
<< QStringLiteral( "myns" ) << QStringLiteral( "http://example.com/myns" );

QTest::newRow( "bbox" )
QTest::newRow( "bbox $geometry" )
<< QStringLiteral( "intersects_bbox($geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
Expand All @@ -876,7 +912,7 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS20_data()
)
<< QString() << QString();

QTest::newRow( "bbox with namespace" )
QTest::newRow( "bbox with namespace $geometry" )
<< QStringLiteral( "intersects_bbox($geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
Expand All @@ -892,7 +928,7 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS20_data()
)
<< QStringLiteral( "myns" ) << QStringLiteral( "http://example.com/myns" );

QTest::newRow( "intersects" )
QTest::newRow( "intersects $geometry" )
<< QStringLiteral( "intersects($geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
Expand All @@ -910,6 +946,57 @@ void TestQgsOgcUtils::testExpressionToOgcFilterWFS20_data()
"</fes:Filter>"
)
<< QString() << QString();

QTest::newRow( "bbox @geometry" )
<< QStringLiteral( "intersects_bbox(@geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
"<fes:Filter xmlns:fes=\"http://www.opengis.net/fes/2.0\" xmlns:gml=\"http://www.opengis.net/gml/3.2\">"
"<fes:BBOX>"
"<fes:ValueReference>my_geometry_name</fes:ValueReference>"
"<gml:Envelope srsName=\"urn:ogc:def:crs:EPSG::4326\">"
"<gml:lowerCorner>49 2</gml:lowerCorner>"
"<gml:upperCorner>50 3</gml:upperCorner>"
"</gml:Envelope>"
"</fes:BBOX>"
"</fes:Filter>"
)
<< QString() << QString();

QTest::newRow( "bbox with namespace @geometry" )
<< QStringLiteral( "intersects_bbox(@geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
"<fes:Filter xmlns:fes=\"http://www.opengis.net/fes/2.0\" xmlns:gml=\"http://www.opengis.net/gml/3.2\" xmlns:myns=\"http://example.com/myns\">"
"<fes:BBOX>"
"<fes:ValueReference>myns:my_geometry_name</fes:ValueReference>"
"<gml:Envelope srsName=\"urn:ogc:def:crs:EPSG::4326\">"
"<gml:lowerCorner>49 2</gml:lowerCorner>"
"<gml:upperCorner>50 3</gml:upperCorner>"
"</gml:Envelope>"
"</fes:BBOX>"
"</fes:Filter>"
)
<< QStringLiteral( "myns" ) << QStringLiteral( "http://example.com/myns" );

QTest::newRow( "intersects @geometry" )
<< QStringLiteral( "intersects(@geometry, geomFromWKT('POLYGON((2 49,2 50,3 50,3 49,2 49))'))" )
<< QStringLiteral( "urn:ogc:def:crs:EPSG::4326" )
<< QString(
"<fes:Filter xmlns:fes=\"http://www.opengis.net/fes/2.0\" xmlns:gml=\"http://www.opengis.net/gml/3.2\">"
"<fes:Intersects>"
"<fes:ValueReference>my_geometry_name</fes:ValueReference>"
"<gml:Polygon gml:id=\"qgis_id_geom_1\" srsName=\"urn:ogc:def:crs:EPSG::4326\">"
"<gml:exterior>"
"<gml:LinearRing>"
"<gml:posList srsDimension=\"2\">49 2 50 2 50 3 49 3 49 2</gml:posList>"
"</gml:LinearRing>"
"</gml:exterior>"
"</gml:Polygon>"
"</fes:Intersects>"
"</fes:Filter>"
)
<< QString() << QString();
}

Q_DECLARE_METATYPE( QgsOgcUtils::GMLVersion )
Expand Down

0 comments on commit 8ac2db8

Please sign in to comment.