Skip to content

Commit

Permalink
Merge pull request #51590 from domi4484/oapifFasterFeatureCount
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Feb 1, 2023
2 parents b905cac + 2200dbd commit 0a94cc2
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
29 changes: 29 additions & 0 deletions src/providers/wfs/oapif/qgsoapifprovider.cpp
Expand Up @@ -214,6 +214,34 @@ QgsWkbTypes::Type QgsOapifProvider::wkbType() const

long long QgsOapifProvider::featureCount() const
{
// If no filter is set try the fast way of retrieving the feature count
if ( mSubsetString.isEmpty() )
{
QString url = mShared->mItemsUrl;
url += QStringLiteral( "?limit=1" );
url = mShared->appendExtraQueryParameters( url );

if ( !mShared->mServerFilter.isEmpty() )
{
url += QStringLiteral( "&" );
url += mShared->mServerFilter;
}

QgsOapifItemsRequest itemsRequest( mShared->mURI.uri(), url );
if ( !itemsRequest.request( true, false ) )
return -1;
if ( itemsRequest.errorCode() != QgsBaseNetworkRequest::NoError )
return -1;

const long long featureCount = itemsRequest.numberMatched();
if ( featureCount >= 0 )
{
mShared->setFeatureCount( featureCount, true );
return featureCount;
}
}

// Retry the slow way by active filter or numberMatched parameter not sent from server
if ( mUpdateFeatureCountAtNextFeatureCountRequest )
{
mUpdateFeatureCountAtNextFeatureCountRequest = false;
Expand All @@ -236,6 +264,7 @@ long long QgsOapifProvider::featureCount() const

mShared->setFeatureCount( count, countExact );
}

return mShared->getFeatureCount();
}

Expand Down
4 changes: 2 additions & 2 deletions src/providers/wfs/oapif/qgsoapifprovider.h
Expand Up @@ -109,8 +109,8 @@ class QgsOapifProvider final: public QgsVectorDataProvider
//! Layer metadata
QgsLayerMetadata mLayerMetadata;

//! Set to true by setSubsetString() if updateFeatureCount is true
mutable bool mUpdateFeatureCountAtNextFeatureCountRequest = false;
//! Set to true by reloadProviderData()
mutable bool mUpdateFeatureCountAtNextFeatureCountRequest = true;

//! Initial requests
bool init();
Expand Down
53 changes: 53 additions & 0 deletions tests/src/python/test_provider_oapif.py
Expand Up @@ -145,6 +145,7 @@ def setUpClass(cls):

items = {
"type": "FeatureCollection",
"numberMatched": 5,
"features": [
{"type": "Feature", "id": "feat.1",
"properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"},
Expand All @@ -164,6 +165,10 @@ def setUpClass(cls):
]
}

# limit 1 for getting count
with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(items).encode('UTF-8'))

# first items
with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(items).encode('UTF-8'))
Expand Down Expand Up @@ -817,6 +822,54 @@ def testCRS2056(self):

self.assertEqual(source.sourceCrs().authid(), 'EPSG:2056')

def testFeatureCountFallback(self):

# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
basetestpath = tempfile.mkdtemp().replace('\\', '/')
endpoint = basetestpath + '/fake_qgis_http_endpoint_feature_count_fallback'

create_landing_page_api_collection(endpoint,
crs_url="http://www.opengis.net/def/crs/EPSG/0/2056",
bbox=[2508500, 1152000, 2513450, 1156950])

items = {
"type": "FeatureCollection",
"features": [
{"type": "Feature", "id": "feat.1",
"properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"},
"geometry": {"type": "Point", "coordinates": [2510100, 1155050]}},
{"type": "Feature", "id": "feat.2",
"properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"},
"geometry": {"type": "Point", "coordinates": [2511250, 1154600]}},
{"type": "Feature", "id": "feat.3",
"properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"},
"geometry": {"type": "Point", "coordinates": [2511260, 1154610]}},
{"type": "Feature", "id": "feat.4",
"properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"},
"geometry": {"type": "Point", "coordinates": [2511270, 1154620]}}
]
}

# first items
with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(items).encode('UTF-8'))

# first items
with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(items).encode('UTF-8'))

# real page
with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(items).encode('UTF-8'))

# Create test layer
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
assert vl.isValid()
source = vl.dataProvider()

self.assertEqual(source.featureCount(), 4)


if __name__ == '__main__':
unittest.main()

0 comments on commit 0a94cc2

Please sign in to comment.