Skip to content
Permalink
Browse files

New class QgsVectorLayerUtils

Contains static helper methods for working with vector layers.
Initially only contains a method to test whether a value
exists within a layer's attributes.
  • Loading branch information
nyalldawson committed Nov 2, 2016
1 parent 3e40f80 commit b7d0fd6f90b14dea8f6b1463436dc4f6c7a04380
@@ -148,6 +148,7 @@
%Include qgsvectorlayerimport.sip
%Include qgsvectorlayerjoinbuffer.sip
%Include qgsvectorlayerundocommand.sip
%Include qgsvectorlayerutils.sip
%Include qgsvectorsimplifymethod.sip

%Include qgscachedfeatureiterator.sip
@@ -0,0 +1,22 @@

/** \ingroup core
* \class QgsVectorLayerUtils
* \brief Contains utility methods for working with QgsVectorLayers.
*
* \note Added in version 3.0
*/
class QgsVectorLayerUtils
{
%TypeHeaderCode
#include <qgsvectorlayerutils.h>
%End
public:

/**
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
* with IDs within this list are ignored when testing for existance of the value.
*/
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );

};
@@ -230,6 +230,7 @@ SET(QGIS_CORE_SRCS
qgsvectorlayerlabelprovider.cpp
qgsvectorlayerrenderer.cpp
qgsvectorlayerundocommand.cpp
qgsvectorlayerutils.cpp
qgsvectorsimplifymethod.cpp
qgsvirtuallayerdefinition.cpp
qgsvirtuallayerdefinitionutils.cpp
@@ -722,6 +723,7 @@ SET(QGIS_CORE_HDRS
qgsvectorlayerlabelprovider.h
qgsvectorlayerrenderer.h
qgsvectorlayerundocommand.h
qgsvectorlayerutils.h
qgsvectorsimplifymethod.h
qgsmapthemecollection.h
qgsxmlutils.h
@@ -403,6 +403,7 @@ struct CORE_EXPORT QgsVectorJoinInfo
* Provider to display vector data in a GRASS GIS layer.
*
* TODO QGIS3: Remove virtual from non-inherited methods (like isModified)
* @see QgsVectorLayerUtils()
*/


@@ -0,0 +1,51 @@
/***************************************************************************
qgsvectorlayerutils.cpp
-----------------------
Date : October 2016
Copyright : (C) 2016 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 "qgsvectorlayerutils.h"

bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds )
{
if ( !layer )
return false;

if ( fieldIndex < 0 || fieldIndex >= layer->fields().count() )
return false;

QString fieldName = layer->fields().at( fieldIndex ).name();

// build up an optimised feature request
QgsFeatureRequest request;
request.setSubsetOfAttributes( QgsAttributeList() );
request.setFlags( QgsFeatureRequest::NoGeometry );

// at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
int limit = ignoreIds.size() + 1;
request.setLimit( limit );

request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
QgsExpression::quotedValue( value ) ) );

QgsFeature feat;
QgsFeatureIterator it = layer->getFeatures( request );
while ( it.nextFeature( feat ) )
{
if ( ignoreIds.contains( feat.id() ) )
continue;

return true;
}

return false;
}
@@ -0,0 +1,41 @@
/***************************************************************************
qgsvectorlayerutils.h
---------------------
Date : October 2016
Copyright : (C) 2016 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. *
* *
***************************************************************************/

#ifndef QGSVECTORLAYERUTILS_H
#define QGSVECTORLAYERUTILS_H

#include "qgsvectorlayer.h"

/** \ingroup core
* \class QgsVectorLayerUtils
* \brief Contains utility methods for working with QgsVectorLayers.
*
* \note Added in version 3.0
*/

class CORE_EXPORT QgsVectorLayerUtils
{
public:

/**
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
* with IDs within this list are ignored when testing for existance of the value.
*/
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );

};

#endif // QGSVECTORLAYERUTILS_H
@@ -111,6 +111,7 @@ ADD_PYTHON_TEST(PyQgsVectorColorRamp test_qgsvectorcolorramp.py)
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)
ADD_PYTHON_TEST(PyQgsVectorLayer test_qgsvectorlayer.py)
ADD_PYTHON_TEST(PyQgsVectorLayerEditBuffer test_qgsvectorlayereditbuffer.py)
ADD_PYTHON_TEST(PyQgsVectorLayerUtils test_qgsvectorlayerutils.py)
ADD_PYTHON_TEST(PyQgsZonalStatistics test_qgszonalstatistics.py)
ADD_PYTHON_TEST(PyQgsMapLayerRegistry test_qgsmaplayerregistry.py)
ADD_PYTHON_TEST(PyQgsVirtualLayerProvider test_provider_virtual.py)
@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsVectorLayerUtils.
.. 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__ = 'Nyall Dawson'
__date__ = '25/10/2016'
__copyright__ = 'Copyright 2016, 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.PyQt.QtCore import QVariant

from qgis.core import (QgsVectorLayer,
QgsVectorLayerUtils,
QgsField,
QgsFields,
QgsFeature
)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
start_app()


def createLayerWithOnePoint():
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
"addfeat", "memory")
pr = layer.dataProvider()
f = QgsFeature()
f.setAttributes(["test", 123])
assert pr.addFeatures([f])
assert layer.pendingFeatureCount() == 1
return layer


class TestQgsVectorLayerUtils(unittest.TestCase):

def test_value_exists(self):
layer = createLayerWithOnePoint()
# add some more features
f1 = QgsFeature(2)
f1.setAttributes(["test1", 124])
f2 = QgsFeature(3)
f2.setAttributes(["test2", 125])
f3 = QgsFeature(4)
f3.setAttributes(["test3", 126])
f4 = QgsFeature(5)
f4.setAttributes(["test4", 127])
layer.dataProvider().addFeatures([f1, f2, f3, f4])

self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test'))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1'))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test4'))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'not present!'))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 123))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 124))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 127))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 99))

# no layer
self.assertFalse(QgsVectorLayerUtils.valueExists(None, 1, 123))
# bad field indexes
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, -1, 'test'))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 100, 'test'))

# with ignore list
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5]))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [999999]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [2]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [99999, 2]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5, 2]))

self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [2, 4, 5]))
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [999999]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [3]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [99999, 3]))
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [2, 4, 5, 3]))


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

0 comments on commit b7d0fd6

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