Skip to content

Commit

Permalink
Add some helpful api to QgsFields
Browse files Browse the repository at this point in the history
- Construct QgsFields from a list of QgsField
- Append a list of QgsField
- Append another QgsFields
  • Loading branch information
nyalldawson committed Jul 2, 2024
1 parent 4cee1e1 commit 71e574d
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 0 deletions.
25 changes: 25 additions & 0 deletions python/PyQt6/core/auto_generated/qgsfields.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ Copy constructor
%End


QgsFields( const QList< QgsField > &fields ) /HoldGIL/;
%Docstring
Construct QgsFields from a list of ``fields``.

.. versionadded:: 3.40
%End

virtual ~QgsFields();

void clear() /HoldGIL/;
Expand All @@ -63,6 +70,24 @@ The ``originIndex`` argument must be set to a value corresponding to the ``origi
- :py:class:`Qgis`.FieldOrigin.Provider: The field's originIndex is the index in provider's fields.
- :py:class:`Qgis`.FieldOrigin.Join: The field's originIndex / 1000 = index of the join, originIndex % 1000 = index within the join
- :py:class:`Qgis`.FieldOrigin.Edit: The originIndex is the index in the list of added attributes
%End

bool append( const QList< QgsField > &fields, Qgis::FieldOrigin origin = Qgis::FieldOrigin::Provider ) /HoldGIL/;
%Docstring
Appends a list of ``fields``.

The fields must have unique names, otherwise it is rejected (returns ``False``).

.. versionadded:: 3.40
%End

bool append( const QgsFields &fields ) /HoldGIL/;
%Docstring
Appends another set of ``fields`` to these fields.

The fields must have unique names, otherwise it is rejected (returns ``False``).

.. versionadded:: 3.40
%End

bool rename( int fieldIdx, const QString &name ) /HoldGIL/;
Expand Down
25 changes: 25 additions & 0 deletions python/core/auto_generated/qgsfields.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ Copy constructor
%End


QgsFields( const QList< QgsField > &fields ) /HoldGIL/;
%Docstring
Construct QgsFields from a list of ``fields``.

.. versionadded:: 3.40
%End

virtual ~QgsFields();

void clear() /HoldGIL/;
Expand All @@ -63,6 +70,24 @@ The ``originIndex`` argument must be set to a value corresponding to the ``origi
- :py:class:`Qgis`.FieldOrigin.Provider: The field's originIndex is the index in provider's fields.
- :py:class:`Qgis`.FieldOrigin.Join: The field's originIndex / 1000 = index of the join, originIndex % 1000 = index within the join
- :py:class:`Qgis`.FieldOrigin.Edit: The originIndex is the index in the list of added attributes
%End

bool append( const QList< QgsField > &fields, Qgis::FieldOrigin origin = Qgis::FieldOrigin::Provider ) /HoldGIL/;
%Docstring
Appends a list of ``fields``.

The fields must have unique names, otherwise it is rejected (returns ``False``).

.. versionadded:: 3.40
%End

bool append( const QgsFields &fields ) /HoldGIL/;
%Docstring
Appends another set of ``fields`` to these fields.

The fields must have unique names, otherwise it is rejected (returns ``False``).

.. versionadded:: 3.40
%End

bool rename( int fieldIdx, const QString &name ) /HoldGIL/;
Expand Down
39 changes: 39 additions & 0 deletions src/core/qgsfields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ QgsFields &QgsFields::operator =( const QgsFields &other ) //NOLINT
return *this;
}

QgsFields::QgsFields( const QList<QgsField> &fields )
{
d = new QgsFieldsPrivate();
for ( const QgsField &field : fields )
{
append( field );
}
}

QgsFields::~QgsFields() //NOLINT
{}

Expand Down Expand Up @@ -70,6 +79,36 @@ bool QgsFields::append( const QgsField &field, Qgis::FieldOrigin origin, int ori
return true;
}

bool QgsFields::append( const QList<QgsField> &fields, Qgis::FieldOrigin origin )
{
for ( const QgsField &field : fields )
{
if ( d->nameToIndex.contains( field.name() ) )
return false;
}

for ( const QgsField &field : fields )
{
append( field, origin );
}
return true;
}

bool QgsFields::append( const QgsFields &fields )
{
for ( const QgsField &field : fields )
{
if ( d->nameToIndex.contains( field.name() ) )
return false;
}

for ( int i = 0; i < fields.size(); ++ i )
{
append( fields.at( i ), fields.fieldOrigin( i ), fields.fieldOriginIndex( i ) );
}
return true;
}

bool QgsFields::rename( int fieldIdx, const QString &name )
{
if ( !exists( fieldIdx ) )
Expand Down
25 changes: 25 additions & 0 deletions src/core/qgsfields.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ class CORE_EXPORT QgsFields
*/
QgsFields &operator =( const QgsFields &other ) SIP_SKIP;

/**
* Construct QgsFields from a list of \a fields.
*
* \since QGIS 3.40
*/
QgsFields( const QList< QgsField > &fields ) SIP_HOLDGIL;

virtual ~QgsFields();

//! Removes all fields
Expand All @@ -110,6 +117,24 @@ class CORE_EXPORT QgsFields
*/
bool append( const QgsField &field, Qgis::FieldOrigin origin = Qgis::FieldOrigin::Provider, int originIndex = -1 ) SIP_HOLDGIL;

/**
* Appends a list of \a fields.
*
* The fields must have unique names, otherwise it is rejected (returns FALSE).
*
* \since QGIS 3.40
*/
bool append( const QList< QgsField > &fields, Qgis::FieldOrigin origin = Qgis::FieldOrigin::Provider ) SIP_HOLDGIL;

/**
* Appends another set of \a fields to these fields.
*
* The fields must have unique names, otherwise it is rejected (returns FALSE).
*
* \since QGIS 3.40
*/
bool append( const QgsFields &fields ) SIP_HOLDGIL;

/**
* Renames a name of field. The field must have unique name, otherwise change is rejected (returns FALSE)
* \since QGIS 3.6
Expand Down
173 changes: 173 additions & 0 deletions tests/src/core/testqgsfields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class TestQgsFields: public QObject
void assignment();
void equality(); //test equality operators
void asVariant(); //test conversion to and from a QVariant
void construct();
void clear();
void exists();
void count();
Expand All @@ -54,6 +55,8 @@ class TestQgsFields: public QObject
void qforeach();
void iterator();
void constIterator();
void appendList();
void appendQgsFields();

private:
};
Expand Down Expand Up @@ -164,6 +167,30 @@ void TestQgsFields::asVariant()
QCOMPARE( fromVar, original );
}

void TestQgsFields::construct()
{
// construct using a list of fields
QgsFields fields(
QList< QgsField >
{
QgsField( QStringLiteral( "field1" ), QMetaType::Type::QString ),
QgsField( QStringLiteral( "field2" ), QMetaType::Type::Int ),
QgsField( QStringLiteral( "field3" ), QMetaType::Type::Double ),
}
);

QCOMPARE( fields.size(), 3 );
QCOMPARE( fields.at( 0 ).name(), QStringLiteral( "field1" ) );
QCOMPARE( fields.at( 0 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.indexFromName( QStringLiteral( "field1" ) ), 0 );
QCOMPARE( fields.at( 1 ).name(), QStringLiteral( "field2" ) );
QCOMPARE( fields.at( 1 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.indexFromName( QStringLiteral( "field2" ) ), 1 );
QCOMPARE( fields.at( 2 ).name(), QStringLiteral( "field3" ) );
QCOMPARE( fields.at( 2 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.indexFromName( QStringLiteral( "field3" ) ), 2 );
}

void TestQgsFields::clear()
{
QgsFields original;
Expand Down Expand Up @@ -621,5 +648,151 @@ void TestQgsFields::constIterator()
QCOMPARE( it3 - it, 1 );
}

void TestQgsFields::appendList()
{
// test appending a list of fields
QgsFields fields;

QVERIFY( fields.append(
QList< QgsField >
{
QgsField( QStringLiteral( "field1" ), QMetaType::Type::QString ),
QgsField( QStringLiteral( "field2" ), QMetaType::Type::Int ),
QgsField( QStringLiteral( "field3" ), QMetaType::Type::Double ),
}
) );

QCOMPARE( fields.size(), 3 );
QCOMPARE( fields.at( 0 ).name(), QStringLiteral( "field1" ) );
QCOMPARE( fields.at( 0 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 0 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field1" ) ), 0 );
QCOMPARE( fields.at( 1 ).name(), QStringLiteral( "field2" ) );
QCOMPARE( fields.at( 1 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 1 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field2" ) ), 1 );
QCOMPARE( fields.at( 2 ).name(), QStringLiteral( "field3" ) );
QCOMPARE( fields.at( 2 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 2 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field3" ) ), 2 );

// should be rejected, duplicate field name
QVERIFY( !fields.append(
QList< QgsField >
{
QgsField( QStringLiteral( "field1" ), QMetaType::Type::QString )
}
) );

QCOMPARE( fields.size(), 3 );

QVERIFY( fields.append(
QList< QgsField >
{
QgsField( QStringLiteral( "field4" ), QMetaType::Type::QString ),
QgsField( QStringLiteral( "field5" ), QMetaType::Type::Int ),
QgsField( QStringLiteral( "field6" ), QMetaType::Type::Double ),
}, Qgis::FieldOrigin::Join
) );

QCOMPARE( fields.size(), 6 );
QCOMPARE( fields.at( 0 ).name(), QStringLiteral( "field1" ) );
QCOMPARE( fields.at( 0 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 0 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field1" ) ), 0 );
QCOMPARE( fields.at( 1 ).name(), QStringLiteral( "field2" ) );
QCOMPARE( fields.at( 1 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 1 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field2" ) ), 1 );
QCOMPARE( fields.at( 2 ).name(), QStringLiteral( "field3" ) );
QCOMPARE( fields.at( 2 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 2 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.indexFromName( QStringLiteral( "field3" ) ), 2 );
QCOMPARE( fields.at( 3 ).name(), QStringLiteral( "field4" ) );
QCOMPARE( fields.at( 3 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 3 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.indexFromName( QStringLiteral( "field4" ) ), 3 );
QCOMPARE( fields.at( 4 ).name(), QStringLiteral( "field5" ) );
QCOMPARE( fields.at( 4 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 4 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.indexFromName( QStringLiteral( "field5" ) ), 4 );
QCOMPARE( fields.at( 5 ).name(), QStringLiteral( "field6" ) );
QCOMPARE( fields.at( 5 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 5 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.indexFromName( QStringLiteral( "field6" ) ), 5 );
}

void TestQgsFields::appendQgsFields()
{
// test appending fields from QgsFields
QgsFields fields;

QgsFields fields2;
fields2.append( QgsField( QStringLiteral( "field1" ), QMetaType::Type::QString ), Qgis::FieldOrigin::Edit, 2 );
fields2.append( QgsField( QStringLiteral( "field2" ), QMetaType::Type::Int ), Qgis::FieldOrigin::Join, 4 );
fields2.append( QgsField( QStringLiteral( "field3" ), QMetaType::Type::Double ), Qgis::FieldOrigin::Provider, 6 );

QVERIFY( fields.append( fields2 ) );
QCOMPARE( fields.size(), 3 );
QCOMPARE( fields.at( 0 ).name(), QStringLiteral( "field1" ) );
QCOMPARE( fields.at( 0 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 0 ), Qgis::FieldOrigin::Edit );
QCOMPARE( fields.fieldOriginIndex( 0 ), 2 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field1" ) ), 0 );
QCOMPARE( fields.at( 1 ).name(), QStringLiteral( "field2" ) );
QCOMPARE( fields.at( 1 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 1 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.fieldOriginIndex( 1 ), 4 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field2" ) ), 1 );
QCOMPARE( fields.at( 2 ).name(), QStringLiteral( "field3" ) );
QCOMPARE( fields.at( 2 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 2 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.fieldOriginIndex( 2 ), 6 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field3" ) ), 2 );

// should be rejected, duplicate field name
QVERIFY( !fields.append( fields2 ) );
QCOMPARE( fields.size(), 3 );

QgsFields fields3;
fields3.append( QgsField( QStringLiteral( "field4" ), QMetaType::Type::QString ), Qgis::FieldOrigin::Expression, 3 );
fields3.append( QgsField( QStringLiteral( "field5" ), QMetaType::Type::Int ), Qgis::FieldOrigin::Join, 5 );
fields3.append( QgsField( QStringLiteral( "field6" ), QMetaType::Type::Double ), Qgis::FieldOrigin::Provider, 7 );

QVERIFY( fields.append( fields3 ) );

QCOMPARE( fields.size(), 6 );
QCOMPARE( fields.at( 0 ).name(), QStringLiteral( "field1" ) );
QCOMPARE( fields.at( 0 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 0 ), Qgis::FieldOrigin::Edit );
QCOMPARE( fields.fieldOriginIndex( 0 ), 2 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field1" ) ), 0 );
QCOMPARE( fields.at( 1 ).name(), QStringLiteral( "field2" ) );
QCOMPARE( fields.at( 1 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 1 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.fieldOriginIndex( 1 ), 4 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field2" ) ), 1 );
QCOMPARE( fields.at( 2 ).name(), QStringLiteral( "field3" ) );
QCOMPARE( fields.at( 2 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 2 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.fieldOriginIndex( 2 ), 6 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field3" ) ), 2 );
QCOMPARE( fields.at( 3 ).name(), QStringLiteral( "field4" ) );
QCOMPARE( fields.at( 3 ).type(), QMetaType::Type::QString );
QCOMPARE( fields.fieldOrigin( 3 ), Qgis::FieldOrigin::Expression );
QCOMPARE( fields.fieldOriginIndex( 3 ), 3 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field4" ) ), 3 );
QCOMPARE( fields.at( 4 ).name(), QStringLiteral( "field5" ) );
QCOMPARE( fields.at( 4 ).type(), QMetaType::Type::Int );
QCOMPARE( fields.fieldOrigin( 4 ), Qgis::FieldOrigin::Join );
QCOMPARE( fields.fieldOriginIndex( 4 ), 5 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field5" ) ), 4 );
QCOMPARE( fields.at( 5 ).name(), QStringLiteral( "field6" ) );
QCOMPARE( fields.at( 5 ).type(), QMetaType::Type::Double );
QCOMPARE( fields.fieldOrigin( 5 ), Qgis::FieldOrigin::Provider );
QCOMPARE( fields.fieldOriginIndex( 5 ), 7 );
QCOMPARE( fields.indexFromName( QStringLiteral( "field6" ) ), 5 );
}

QGSTEST_MAIN( TestQgsFields )
#include "testqgsfields.moc"

0 comments on commit 71e574d

Please sign in to comment.