Skip to content

Commit

Permalink
Try to use provider native method for saving default metadata before
Browse files Browse the repository at this point in the history
resorting to .qmd sidecar files

This ensures we correctly store metadata in the gpkg_metadata table,
linked to the associated table, for GPKG files instead of as sidecar files.

Fixes #31161, fixes #25119
  • Loading branch information
nyalldawson committed May 4, 2021
1 parent 4cbec54 commit 0a12fc7
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/core/qgsmaplayer.cpp
Expand Up @@ -59,6 +59,7 @@
#include "qgsmessagelog.h"
#include "qgsmaplayertemporalproperties.h"
#include "qgsmaplayerelevationproperties.h"
#include "qgsprovidermetadata.h"

QString QgsMapLayer::extensionPropertyType( QgsMapLayer::PropertyType type )
{
Expand Down Expand Up @@ -880,6 +881,28 @@ QString QgsMapLayer::metadataUri() const

QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
{
if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
{
if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
{
try
{
QString errorMessage;
resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
if ( resultFlag )
return tr( "Successfully saved default layer metadata" );
else
return errorMessage;
}
catch ( QgsNotSupportedException &e )
{
resultFlag = false;
return e.what();
}
}
}

// fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
return saveNamedMetadata( metadataUri(), resultFlag );
}

Expand Down
16 changes: 16 additions & 0 deletions tests/src/python/test_provider_ogr.py
Expand Up @@ -1271,6 +1271,22 @@ def testSaveMetadataUnsupported(self):
with self.assertRaises(QgsNotSupportedException):
QgsProviderRegistry.instance().saveLayerMetadata('ogr', 'WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', metadata)

def testSaveDefaultMetadataUnsupported(self):
"""
Test saving default metadata to an unsupported layer
"""
layer = QgsVectorLayer('WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', 'test')
# now save some metadata
metadata = QgsLayerMetadata()
metadata.setAbstract('my abstract')
metadata.setIdentifier('my identifier')
metadata.setLicenses(['l1', 'l2'])
layer.setMetadata(metadata)
# save as default
msg, res = layer.saveDefaultMetadata()
self.assertFalse(res)
self.assertEqual(msg, 'Storing metadata for the specified uri is not supported')

def testEmbeddedSymbolsKml(self):
"""
Test retrieving embedded symbols from a KML file
Expand Down
58 changes: 58 additions & 0 deletions tests/src/python/test_provider_ogr_gpkg.py
Expand Up @@ -1717,6 +1717,64 @@ def testGeopackageRestoreMetadata(self):
self.assertEqual(metadata2.identifier(), 'my identifier')
self.assertEqual(metadata2.licenses(), ['l1', 'l2'])

def testGeopackageSaveDefaultMetadata(self):
"""
Test saving layer metadata as default to a gpkg file
"""
tmpfile = os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.gpkg')
ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
f = None
ds = None

uri = QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'})
layer = QgsVectorLayer(uri, 'test')
self.assertTrue(layer.isValid())
# now save some metadata
metadata = QgsLayerMetadata()
metadata.setAbstract('my abstract')
metadata.setIdentifier('my identifier')
metadata.setLicenses(['l1', 'l2'])
layer.setMetadata(metadata)
# save as default
msg, res = layer.saveDefaultMetadata()
self.assertTrue(res)

# QMD sidecar should NOT exist -- metadata should be written to gpkg_metadata table
self.assertFalse(os.path.exists(os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.qmd')))

con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()

# check that main gpkg_contents metadata columns have been updated
rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'")
rows = [r for r in rs]
self.assertEqual(len(rows), 1)
self.assertCountEqual(rows[0], ['my identifier', 'my abstract'])

rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'")
rows = [r for r in rs]
file_ids = [row[0] for row in rows]
self.assertTrue(file_ids)

rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'")
res = [row for row in rs]
self.assertEqual(len(res), 1)
# id must match md_file_id from gpkg_metadata_reference
self.assertIn(res[0][0], file_ids)
self.assertEqual(res[0][1], 'dataset')
self.assertEqual(res[0][2], 'text/xml')
con.close()

# reload layer and check that metadata was restored
layer2 = QgsVectorLayer(uri, 'test')
self.assertTrue(layer2.isValid())
self.assertEqual(layer2.metadata().abstract(), 'my abstract')
self.assertEqual(layer2.metadata().identifier(), 'my identifier')
self.assertEqual(layer2.metadata().licenses(), ['l1', 'l2'])

def testUniqueValuesOnFidColumn(self):
"""Test regression #21311 OGR provider returns an empty set for GPKG uniqueValues"""

Expand Down

0 comments on commit 0a12fc7

Please sign in to comment.