Move uniqueValues to QgsFeatureSource

Also change signature of QgsVectorLayer/QgsVectorDataProvider
uniqueValues method to match (and improve API)
This commit is contained in:
Nyall Dawson 2017-06-05 14:41:48 +10:00
parent f69d1c2065
commit 3388857526
30 changed files with 195 additions and 111 deletions

View File

@ -2275,6 +2275,7 @@ clause fragment which must be evaluated by the provider in order to calculate th
QGIS 3.0 defaultValue() only returns literal, constant defaultValues. A new method defaultValueClause
has been added which returns the SQL clause fragments which must be evaluated by the provider itself.
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
@ -2335,6 +2336,7 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
- 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()
- annotationForm() and setAnnotationForm() have been removed. Form path is stored in individual QgsFormAnnotation objects.
- setLayerTransparency, layerTransparency, and layerTransparencyChanged were removed. Use opacity, setOpacity and opacityChanged instead.
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}

View File

@ -69,6 +69,15 @@ class QgsFeatureSource
:rtype: long
%End
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
%Docstring
Returns the set of unique values contained within the specified ``fieldIndex`` from this source.
If specified, the ``limit`` option can be used to limit the number of returned values.
The base class implementation uses a non-optimised approach of looping through
all features in the source.
:rtype: set of QVariant
%End
};

View File

@ -156,16 +156,6 @@ Bitmask of all provider's editing capabilities
:rtype: QVariant
%End
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
%Docstring
Return unique values of an attribute
\param index the index of the attribute
\param uniqueValues values reference to the list to fill
\param limit maxmum number of the values to return
Default implementation simply iterates the features
%End
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
QgsFeedback *feedback = 0 ) const;
%Docstring

View File

@ -1507,18 +1507,19 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
:rtype: QgsEditorWidgetSetup
%End
void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
%Docstring
Calculates a list of unique values contained within an attribute in the layer. Note that
in some circumstances when unsaved changes are present for the layer then the returned list
may contain outdated values (for instance when the attribute value in a saved feature has
been changed inside the edit buffer then the previous saved value will be included in the
returned list).
\param index column index for attribute
\param uniqueValues out: result list
\param fieldIndex column index for attribute
\param limit maximum number of values to return (or -1 if unlimited)
.. seealso:: minimumValue()
.. seealso:: maximumValue()
:rtype: set of QVariant
%End
QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,

View File

@ -158,6 +158,7 @@ SET(QGIS_CORE_SRCS
qgsfeatureiterator.cpp
qgsfeaturerequest.cpp
qgsfeaturesink.cpp
qgsfeaturesource.cpp
qgsfeaturestore.cpp
qgsfield.cpp
qgsfieldconstraints.cpp

View File

@ -787,8 +787,7 @@ void QgsDxfExport::writeTables()
}
else
{
QList<QVariant> values;
vl->uniqueValues( attrIdx, values );
QSet<QVariant> values = vl->uniqueValues( attrIdx );
Q_FOREACH ( const QVariant &v, values )
{
layerNames << dxfLayerName( v.toString() );

View File

@ -274,9 +274,8 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
if ( !useSelection )
{
// not using selection, so use provider optimised version
QList<QVariant> values;
layer->uniqueValues( fieldIndex, values );
return values;
QSet<QVariant> values = layer->uniqueValues( fieldIndex );
return values.toList();
}
else
{

View File

@ -173,7 +173,7 @@ template<class Object> inline QgsSignalBlocker<Object> whileBlocking( Object *ob
}
//! Hash for QVariant
uint qHash( const QVariant &variant );
CORE_EXPORT uint qHash( const QVariant &variant );
//! Returns a string representation of a double
//! \param a double value

View File

@ -0,0 +1,42 @@
/***************************************************************************
qgsfeaturesource.cpp
-------------------
begin : May 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsfeaturesource.h"
#include "qgsfeaturerequest.h"
#include "qgsfeatureiterator.h"
QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
{
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
return QSet<QVariant>();
QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
QSet<QVariant> values;
QgsFeatureIterator it = getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
values.insert( f.attribute( fieldIndex ) );
if ( limit > 0 && values.size() >= limit )
return values;
}
return values;
}

10
src/core/qgsfeaturesource.h Executable file → Normal file
View File

@ -20,9 +20,9 @@
#include "qgis_core.h"
#include "qgis.h"
#include "qgsfeaturerequest.h"
class QgsFeatureIterator;
class QgsFeatureRequest;
class QgsCoordinateReferenceSystem;
class QgsFields;
@ -79,6 +79,14 @@ class CORE_EXPORT QgsFeatureSource
*/
virtual long featureCount() const = 0;
/**
* Returns the set of unique values contained within the specified \a fieldIndex from this source.
* If specified, the \a limit option can be used to limit the number of returned values.
* The base class implementation uses a non-optimised approach of looping through
* all features in the source.
*/
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
};
Q_DECLARE_METATYPE( QgsFeatureSource * )

View File

@ -433,28 +433,6 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
return mCacheMaxValues[index];
}
void QgsVectorDataProvider::uniqueValues( int index, QList<QVariant> &values, int limit ) const
{
QgsFeature f;
QgsAttributeList keys;
keys.append( index );
QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ).setFlags( QgsFeatureRequest::NoGeometry ) );
QSet<QString> set;
values.clear();
while ( fi.nextFeature( f ) )
{
if ( !set.contains( f.attribute( index ).toString() ) )
{
values.append( f.attribute( index ) );
set.insert( f.attribute( index ).toString() );
}
if ( limit >= 0 && values.size() >= limit )
break;
}
}
QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
{

View File

@ -186,16 +186,6 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual QVariant maximumValue( int index ) const;
/**
* Return unique values of an attribute
* \param index the index of the attribute
* \param uniqueValues values reference to the list to fill
* \param limit maxmum number of the values to return
*
* Default implementation simply iterates the features
*/
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
/**
* Returns unique string values of an attribute which contain a specified subset string. Subset
* matching is done in a case-insensitive manner.

View File

@ -3010,23 +3010,23 @@ QString QgsVectorLayer::defaultValueExpression( int index ) const
return mFields.at( index ).defaultValueExpression();
}
void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
{
uniqueValues.clear();
QSet<QVariant> uniqueValues;
if ( !mDataProvider )
{
return;
return uniqueValues;
}
QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
switch ( origin )
{
case QgsFields::OriginUnknown:
return;
return uniqueValues;
case QgsFields::OriginProvider: //a provider field
{
mDataProvider->uniqueValues( index, uniqueValues, limit );
uniqueValues = mDataProvider->uniqueValues( index, limit );
if ( mEditBuffer )
{
@ -3070,7 +3070,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
}
}
return;
return uniqueValues;
}
case QgsFields::OriginEdit:
@ -3080,8 +3080,8 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
mEditBuffer->mChangedAttributeValues.isEmpty() )
{
mDataProvider->uniqueValues( index, uniqueValues, limit );
return;
uniqueValues = mDataProvider->uniqueValues( index, limit );
return uniqueValues;
}
FALLTHROUGH;
//we need to go through each feature
@ -3108,12 +3108,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
}
}
uniqueValues = val.values();
return;
return val.values().toSet();
}
}
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
return uniqueValues;
}
QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

View File

@ -1423,13 +1423,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* may contain outdated values (for instance when the attribute value in a saved feature has
* been changed inside the edit buffer then the previous saved value will be included in the
* returned list).
* \param index column index for attribute
* \param uniqueValues out: result list
* \param fieldIndex column index for attribute
* \param limit maximum number of values to return (or -1 if unlimited)
* \see minimumValue()
* \see maximumValue()
*/
void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;
/**
* Returns unique string values of an attribute which contain a specified subset string. Subset

View File

@ -466,13 +466,12 @@ void QgsRelationReferenceWidget::init()
{
Q_FOREACH ( const QString &fieldName, mFilterFields )
{
QVariantList uniqueValues;
int idx = mReferencedLayer->fields().lookupField( fieldName );
QComboBox *cb = new QComboBox();
cb->setProperty( "Field", fieldName );
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
mFilterComboBoxes << cb;
mReferencedLayer->uniqueValues( idx, uniqueValues );
QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
QVariant nullValue = QgsApplication::nullRepresentation();
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );

View File

@ -61,9 +61,7 @@ void QgsUniqueValuesWidgetWrapper::initWidget( QWidget *editor )
QStringList sValues;
QList<QVariant> values;
layer()->uniqueValues( fieldIdx(), values );
QSet< QVariant> values = layer()->uniqueValues( fieldIdx() );
Q_FOREACH ( const QVariant &v, values )
{

View File

@ -336,9 +336,8 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
if ( fieldIndex < 0 )
return;
QList<QVariant> values;
QStringList strValues;
mLayer->uniqueValues( fieldIndex, values, countLimit );
QSet<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit );
Q_FOREACH ( const QVariant &value, values )
{
QString strValue;

View File

@ -117,29 +117,27 @@ void QgsQueryBuilder::fillValues( int idx, int limit )
mModelValues->clear();
// determine the field type
QList<QVariant> values;
mLayer->uniqueValues( idx, values, limit );
QSet<QVariant> values = mLayer->uniqueValues( idx, limit );
QgsSettings settings;
QString nullValue = QgsApplication::nullRepresentation();
QgsDebugMsg( QString( "nullValue: %1" ).arg( nullValue ) );
for ( int i = 0; i < values.size(); i++ )
Q_FOREACH ( const QVariant &var, values )
{
QString value;
if ( values[i].isNull() )
if ( var.isNull() )
value = nullValue;
else if ( values[i].type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
value = values[i].toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
else if ( var.type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
else
value = values[i].toString();
value = var.toString();
QStandardItem *myItem = new QStandardItem( value );
myItem->setEditable( false );
myItem->setData( values[i], Qt::UserRole + 1 );
myItem->setData( var, Qt::UserRole + 1 );
mModelValues->insertRow( mModelValues->rowCount(), myItem );
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( values[i].isNull() ).arg( values[i].isNull() ? nullValue : values[i].toString() ) );
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( var.isNull() ).arg( var.isNull() ? nullValue : var.toString() ) );
}
}

View File

@ -649,7 +649,7 @@ void QgsCategorizedSymbolRendererWidget::addCategories()
}
else
{
mLayer->uniqueValues( idx, unique_vals );
unique_vals = mLayer->uniqueValues( idx ).toList();
}
// ask to abort if too many classes

View File

@ -607,9 +607,9 @@ QVariant QgsMssqlProvider::maximumValue( int index ) const
}
// Returns the list of unique values of an attribute
void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
QSet<QVariant> QgsMssqlProvider::uniqueValues( int index, int limit ) const
{
uniqueValues.clear();
QSet<QVariant> uniqueValues;
// get the field name
QgsField fld = mAttributeFields.at( index );
@ -643,9 +643,10 @@ void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, i
// read all features
while ( query.next() )
{
uniqueValues.append( query.value( 0 ) );
uniqueValues.insert( query.value( 0 ) );
}
}
return uniqueValues;
}

View File

@ -66,7 +66,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider
virtual QStringList subLayers() const override;
virtual QVariant minimumValue( int index ) const override;
virtual QVariant maximumValue( int index ) const override;
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
virtual QgsWkbTypes::Type wkbType() const override;

View File

@ -30,6 +30,8 @@ email : sherman at mrcc.com
#include "qgsgeometry.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectorlayerexporter.h"
#include "qgis.h"
#define CPL_SUPRESS_CPLUSPLUS //#spellok
#include <gdal.h> // to collect version information
@ -2949,17 +2951,17 @@ QgsCoordinateReferenceSystem QgsOgrProvider::crs() const
return srs;
}
void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
QSet<QVariant> QgsOgrProvider::uniqueValues( int index, int limit ) const
{
uniqueValues.clear();
QSet<QVariant> uniqueValues;
if ( !mValid || index < 0 || index >= mAttributeFields.count() )
return;
return uniqueValues;
QgsField fld = mAttributeFields.at( index );
if ( fld.name().isNull() )
{
return; //not a provider field
return uniqueValues; //not a provider field
}
QByteArray sql = "SELECT DISTINCT " + quotedIdentifier( textEncoding()->fromUnicode( fld.name() ) );
@ -2977,7 +2979,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
if ( !l )
{
QgsDebugMsg( "Failed to execute SQL" );
return QgsVectorDataProvider::uniqueValues( index, uniqueValues, limit );
return QgsVectorDataProvider::uniqueValues( index, limit );
}
OGRFeatureH f;
@ -2991,6 +2993,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
}
OGR_DS_ReleaseResultSet( ogrDataSource, l );
return uniqueValues;
}
QStringList QgsOgrProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

View File

@ -103,7 +103,7 @@ class QgsOgrProvider : public QgsVectorDataProvider
bool isValid() const override;
QVariant minimumValue( int index ) const override;
QVariant maximumValue( int index ) const override;
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
QgsFeedback *feedback = nullptr ) const override;

View File

@ -1553,9 +1553,9 @@ QVariant QgsPostgresProvider::minimumValue( int index ) const
}
// Returns the list of unique values of an attribute
void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
QSet<QVariant> QgsPostgresProvider::uniqueValues( int index, int limit ) const
{
uniqueValues.clear();
QSet<QVariant> uniqueValues;
try
{
@ -1583,12 +1583,13 @@ void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
{
for ( int i = 0; i < res.PQntuples(); i++ )
uniqueValues.append( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
uniqueValues.insert( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
}
}
catch ( PGFieldNotFound )
{
}
return uniqueValues;
}
QStringList QgsPostgresProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

View File

@ -126,7 +126,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
QString dataComment() const override;
QVariant minimumValue( int index ) const override;
QVariant maximumValue( int index ) const override;
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
QgsFeedback *feedback = nullptr ) const override;
virtual void enumValues( int index, QStringList &enumList ) const override;

View File

@ -3641,17 +3641,17 @@ QVariant QgsSpatiaLiteProvider::maximumValue( int index ) const
}
// Returns the list of unique values of an attribute
void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit ) const
QSet<QVariant> QgsSpatiaLiteProvider::uniqueValues( int index, int limit ) const
{
sqlite3_stmt *stmt = nullptr;
QString sql;
uniqueValues.clear();
QSet<QVariant> uniqueValues;
// get the field name
if ( index < 0 || index >= mAttributeFields.count() )
{
return; //invalid field
return uniqueValues; //invalid field
}
QgsField fld = mAttributeFields.at( index );
@ -3674,7 +3674,7 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
{
// some error occurred
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
return;
return uniqueValues;
}
while ( 1 )
@ -3694,16 +3694,16 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
switch ( sqlite3_column_type( stmt, 0 ) )
{
case SQLITE_INTEGER:
uniqueValues.append( QVariant( sqlite3_column_int( stmt, 0 ) ) );
uniqueValues.insert( QVariant( sqlite3_column_int( stmt, 0 ) ) );
break;
case SQLITE_FLOAT:
uniqueValues.append( QVariant( sqlite3_column_double( stmt, 0 ) ) );
uniqueValues.insert( QVariant( sqlite3_column_double( stmt, 0 ) ) );
break;
case SQLITE_TEXT:
uniqueValues.append( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
uniqueValues.insert( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
break;
default:
uniqueValues.append( QVariant( mAttributeFields.at( index ).type() ) );
uniqueValues.insert( QVariant( mAttributeFields.at( index ).type() ) );
break;
}
}
@ -3711,13 +3711,13 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
{
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
sqlite3_finalize( stmt );
return;
return uniqueValues;
}
}
sqlite3_finalize( stmt );
return;
return uniqueValues;
}
QStringList QgsSpatiaLiteProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

View File

@ -96,7 +96,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
QgsFields fields() const override;
QVariant minimumValue( int index ) const override;
QVariant maximumValue( int index ) const override;
virtual void uniqueValues( int index, QList < QVariant > &uniqueValues, int limit = -1 ) const override;
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
QgsFeedback *feedback = nullptr ) const override;

View File

@ -310,9 +310,8 @@ void TestQgsVectorLayer::uniqueValues()
QgsVectorLayer *vLayer = static_cast< QgsVectorLayer * >( mpPointsLayer );
//test with invalid field
QList<QVariant> values;
vLayer->uniqueValues( 1000, values );
QCOMPARE( values.length(), 0 );
QSet<QVariant> values = vLayer->uniqueValues( 1000 );
QCOMPARE( values.count(), 0 );
}
void TestQgsVectorLayer::minimumValue()

View File

@ -51,6 +51,7 @@ ADD_PYTHON_TEST(PyQgsExpressionLineEdit test_qgsexpressionlineedit.py)
ADD_PYTHON_TEST(PyQgsExtentGroupBox test_qgsextentgroupbox.py)
ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
ADD_PYTHON_TEST(PyQgsFeatureSink test_qgsfeaturesink.py)
ADD_PYTHON_TEST(PyQgsFeatureSource test_qgsfeaturesource.py)
ADD_PYTHON_TEST(PyQgsFieldFormattersTest test_qgsfieldformatters.py)
ADD_PYTHON_TEST(PyQgsFillSymbolLayers test_qgsfillsymbollayers.py)
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)

View File

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsFeatureSource.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = '(C) 2017 by Nyall Dawson'
__date__ = '26/04/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
import os
from qgis.core import (QgsVectorLayer,
QgsFeature,
QgsGeometry,
QgsPointXY)
from qgis.PyQt.QtCore import QVariant
from qgis.testing import start_app, unittest
start_app()
def createLayerWithFivePoints():
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
"addfeat", "memory")
pr = layer.dataProvider()
f = QgsFeature()
f.setAttributes(["test", 1])
f.setGeometry(QgsGeometry.fromPoint(QgsPointXY(100, 200)))
f2 = QgsFeature()
f2.setAttributes(["test2", 3])
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(200, 200)))
f3 = QgsFeature()
f3.setAttributes(["test2", 3])
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(300, 200)))
f4 = QgsFeature()
f4.setAttributes(["test3", 3])
f4.setGeometry(QgsGeometry.fromPoint(QgsPointXY(400, 300)))
f5 = QgsFeature()
f5.setAttributes(["test4", 4])
f5.setGeometry(QgsGeometry.fromPoint(QgsPointXY(0, 0)))
assert pr.addFeatures([f, f2, f3, f4, f5])
assert layer.featureCount() == 5
return layer
class TestQgsFeatureSource(unittest.TestCase):
def testUniqueValues(self):
"""
Test retrieving unique values using base class method
"""
# memory provider uses base class method
layer = createLayerWithFivePoints()
self.assertFalse(layer.dataProvider().uniqueValues(-1))
self.assertFalse(layer.dataProvider().uniqueValues(100))
self.assertEqual(layer.dataProvider().uniqueValues(0), {'test', 'test2', 'test3', 'test4'})
self.assertEqual(layer.dataProvider().uniqueValues(1), {1, 3, 3, 4})
if __name__ == '__main__':
unittest.main()