Skip to content
Permalink
Browse files

Add option to regenerate primary key to QgsVectorLayerUtils.makeFeatu…

…resCompatible

Allows us to optionally reset the fid field value when required
  • Loading branch information
nyalldawson committed Oct 15, 2020
1 parent a53bb3d commit 4b3703d87c3dcfb5c44b2d478083c683462c95f1
@@ -237,7 +237,7 @@ Finally, the feature's fields are set to ``fields``.
.. versionadded:: 3.4
%End

static QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer );
static QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags() );
%Docstring
Converts input ``feature`` to be compatible with the given ``layer``.

@@ -255,10 +255,12 @@ The following operations will be performed to convert the input features:
- drop Z/M
- convert multi part geometries to single part

Optionally, ``sinkFlags`` can be specified to further refine the compatibility logic.

.. versionadded:: 3.4
%End

static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer );
static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags() );
%Docstring
Converts input ``features`` to be compatible with the given ``layer``.

@@ -276,6 +278,8 @@ The following operations will be performed to convert the input features:
- drop Z/M
- convert multi part geometries to single part

Optionally, ``sinkFlags`` can be specified to further refine the compatibility logic.

.. versionadded:: 3.4
%End

@@ -735,13 +735,22 @@ void QgsVectorLayerUtils::matchAttributesToFields( QgsFeature &feature, const Qg
feature.setFields( fields );
}

QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer )
QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
{
QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
QgsFeatureList resultFeatures;
QgsFeature newF( feature );
// Fix attributes
QgsVectorLayerUtils::matchAttributesToFields( newF, layer->fields( ) );

if ( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey && layer->storageType() == QLatin1String( "GPKG" ) )
{
// drop incoming fid value, let it be regenerated
const int fidIndex = layer->fields().lookupField( QStringLiteral( "fid" ) );
if ( fidIndex >= 0 )
newF.setAttribute( fidIndex, QVariant() );
}

// Does geometry need transformations?
QgsWkbTypes::GeometryType newFGeomType( QgsWkbTypes::geometryType( newF.geometry().wkbType() ) );
bool newFHasGeom = newFGeomType !=
@@ -785,12 +794,12 @@ QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &fea
return resultFeatures;
}

QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer )
QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
{
QgsFeatureList resultFeatures;
for ( const QgsFeature &f : features )
{
const QgsFeatureList features( makeFeatureCompatible( f, layer ) );
const QgsFeatureList features( makeFeatureCompatible( f, layer, sinkFlags ) );
for ( const auto &_f : features )
{
resultFeatures.append( _f );
@@ -20,6 +20,7 @@
#include "qgsgeometry.h"
#include "qgsvectorlayerfeatureiterator.h"
#include "qgssymbollayerreference.h"
#include "qgsfeaturesink.h"

class QgsFeatureRenderer;
class QgsSymbolLayer;
@@ -264,9 +265,11 @@ class CORE_EXPORT QgsVectorLayerUtils
* - drop Z/M
* - convert multi part geometries to single part
*
* Optionally, \a sinkFlags can be specified to further refine the compatibility logic.
*
* \since QGIS 3.4
*/
static QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer );
static QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags() );

/**
* Converts input \a features to be compatible with the given \a layer.
@@ -285,9 +288,11 @@ class CORE_EXPORT QgsVectorLayerUtils
* - drop Z/M
* - convert multi part geometries to single part
*
* Optionally, \a sinkFlags can be specified to further refine the compatibility logic.
*
* \since QGIS 3.4
*/
static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer );
static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags() );

/**
* \return true if the \param feature field at index \param fieldIndex from \param layer
@@ -28,7 +28,8 @@
QgsCoordinateReferenceSystem,
QgsProject,
QgsProcessingException,
QgsVectorLayer
QgsVectorLayer,
QgsFeatureSink
)
from processing.core.Processing import Processing
from processing.core.ProcessingConfig import ProcessingConfig
@@ -912,6 +913,26 @@ def test_unique_constraints(self):

self.assertTrue(gpkg_layer.commitChanges())

def test_regenerate_fid(self):
"""Test RegeneratePrimaryKey flag"""
temp_dir = QTemporaryDir()
temp_path = temp_dir.path()
gpkg_name = 'bug_31634_Multi_to_Singleparts_FID.gpkg'
gpkg_path = os.path.join(temp_path, gpkg_name)
shutil.copyfile(os.path.join(unitTestDataPath(), gpkg_name), gpkg_path)

gpkg_layer = QgsVectorLayer(gpkg_path + '|layername=Multi_to_Singleparts_FID_bug', 'lyr', 'ogr')
self.assertTrue(gpkg_layer.isValid())

f = next(gpkg_layer.getFeatures())
self.assertEqual(f['fid'], 1)
res = QgsVectorLayerUtils.makeFeatureCompatible(f, gpkg_layer)
self.assertEqual([ff['fid'] for ff in res], [1])

# if RegeneratePrimaryKey set then we should discard fid field
res = QgsVectorLayerUtils.makeFeatureCompatible(f, gpkg_layer, QgsFeatureSink.RegeneratePrimaryKey)
self.assertEqual([ff['fid'] for ff in res], [None])


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

0 comments on commit 4b3703d

Please sign in to comment.
You can’t perform that action at this time.