Skip to content

Commit 09e0365

Browse files
authoredJun 5, 2017
Merge pull request #4680 from nyalldawson/unique_values
Move uniqueValues to QgsFeatureSource
2 parents 27850fb + 3388857 commit 09e0365

30 files changed

+195
-111
lines changed
 

‎doc/api_break.dox

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,7 @@ clause fragment which must be evaluated by the provider in order to calculate th
22752275
QGIS 3.0 defaultValue() only returns literal, constant defaultValues. A new method defaultValueClause
22762276
has been added which returns the SQL clause fragments which must be evaluated by the provider itself.
22772277
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
2278+
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
22782279

22792280

22802281
QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
@@ -2335,6 +2336,7 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
23352336
- addFeatures() no longer accepts a makeSelected boolean, and will not automatically select newly added features. If desired, features must be manually selected by calling selectByIds() after addFeatures()
23362337
- annotationForm() and setAnnotationForm() have been removed. Form path is stored in individual QgsFormAnnotation objects.
23372338
- setLayerTransparency, layerTransparency, and layerTransparencyChanged were removed. Use opacity, setOpacity and opacityChanged instead.
2339+
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
23382340

23392341

23402342
QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}

‎python/core/qgsfeaturesource.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ class QgsFeatureSource
6969
:rtype: long
7070
%End
7171

72+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
73+
%Docstring
74+
Returns the set of unique values contained within the specified ``fieldIndex`` from this source.
75+
If specified, the ``limit`` option can be used to limit the number of returned values.
76+
The base class implementation uses a non-optimised approach of looping through
77+
all features in the source.
78+
:rtype: set of QVariant
79+
%End
80+
7281
};
7382

7483

‎python/core/qgsvectordataprovider.sip

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,6 @@ Bitmask of all provider's editing capabilities
156156
:rtype: QVariant
157157
%End
158158

159-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
160-
%Docstring
161-
Return unique values of an attribute
162-
\param index the index of the attribute
163-
\param uniqueValues values reference to the list to fill
164-
\param limit maxmum number of the values to return
165-
166-
Default implementation simply iterates the features
167-
%End
168-
169159
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
170160
QgsFeedback *feedback = 0 ) const;
171161
%Docstring

‎python/core/qgsvectorlayer.sip

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,18 +1507,19 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
15071507
:rtype: QgsEditorWidgetSetup
15081508
%End
15091509

1510-
void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
1510+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
1511+
15111512
%Docstring
15121513
Calculates a list of unique values contained within an attribute in the layer. Note that
15131514
in some circumstances when unsaved changes are present for the layer then the returned list
15141515
may contain outdated values (for instance when the attribute value in a saved feature has
15151516
been changed inside the edit buffer then the previous saved value will be included in the
15161517
returned list).
1517-
\param index column index for attribute
1518-
\param uniqueValues out: result list
1518+
\param fieldIndex column index for attribute
15191519
\param limit maximum number of values to return (or -1 if unlimited)
15201520
.. seealso:: minimumValue()
15211521
.. seealso:: maximumValue()
1522+
:rtype: set of QVariant
15221523
%End
15231524

15241525
QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ SET(QGIS_CORE_SRCS
158158
qgsfeatureiterator.cpp
159159
qgsfeaturerequest.cpp
160160
qgsfeaturesink.cpp
161+
qgsfeaturesource.cpp
161162
qgsfeaturestore.cpp
162163
qgsfield.cpp
163164
qgsfieldconstraints.cpp

‎src/core/dxf/qgsdxfexport.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,7 @@ void QgsDxfExport::writeTables()
787787
}
788788
else
789789
{
790-
QList<QVariant> values;
791-
vl->uniqueValues( attrIdx, values );
790+
QSet<QVariant> values = vl->uniqueValues( attrIdx );
792791
Q_FOREACH ( const QVariant &v, values )
793792
{
794793
layerNames << dxfLayerName( v.toString() );

‎src/core/processing/qgsprocessingutils.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,8 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
274274
if ( !useSelection )
275275
{
276276
// not using selection, so use provider optimised version
277-
QList<QVariant> values;
278-
layer->uniqueValues( fieldIndex, values );
279-
return values;
277+
QSet<QVariant> values = layer->uniqueValues( fieldIndex );
278+
return values.toList();
280279
}
281280
else
282281
{

‎src/core/qgis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ template<class Object> inline QgsSignalBlocker<Object> whileBlocking( Object *ob
173173
}
174174

175175
//! Hash for QVariant
176-
uint qHash( const QVariant &variant );
176+
CORE_EXPORT uint qHash( const QVariant &variant );
177177

178178
//! Returns a string representation of a double
179179
//! \param a double value

‎src/core/qgsfeaturesource.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/***************************************************************************
2+
qgsfeaturesource.cpp
3+
-------------------
4+
begin : May 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsfeaturesource.h"
19+
#include "qgsfeaturerequest.h"
20+
#include "qgsfeatureiterator.h"
21+
22+
QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
23+
{
24+
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
25+
return QSet<QVariant>();
26+
27+
QgsFeatureRequest req;
28+
req.setFlags( QgsFeatureRequest::NoGeometry );
29+
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
30+
31+
QSet<QVariant> values;
32+
QgsFeatureIterator it = getFeatures( req );
33+
QgsFeature f;
34+
while ( it.nextFeature( f ) )
35+
{
36+
values.insert( f.attribute( fieldIndex ) );
37+
if ( limit > 0 && values.size() >= limit )
38+
return values;
39+
}
40+
return values;
41+
}
42+

‎src/core/qgsfeaturesource.h

100755100644
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
#include "qgis_core.h"
2222
#include "qgis.h"
23+
#include "qgsfeaturerequest.h"
2324

2425
class QgsFeatureIterator;
25-
class QgsFeatureRequest;
2626
class QgsCoordinateReferenceSystem;
2727
class QgsFields;
2828

@@ -79,6 +79,14 @@ class CORE_EXPORT QgsFeatureSource
7979
*/
8080
virtual long featureCount() const = 0;
8181

82+
/**
83+
* Returns the set of unique values contained within the specified \a fieldIndex from this source.
84+
* If specified, the \a limit option can be used to limit the number of returned values.
85+
* The base class implementation uses a non-optimised approach of looping through
86+
* all features in the source.
87+
*/
88+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
89+
8290
};
8391

8492
Q_DECLARE_METATYPE( QgsFeatureSource * )

‎src/core/qgsvectordataprovider.cpp

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -433,28 +433,6 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
433433
return mCacheMaxValues[index];
434434
}
435435

436-
void QgsVectorDataProvider::uniqueValues( int index, QList<QVariant> &values, int limit ) const
437-
{
438-
QgsFeature f;
439-
QgsAttributeList keys;
440-
keys.append( index );
441-
QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ).setFlags( QgsFeatureRequest::NoGeometry ) );
442-
443-
QSet<QString> set;
444-
values.clear();
445-
446-
while ( fi.nextFeature( f ) )
447-
{
448-
if ( !set.contains( f.attribute( index ).toString() ) )
449-
{
450-
values.append( f.attribute( index ) );
451-
set.insert( f.attribute( index ).toString() );
452-
}
453-
454-
if ( limit >= 0 && values.size() >= limit )
455-
break;
456-
}
457-
}
458436

459437
QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
460438
{

‎src/core/qgsvectordataprovider.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,6 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
186186
*/
187187
virtual QVariant maximumValue( int index ) const;
188188

189-
/**
190-
* Return unique values of an attribute
191-
* \param index the index of the attribute
192-
* \param uniqueValues values reference to the list to fill
193-
* \param limit maxmum number of the values to return
194-
*
195-
* Default implementation simply iterates the features
196-
*/
197-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
198-
199189
/**
200190
* Returns unique string values of an attribute which contain a specified subset string. Subset
201191
* matching is done in a case-insensitive manner.

‎src/core/qgsvectorlayer.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,23 +3010,23 @@ QString QgsVectorLayer::defaultValueExpression( int index ) const
30103010
return mFields.at( index ).defaultValueExpression();
30113011
}
30123012

3013-
void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
3013+
QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
30143014
{
3015-
uniqueValues.clear();
3015+
QSet<QVariant> uniqueValues;
30163016
if ( !mDataProvider )
30173017
{
3018-
return;
3018+
return uniqueValues;
30193019
}
30203020

30213021
QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
30223022
switch ( origin )
30233023
{
30243024
case QgsFields::OriginUnknown:
3025-
return;
3025+
return uniqueValues;
30263026

30273027
case QgsFields::OriginProvider: //a provider field
30283028
{
3029-
mDataProvider->uniqueValues( index, uniqueValues, limit );
3029+
uniqueValues = mDataProvider->uniqueValues( index, limit );
30303030

30313031
if ( mEditBuffer )
30323032
{
@@ -3070,7 +3070,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
30703070
}
30713071
}
30723072

3073-
return;
3073+
return uniqueValues;
30743074
}
30753075

30763076
case QgsFields::OriginEdit:
@@ -3080,8 +3080,8 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
30803080
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
30813081
mEditBuffer->mChangedAttributeValues.isEmpty() )
30823082
{
3083-
mDataProvider->uniqueValues( index, uniqueValues, limit );
3084-
return;
3083+
uniqueValues = mDataProvider->uniqueValues( index, limit );
3084+
return uniqueValues;
30853085
}
30863086
FALLTHROUGH;
30873087
//we need to go through each feature
@@ -3108,12 +3108,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
31083108
}
31093109
}
31103110

3111-
uniqueValues = val.values();
3112-
return;
3111+
return val.values().toSet();
31133112
}
31143113
}
31153114

31163115
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
3116+
return uniqueValues;
31173117
}
31183118

31193119
QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

‎src/core/qgsvectorlayer.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,13 +1423,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
14231423
* may contain outdated values (for instance when the attribute value in a saved feature has
14241424
* been changed inside the edit buffer then the previous saved value will be included in the
14251425
* returned list).
1426-
* \param index column index for attribute
1427-
* \param uniqueValues out: result list
1426+
* \param fieldIndex column index for attribute
14281427
* \param limit maximum number of values to return (or -1 if unlimited)
14291428
* \see minimumValue()
14301429
* \see maximumValue()
14311430
*/
1432-
void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
1431+
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;
14331432

14341433
/**
14351434
* Returns unique string values of an attribute which contain a specified subset string. Subset

‎src/gui/editorwidgets/qgsrelationreferencewidget.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,13 +466,12 @@ void QgsRelationReferenceWidget::init()
466466
{
467467
Q_FOREACH ( const QString &fieldName, mFilterFields )
468468
{
469-
QVariantList uniqueValues;
470469
int idx = mReferencedLayer->fields().lookupField( fieldName );
471470
QComboBox *cb = new QComboBox();
472471
cb->setProperty( "Field", fieldName );
473472
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
474473
mFilterComboBoxes << cb;
475-
mReferencedLayer->uniqueValues( idx, uniqueValues );
474+
QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
476475
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
477476
QVariant nullValue = QgsApplication::nullRepresentation();
478477
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );

‎src/gui/editorwidgets/qgsuniquevaluewidgetwrapper.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ void QgsUniqueValuesWidgetWrapper::initWidget( QWidget *editor )
6161

6262
QStringList sValues;
6363

64-
QList<QVariant> values;
65-
66-
layer()->uniqueValues( fieldIdx(), values );
64+
QSet< QVariant> values = layer()->uniqueValues( fieldIdx() );
6765

6866
Q_FOREACH ( const QVariant &v, values )
6967
{

‎src/gui/qgsexpressionbuilderwidget.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,8 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
336336
if ( fieldIndex < 0 )
337337
return;
338338

339-
QList<QVariant> values;
340339
QStringList strValues;
341-
mLayer->uniqueValues( fieldIndex, values, countLimit );
340+
QSet<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit );
342341
Q_FOREACH ( const QVariant &value, values )
343342
{
344343
QString strValue;

‎src/gui/qgsquerybuilder.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,29 +117,27 @@ void QgsQueryBuilder::fillValues( int idx, int limit )
117117
mModelValues->clear();
118118

119119
// determine the field type
120-
QList<QVariant> values;
121-
mLayer->uniqueValues( idx, values, limit );
120+
QSet<QVariant> values = mLayer->uniqueValues( idx, limit );
122121

123-
QgsSettings settings;
124122
QString nullValue = QgsApplication::nullRepresentation();
125123

126124
QgsDebugMsg( QString( "nullValue: %1" ).arg( nullValue ) );
127125

128-
for ( int i = 0; i < values.size(); i++ )
126+
Q_FOREACH ( const QVariant &var, values )
129127
{
130128
QString value;
131-
if ( values[i].isNull() )
129+
if ( var.isNull() )
132130
value = nullValue;
133-
else if ( values[i].type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
134-
value = values[i].toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
131+
else if ( var.type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
132+
value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
135133
else
136-
value = values[i].toString();
134+
value = var.toString();
137135

138136
QStandardItem *myItem = new QStandardItem( value );
139137
myItem->setEditable( false );
140-
myItem->setData( values[i], Qt::UserRole + 1 );
138+
myItem->setData( var, Qt::UserRole + 1 );
141139
mModelValues->insertRow( mModelValues->rowCount(), myItem );
142-
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( values[i].isNull() ).arg( values[i].isNull() ? nullValue : values[i].toString() ) );
140+
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( var.isNull() ).arg( var.isNull() ? nullValue : var.toString() ) );
143141
}
144142
}
145143

‎src/gui/symbology-ng/qgscategorizedsymbolrendererwidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ void QgsCategorizedSymbolRendererWidget::addCategories()
649649
}
650650
else
651651
{
652-
mLayer->uniqueValues( idx, unique_vals );
652+
unique_vals = mLayer->uniqueValues( idx ).toList();
653653
}
654654

655655
// ask to abort if too many classes

‎src/providers/mssql/qgsmssqlprovider.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,9 @@ QVariant QgsMssqlProvider::maximumValue( int index ) const
607607
}
608608

609609
// Returns the list of unique values of an attribute
610-
void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
610+
QSet<QVariant> QgsMssqlProvider::uniqueValues( int index, int limit ) const
611611
{
612-
uniqueValues.clear();
612+
QSet<QVariant> uniqueValues;
613613

614614
// get the field name
615615
QgsField fld = mAttributeFields.at( index );
@@ -643,9 +643,10 @@ void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, i
643643
// read all features
644644
while ( query.next() )
645645
{
646-
uniqueValues.append( query.value( 0 ) );
646+
uniqueValues.insert( query.value( 0 ) );
647647
}
648648
}
649+
return uniqueValues;
649650
}
650651

651652

‎src/providers/mssql/qgsmssqlprovider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider
6666
virtual QStringList subLayers() const override;
6767
virtual QVariant minimumValue( int index ) const override;
6868
virtual QVariant maximumValue( int index ) const override;
69-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
69+
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
7070
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
7171

7272
virtual QgsWkbTypes::Type wkbType() const override;

‎src/providers/ogr/qgsogrprovider.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ email : sherman at mrcc.com
3030
#include "qgsgeometry.h"
3131
#include "qgscoordinatereferencesystem.h"
3232
#include "qgsvectorlayerexporter.h"
33+
#include "qgis.h"
34+
3335

3436
#define CPL_SUPRESS_CPLUSPLUS //#spellok
3537
#include <gdal.h> // to collect version information
@@ -2949,17 +2951,17 @@ QgsCoordinateReferenceSystem QgsOgrProvider::crs() const
29492951
return srs;
29502952
}
29512953

2952-
void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
2954+
QSet<QVariant> QgsOgrProvider::uniqueValues( int index, int limit ) const
29532955
{
2954-
uniqueValues.clear();
2956+
QSet<QVariant> uniqueValues;
29552957

29562958
if ( !mValid || index < 0 || index >= mAttributeFields.count() )
2957-
return;
2959+
return uniqueValues;
29582960

29592961
QgsField fld = mAttributeFields.at( index );
29602962
if ( fld.name().isNull() )
29612963
{
2962-
return; //not a provider field
2964+
return uniqueValues; //not a provider field
29632965
}
29642966

29652967
QByteArray sql = "SELECT DISTINCT " + quotedIdentifier( textEncoding()->fromUnicode( fld.name() ) );
@@ -2977,7 +2979,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
29772979
if ( !l )
29782980
{
29792981
QgsDebugMsg( "Failed to execute SQL" );
2980-
return QgsVectorDataProvider::uniqueValues( index, uniqueValues, limit );
2982+
return QgsVectorDataProvider::uniqueValues( index, limit );
29812983
}
29822984

29832985
OGRFeatureH f;
@@ -2991,6 +2993,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
29912993
}
29922994

29932995
OGR_DS_ReleaseResultSet( ogrDataSource, l );
2996+
return uniqueValues;
29942997
}
29952998

29962999
QStringList QgsOgrProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

‎src/providers/ogr/qgsogrprovider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class QgsOgrProvider : public QgsVectorDataProvider
103103
bool isValid() const override;
104104
QVariant minimumValue( int index ) const override;
105105
QVariant maximumValue( int index ) const override;
106-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
106+
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
107107
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
108108
QgsFeedback *feedback = nullptr ) const override;
109109

‎src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,9 +1553,9 @@ QVariant QgsPostgresProvider::minimumValue( int index ) const
15531553
}
15541554

15551555
// Returns the list of unique values of an attribute
1556-
void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
1556+
QSet<QVariant> QgsPostgresProvider::uniqueValues( int index, int limit ) const
15571557
{
1558-
uniqueValues.clear();
1558+
QSet<QVariant> uniqueValues;
15591559

15601560
try
15611561
{
@@ -1583,12 +1583,13 @@ void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues
15831583
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
15841584
{
15851585
for ( int i = 0; i < res.PQntuples(); i++ )
1586-
uniqueValues.append( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
1586+
uniqueValues.insert( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
15871587
}
15881588
}
15891589
catch ( PGFieldNotFound )
15901590
{
15911591
}
1592+
return uniqueValues;
15921593
}
15931594

15941595
QStringList QgsPostgresProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

‎src/providers/postgres/qgspostgresprovider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
126126
QString dataComment() const override;
127127
QVariant minimumValue( int index ) const override;
128128
QVariant maximumValue( int index ) const override;
129-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
129+
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
130130
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
131131
QgsFeedback *feedback = nullptr ) const override;
132132
virtual void enumValues( int index, QStringList &enumList ) const override;

‎src/providers/spatialite/qgsspatialiteprovider.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3641,17 +3641,17 @@ QVariant QgsSpatiaLiteProvider::maximumValue( int index ) const
36413641
}
36423642

36433643
// Returns the list of unique values of an attribute
3644-
void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit ) const
3644+
QSet<QVariant> QgsSpatiaLiteProvider::uniqueValues( int index, int limit ) const
36453645
{
36463646
sqlite3_stmt *stmt = nullptr;
36473647
QString sql;
36483648

3649-
uniqueValues.clear();
3649+
QSet<QVariant> uniqueValues;
36503650

36513651
// get the field name
36523652
if ( index < 0 || index >= mAttributeFields.count() )
36533653
{
3654-
return; //invalid field
3654+
return uniqueValues; //invalid field
36553655
}
36563656
QgsField fld = mAttributeFields.at( index );
36573657

@@ -3674,7 +3674,7 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
36743674
{
36753675
// some error occurred
36763676
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
3677-
return;
3677+
return uniqueValues;
36783678
}
36793679

36803680
while ( 1 )
@@ -3694,30 +3694,30 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
36943694
switch ( sqlite3_column_type( stmt, 0 ) )
36953695
{
36963696
case SQLITE_INTEGER:
3697-
uniqueValues.append( QVariant( sqlite3_column_int( stmt, 0 ) ) );
3697+
uniqueValues.insert( QVariant( sqlite3_column_int( stmt, 0 ) ) );
36983698
break;
36993699
case SQLITE_FLOAT:
3700-
uniqueValues.append( QVariant( sqlite3_column_double( stmt, 0 ) ) );
3700+
uniqueValues.insert( QVariant( sqlite3_column_double( stmt, 0 ) ) );
37013701
break;
37023702
case SQLITE_TEXT:
3703-
uniqueValues.append( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
3703+
uniqueValues.insert( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
37043704
break;
37053705
default:
3706-
uniqueValues.append( QVariant( mAttributeFields.at( index ).type() ) );
3706+
uniqueValues.insert( QVariant( mAttributeFields.at( index ).type() ) );
37073707
break;
37083708
}
37093709
}
37103710
else
37113711
{
37123712
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
37133713
sqlite3_finalize( stmt );
3714-
return;
3714+
return uniqueValues;
37153715
}
37163716
}
37173717

37183718
sqlite3_finalize( stmt );
37193719

3720-
return;
3720+
return uniqueValues;
37213721
}
37223722

37233723
QStringList QgsSpatiaLiteProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

‎src/providers/spatialite/qgsspatialiteprovider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
9696
QgsFields fields() const override;
9797
QVariant minimumValue( int index ) const override;
9898
QVariant maximumValue( int index ) const override;
99-
virtual void uniqueValues( int index, QList < QVariant > &uniqueValues, int limit = -1 ) const override;
99+
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
100100
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
101101
QgsFeedback *feedback = nullptr ) const override;
102102

‎tests/src/core/testqgsvectorlayer.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,8 @@ void TestQgsVectorLayer::uniqueValues()
310310
QgsVectorLayer *vLayer = static_cast< QgsVectorLayer * >( mpPointsLayer );
311311

312312
//test with invalid field
313-
QList<QVariant> values;
314-
vLayer->uniqueValues( 1000, values );
315-
QCOMPARE( values.length(), 0 );
313+
QSet<QVariant> values = vLayer->uniqueValues( 1000 );
314+
QCOMPARE( values.count(), 0 );
316315
}
317316

318317
void TestQgsVectorLayer::minimumValue()

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ADD_PYTHON_TEST(PyQgsExpressionLineEdit test_qgsexpressionlineedit.py)
5151
ADD_PYTHON_TEST(PyQgsExtentGroupBox test_qgsextentgroupbox.py)
5252
ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
5353
ADD_PYTHON_TEST(PyQgsFeatureSink test_qgsfeaturesink.py)
54+
ADD_PYTHON_TEST(PyQgsFeatureSource test_qgsfeaturesource.py)
5455
ADD_PYTHON_TEST(PyQgsFieldFormattersTest test_qgsfieldformatters.py)
5556
ADD_PYTHON_TEST(PyQgsFillSymbolLayers test_qgsfillsymbollayers.py)
5657
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsFeatureSource.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = '(C) 2017 by Nyall Dawson'
10+
__date__ = '26/04/2017'
11+
__copyright__ = 'Copyright 2017, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
import qgis # NOQA
15+
16+
import os
17+
18+
from qgis.core import (QgsVectorLayer,
19+
QgsFeature,
20+
QgsGeometry,
21+
QgsPointXY)
22+
from qgis.PyQt.QtCore import QVariant
23+
from qgis.testing import start_app, unittest
24+
start_app()
25+
26+
27+
def createLayerWithFivePoints():
28+
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
29+
"addfeat", "memory")
30+
pr = layer.dataProvider()
31+
f = QgsFeature()
32+
f.setAttributes(["test", 1])
33+
f.setGeometry(QgsGeometry.fromPoint(QgsPointXY(100, 200)))
34+
f2 = QgsFeature()
35+
f2.setAttributes(["test2", 3])
36+
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(200, 200)))
37+
f3 = QgsFeature()
38+
f3.setAttributes(["test2", 3])
39+
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(300, 200)))
40+
f4 = QgsFeature()
41+
f4.setAttributes(["test3", 3])
42+
f4.setGeometry(QgsGeometry.fromPoint(QgsPointXY(400, 300)))
43+
f5 = QgsFeature()
44+
f5.setAttributes(["test4", 4])
45+
f5.setGeometry(QgsGeometry.fromPoint(QgsPointXY(0, 0)))
46+
assert pr.addFeatures([f, f2, f3, f4, f5])
47+
assert layer.featureCount() == 5
48+
return layer
49+
50+
51+
class TestQgsFeatureSource(unittest.TestCase):
52+
53+
def testUniqueValues(self):
54+
"""
55+
Test retrieving unique values using base class method
56+
"""
57+
58+
# memory provider uses base class method
59+
layer = createLayerWithFivePoints()
60+
self.assertFalse(layer.dataProvider().uniqueValues(-1))
61+
self.assertFalse(layer.dataProvider().uniqueValues(100))
62+
self.assertEqual(layer.dataProvider().uniqueValues(0), {'test', 'test2', 'test3', 'test4'})
63+
self.assertEqual(layer.dataProvider().uniqueValues(1), {1, 3, 3, 4})
64+
65+
66+
if __name__ == '__main__':
67+
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.