QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsalgorithmexplodehstore.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmexplodehstore.h
3  ---------------------
4  begin : September 2018
5  copyright : (C) 2018 by Etienne Trimaille
6  email : etienne dot trimaille 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 "qgis.h"
20 #include "qgshstoreutils.h"
21 #include "qgsprocessingutils.h"
22 
24 
25 QString QgsExplodeHstoreAlgorithm::name() const
26 {
27  return QStringLiteral( "explodehstorefield" );
28 }
29 
30 QString QgsExplodeHstoreAlgorithm::displayName() const
31 {
32  return QObject::tr( "Explode HStore Field" );
33 }
34 
35 QStringList QgsExplodeHstoreAlgorithm::tags() const
36 {
37  return QObject::tr( "field,explode,hstore,osm,openstreetmap" ).split( ',' );
38 }
39 
40 QString QgsExplodeHstoreAlgorithm::group() const
41 {
42  return QObject::tr( "Vector table" );
43 }
44 
45 QString QgsExplodeHstoreAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectortable" );
48 }
49 
50 QString QgsExplodeHstoreAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "This algorithm creates a copy of the input layer and adds a new field for every unique key in the HStore field.\n"
53  "The expected field list is an optional comma separated list. By default, all unique keys are added. If this list is specified, only these fields are added and the HStore field is updated." );
54 }
55 
56 QgsProcessingAlgorithm *QgsExplodeHstoreAlgorithm::createInstance() const
57 {
58  return new QgsExplodeHstoreAlgorithm();
59 }
60 
61 void QgsExplodeHstoreAlgorithm::initAlgorithm( const QVariantMap & )
62 {
63  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
64  QObject::tr( "Input layer" ) ) );
65  addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ),
66  QObject::tr( "HStore field" ), QVariant(), QStringLiteral( "INPUT" ) ) );
67  addParameter( new QgsProcessingParameterString( QStringLiteral( "EXPECTED_FIELDS" ), QObject::tr( "Expected list of fields separated by a comma" ), QVariant(), false, true ) );
68  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Exploded" ) ) );
69 }
70 
71 QVariantMap QgsExplodeHstoreAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
72 {
73  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
74  if ( !source )
75  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
76  int attrSourceCount = source->fields().count();
77 
78  QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
79  int fieldIndex = source->fields().lookupField( fieldName );
80  if ( fieldIndex < 0 )
81  throw QgsProcessingException( QObject::tr( "Invalid HStore field" ) );
82 
83  QStringList expectedFields;
84  QString fieldList = parameterAsString( parameters, QStringLiteral( "EXPECTED_FIELDS" ), context );
85  if ( ! fieldList.trimmed().isEmpty() )
86  {
87  expectedFields = fieldList.split( ',' );
88  }
89 
90  QList<QString> fieldsToAdd;
91  QHash<QgsFeatureId, QVariantMap> hstoreFeatures;
92  QList<QgsFeature> features;
93 
94  double step = source->featureCount() > 0 ? 50.0 / source->featureCount() : 1;
95  int i = 0;
96  QgsFeatureIterator featIterator = source->getFeatures( );
97  QgsFeature feat;
98  while ( featIterator.nextFeature( feat ) )
99  {
100  i++;
101  if ( feedback->isCanceled() )
102  break;
103 
104  double progress = i * step;
105  if ( progress >= 50 )
106  feedback->setProgress( 50.0 );
107  else
108  feedback->setProgress( progress );
109 
110  QVariantMap currentHStore = QgsHstoreUtils::parse( feat.attribute( fieldName ).toString() );
111  for ( const QString &key : currentHStore.keys() )
112  {
113  if ( expectedFields.isEmpty() && ! fieldsToAdd.contains( key ) )
114  fieldsToAdd.insert( 0, key );
115  }
116  hstoreFeatures.insert( feat.id(), currentHStore );
117  features.append( feat );
118  }
119 
120  if ( ! expectedFields.isEmpty() )
121  {
122  fieldsToAdd = expectedFields;
123  }
124 
125  QgsFields hstoreFields;
126  for ( const QString &fieldName : fieldsToAdd )
127  {
128  hstoreFields.append( QgsField( fieldName, QVariant::String ) );
129  }
130 
131  QgsFields outFields = QgsProcessingUtils::combineFields( source->fields(), hstoreFields );
132 
133  QString sinkId;
134  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, sinkId, outFields, source->wkbType(), source->sourceCrs() ) );
135  if ( !sink )
136  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
137 
138  QList<int> fieldIndicesInput = QgsProcessingUtils::fieldNamesToIndices( QStringList(), source->fields() );
139  int attrCount = attrSourceCount + fieldsToAdd.count();
140  QgsFeature outFeature;
141  step = !features.empty() ? 50.0 / features.count() : 1;
142  i = 0;
143  for ( const QgsFeature &feat : std::as_const( features ) )
144  {
145  i++;
146  if ( feedback->isCanceled() )
147  break;
148 
149  feedback->setProgress( i * step + 50.0 );
150 
151  QgsAttributes outAttributes( attrCount );
152 
153  const QgsAttributes attrs( feat.attributes() );
154  for ( int i = 0; i < fieldIndicesInput.count(); ++i )
155  outAttributes[i] = attrs[fieldIndicesInput[i]];
156 
157  QVariantMap currentHStore = hstoreFeatures.take( feat.id() );
158 
159  QString current;
160  for ( int i = 0; i < fieldsToAdd.count(); ++i )
161  {
162  current = fieldsToAdd.at( i );
163  if ( currentHStore.contains( current ) )
164  {
165  outAttributes[attrSourceCount + i] = currentHStore.take( current );
166  }
167  }
168 
169  if ( ! expectedFields.isEmpty() )
170  {
171  outAttributes[fieldIndex] = QgsHstoreUtils::build( currentHStore );
172  }
173 
174  outFeature.setGeometry( QgsGeometry( feat.geometry() ) );
175  outFeature.setAttributes( outAttributes );
176  if ( !sink->addFeature( outFeature, QgsFeatureSink::FastInsert ) )
177  throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
178  }
179 
180  QVariantMap outputs;
181  outputs.insert( QStringLiteral( "OUTPUT" ), sinkId );
182  return outputs;
183 }
184 
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:76
QgsHstoreUtils::build
CORE_EXPORT QString build(const QVariantMap &map)
Build a hstore-formatted string from a QVariantMap.
Definition: qgshstoreutils.cpp:88
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsHstoreUtils::parse
CORE_EXPORT QVariantMap parse(const QString &string)
Returns a QVariantMap object containing the key and values from a hstore-formatted string.
Definition: qgshstoreutils.cpp:20
qgis.h
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:3057
QgsFields::append
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
QgsProcessingUtils::combineFields
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
Definition: qgsprocessingutils.cpp:1238
QgsProcessingParameterFeatureSink
A feature sink output for processing algorithms.
Definition: qgsprocessingparameters.h:3219
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
qgsalgorithmexplodehstore.h
qgshstoreutils.h
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingUtils::fieldNamesToIndices
static QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
Definition: qgsprocessingutils.cpp:1274
QgsProcessingParameterString
A string parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2647
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:327
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:69
qgsprocessingutils.h
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsAttributes
A vector of attributes. Mostly equal to QVector<QVariant>.
Definition: qgsattributes.h:57
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsProcessingParameterField
A vector layer or feature source field parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2940
QgsFeatureSink::FastInsert
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Definition: qgsfeaturesink.h:70
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50