Skip to content

Commit

Permalink
Merge pull request #47053 from nirvn/save_as_gpkg_preserve_array
Browse files Browse the repository at this point in the history
[vector file writer] Preserve array fields when saving as geopackage
  • Loading branch information
nirvn committed Jan 30, 2022
2 parents cf92467 + c14de22 commit 8860a8a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 8 deletions.
56 changes: 48 additions & 8 deletions src/core/qgsvectorfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "qgsfeature.h"
#include "qgsfeatureiterator.h"
#include "qgsgeometry.h"

#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgscoordinatereferencesystem.h"
Expand All @@ -47,6 +48,7 @@
#include <QMetaType>
#include <QMutex>
#include <QRegularExpression>
#include <QJsonDocument>

#include <cassert>
#include <cstdlib> // size_t
Expand Down Expand Up @@ -597,6 +599,7 @@ void QgsVectorFileWriter::init( QString vectorFileName,
}

OGRFieldType ogrType = OFTString; //default to string
OGRFieldSubType ogrSubType = OFSTNone;
int ogrWidth = attrField.length();
int ogrPrecision = attrField.precision();
if ( ogrPrecision > 0 )
Expand Down Expand Up @@ -629,6 +632,7 @@ void QgsVectorFileWriter::init( QString vectorFileName,

case QVariant::Bool:
ogrType = OFTInteger;
ogrSubType = OFSTBoolean;
ogrWidth = 1;
ogrPrecision = 0;
break;
Expand Down Expand Up @@ -679,6 +683,14 @@ void QgsVectorFileWriter::init( QString vectorFileName,

case QVariant::StringList:
{
// handle GPKG conversion to JSON
if ( mOgrDriverName == QLatin1String( "GPKG" ) )
{
ogrType = OFTString;
ogrSubType = OFSTJSON;
break;
}

const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES, nullptr );
if ( pszDataTypes && strstr( pszDataTypes, "StringList" ) )
{
Expand All @@ -694,6 +706,14 @@ void QgsVectorFileWriter::init( QString vectorFileName,
}

case QVariant::List:
// handle GPKG conversion to JSON
if ( mOgrDriverName == QLatin1String( "GPKG" ) )
{
ogrType = OFTString;
ogrSubType = OFSTJSON;
break;
}

// fall through to default for other unsupported types
if ( attrField.subType() == QVariant::String )
{
Expand Down Expand Up @@ -803,14 +823,8 @@ void QgsVectorFileWriter::init( QString vectorFileName,
OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
}

switch ( attrField.type() )
{
case QVariant::Bool:
OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
break;
default:
break;
}
if ( ogrSubType != OFSTNone )
OGR_Fld_SetSubType( fld.get(), ogrSubType );

// create the field
QgsDebugMsgLevel( "creating field " + attrField.name() +
Expand Down Expand Up @@ -2537,6 +2551,19 @@ gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeatur

case QVariant::StringList:
{
// handle GPKG conversion to JSON
if ( mOgrDriverName == QLatin1String( "GPKG" ) )
{
const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
QString jsonString;
if ( !doc.isNull() )
{
jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).constData() );
}
OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( jsonString.constData() ) );
break;
}

QStringList list = attrValue.toStringList();
if ( mSupportedListSubTypes.contains( QVariant::String ) )
{
Expand All @@ -2563,6 +2590,19 @@ gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeatur
}

case QVariant::List:
// handle GPKG conversion to JSON
if ( mOgrDriverName == QLatin1String( "GPKG" ) )
{
const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
QString jsonString;
if ( !doc.isNull() )
{
jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).data() );
}
OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( jsonString.constData() ) );
break;
}

// fall through to default for unsupported types
if ( field.subType() == QVariant::String )
{
Expand Down
43 changes: 43 additions & 0 deletions tests/src/core/testqgsvectorfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class TestQgsVectorFileWriter: public QObject
void prepareWriteAsVectorFormat();
//! Test regression #21714 (Exported GeoPackages have wrong field definitions)
void testTextFieldLength();
//! Test export of array fields to GeoPackages
void testExportArrayToGpkg();
//! Test https://github.com/qgis/QGIS/issues/29819
void testExportToGpxPoint();
//! Test https://github.com/qgis/QGIS/issues/29819
Expand Down Expand Up @@ -535,6 +537,47 @@ void TestQgsVectorFileWriter::testTextFieldLength()

}

void TestQgsVectorFileWriter::testExportArrayToGpkg()
{
QTemporaryFile tmpFile( QDir::tempPath() + "/test_qgsvectorfilewriter3_XXXXXX.gpkg" );
tmpFile.open();
const QString fileName( tmpFile.fileName( ) );
QgsVectorLayer vl( "Point?field=arrayfield:integerlist&field=arrayfield2:stringlist", "test", "memory" );
QCOMPARE( vl.fields().at( 0 ).type(), QVariant::List );
QCOMPARE( vl.fields().at( 0 ).subType(), QVariant::Int );
QCOMPARE( vl.fields().at( 1 ).type(), QVariant::StringList );
QCOMPARE( vl.fields().at( 1 ).subType(), QVariant::String );
QgsFeature f { vl.fields() };
f.setAttribute( 0, QVariantList() << 1 << 2 << 3 );
f.setAttribute( 1, QStringList() << "a" << "b" << "c" );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "point(9 45)" ) ) );
QVERIFY( vl.startEditing() );
QVERIFY( vl.addFeature( f ) );
QgsVectorFileWriter::SaveVectorOptions options;
options.driverName = "GPKG";
options.layerName = "test";
QString newFilename;
const QgsVectorFileWriter::WriterError error( QgsVectorFileWriter::writeAsVectorFormatV3(
&vl,
fileName,
vl.transformContext(),
options, nullptr,
&newFilename ) );
QCOMPARE( error, QgsVectorFileWriter::WriterError::NoError );
QCOMPARE( newFilename, fileName );
const QgsVectorLayer vl2( QStringLiteral( "%1|layername=test" ).arg( fileName ), "src_test", "ogr" );
QVERIFY( vl2.isValid() );
QCOMPARE( vl2.featureCount(), 1L );
QCOMPARE( vl2.fields().at( 1 ).type(), QVariant::Map );
QCOMPARE( vl2.fields().at( 1 ).subType(), QVariant::String );
QCOMPARE( vl2.fields().at( 1 ).typeName(), QStringLiteral( "JSON" ) );
QCOMPARE( vl2.fields().at( 2 ).type(), QVariant::Map );
QCOMPARE( vl2.fields().at( 2 ).subType(), QVariant::String );
QCOMPARE( vl2.fields().at( 2 ).typeName(), QStringLiteral( "JSON" ) );
QCOMPARE( vl2.getFeature( 1 ).attribute( 1 ).toList(), QVariantList() << 1 << 2 << 3 );
QCOMPARE( vl2.getFeature( 1 ).attribute( 2 ).toStringList(), QStringList() << "a" << "b" << "c" );
}

void TestQgsVectorFileWriter::_testExportToGpx( const QString &geomTypeName,
const QString &wkt,
const QString &expectedLayerName,
Expand Down

0 comments on commit 8860a8a

Please sign in to comment.