QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsaggregatecalculator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsaggregatecalculator.cpp
3  --------------------------
4  begin : May 2016
5  copyright : (C) 2016 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 "qgsaggregatecalculator.h"
19 #include "qgsexpressionutils.h"
20 #include "qgsfeature.h"
21 #include "qgsfeaturerequest.h"
22 #include "qgsfeatureiterator.h"
23 #include "qgsgeometry.h"
24 #include "qgsvectorlayer.h"
25 
26 
27 
29  : mLayer( layer )
30 {
31 
32 }
33 
35 {
36  return mLayer;
37 }
38 
40 {
41  mFilterExpression = parameters.filter;
42  mDelimiter = parameters.delimiter;
43  mOrderBy = parameters.orderBy;
44 }
45 
47 {
48  mFidsSet = true;
49  mFidsFilter = fids;
50 }
51 
53  const QString &fieldOrExpression, QgsExpressionContext *context, bool *ok, QgsFeedback *feedback ) const
54 {
55  mLastError.clear();
56  if ( ok )
57  *ok = false;
58 
60 
61  if ( !mLayer )
62  return QVariant();
63 
64  QgsExpressionContext defaultContext = mLayer->createExpressionContext();
65  context = context ? context : &defaultContext;
66 
67  std::unique_ptr<QgsExpression> expression;
68 
69  const int attrNum = QgsExpression::expressionToLayerFieldIndex( fieldOrExpression, mLayer );
70  if ( attrNum == -1 )
71  {
72  Q_ASSERT( context );
73  context->setFields( mLayer->fields() );
74  // try to use expression
75  expression.reset( new QgsExpression( fieldOrExpression ) );
76 
77  if ( expression->hasParserError() || !expression->prepare( context ) )
78  {
79  mLastError = !expression->parserErrorString().isEmpty() ? expression->parserErrorString() : expression->evalErrorString();
80  return QVariant();
81  }
82  }
83 
84  QSet<QString> lst;
85  if ( !expression )
86  lst.insert( mLayer->fields().at( attrNum ).name() );
87  else
88  lst = expression->referencedColumns();
89 
90  request.setFlags( ( expression && expression->needsGeometry() ) ?
93  .setSubsetOfAttributes( lst, mLayer->fields() );
94 
95  if ( mFidsSet )
96  request.setFilterFids( mFidsFilter );
97 
98  if ( !mOrderBy.empty() )
99  request.setOrderBy( mOrderBy );
100 
101  if ( !mFilterExpression.isEmpty() )
102  request.setFilterExpression( mFilterExpression );
103  if ( context )
104  request.setExpressionContext( *context );
105 
106  request.setFeedback( feedback ? feedback : ( context ? context->feedback() : nullptr ) );
107 
108  //determine result type
109  QVariant::Type resultType = QVariant::Double;
110  int userType = 0;
111  if ( attrNum == -1 )
112  {
113  if ( aggregate == GeometryCollect )
114  {
115  // in this case we know the result should be a geometry value, so no need to sniff it out...
116  resultType = QVariant::UserType;
117  }
118  else
119  {
120  // check expression result type
121  bool foundFeatures = false;
122  std::tuple<QVariant::Type, int> returnType = QgsExpressionUtils::determineResultType( fieldOrExpression, mLayer, request, *context, &foundFeatures );
123  if ( !foundFeatures )
124  {
125  if ( ok )
126  *ok = true;
127  return defaultValue( aggregate );
128  }
129 
130  resultType = std::get<0>( returnType );
131  userType = std::get<1>( returnType );
132  if ( resultType == QVariant::Invalid )
133  {
134  QVariant v;
135  switch ( aggregate )
136  {
137  // string
138  case StringConcatenate:
140  case StringMinimumLength:
141  case StringMaximumLength:
142  v = QString();
143  break;
144 
145  // numerical
146  case Sum:
147  case Mean:
148  case Median:
149  case StDev:
150  case StDevSample:
151  case Range:
152  case FirstQuartile:
153  case ThirdQuartile:
154  case InterQuartileRange:
155  // mixed type, fallback to numerical
156  case Count:
157  case CountDistinct:
158  case CountMissing:
159  case Minority:
160  case Majority:
161  case Min:
162  case Max:
163  v = 0.0;
164  break;
165 
166  // geometry
167  case GeometryCollect:
168  v = QgsGeometry();
169  break;
170 
171  // list, fallback to string
172  case ArrayAggregate:
173  v = QString();
174  break;
175  }
176  resultType = v.type();
177  userType = v.userType();
178  }
179  }
180  }
181  else
182  resultType = mLayer->fields().at( attrNum ).type();
183 
184  QgsFeatureIterator fit = mLayer->getFeatures( request );
185  return calculate( aggregate, fit, resultType, userType, attrNum, expression.get(), mDelimiter, context, ok, &mLastError );
186 }
187 
189 {
190  const QString normalized = string.trimmed().toLower();
191 
192  if ( ok )
193  *ok = true;
194 
195  if ( normalized == QLatin1String( "count" ) )
196  return Count;
197  else if ( normalized == QLatin1String( "count_distinct" ) )
198  return CountDistinct;
199  else if ( normalized == QLatin1String( "count_missing" ) )
200  return CountMissing;
201  else if ( normalized == QLatin1String( "min" ) )
202  return Min;
203  else if ( normalized == QLatin1String( "max" ) )
204  return Max;
205  else if ( normalized == QLatin1String( "sum" ) )
206  return Sum;
207  else if ( normalized == QLatin1String( "mean" ) )
208  return Mean;
209  else if ( normalized == QLatin1String( "median" ) )
210  return Median;
211  else if ( normalized == QLatin1String( "stdev" ) )
212  return StDev;
213  else if ( normalized == QLatin1String( "stdevsample" ) )
214  return StDevSample;
215  else if ( normalized == QLatin1String( "range" ) )
216  return Range;
217  else if ( normalized == QLatin1String( "minority" ) )
218  return Minority;
219  else if ( normalized == QLatin1String( "majority" ) )
220  return Majority;
221  else if ( normalized == QLatin1String( "q1" ) )
222  return FirstQuartile;
223  else if ( normalized == QLatin1String( "q3" ) )
224  return ThirdQuartile;
225  else if ( normalized == QLatin1String( "iqr" ) )
226  return InterQuartileRange;
227  else if ( normalized == QLatin1String( "min_length" ) )
228  return StringMinimumLength;
229  else if ( normalized == QLatin1String( "max_length" ) )
230  return StringMaximumLength;
231  else if ( normalized == QLatin1String( "concatenate" ) )
232  return StringConcatenate;
233  else if ( normalized == QLatin1String( "concatenate_unique" ) )
235  else if ( normalized == QLatin1String( "collect" ) )
236  return GeometryCollect;
237  else if ( normalized == QLatin1String( "array_agg" ) )
238  return ArrayAggregate;
239 
240  if ( ok )
241  *ok = false;
242 
243  return Count;
244 }
245 
247 {
248  switch ( aggregate )
249  {
251  return QObject::tr( "count" );
253  return QObject::tr( "count distinct" );
255  return QObject::tr( "count missing" );
257  return QObject::tr( "minimum" );
259  return QObject::tr( "maximum" );
261  return QObject::tr( "sum" );
263  return QObject::tr( "mean" );
265  return QObject::tr( "median" );
267  return QObject::tr( "standard deviation" );
269  return QObject::tr( "standard deviation (sample)" );
271  return QObject::tr( "range" );
273  return QObject::tr( "minority" );
275  return QObject::tr( "majority" );
277  return QObject::tr( "first quartile" );
279  return QObject::tr( "third quartile" );
281  return QObject::tr( "inter quartile range" );
283  return QObject::tr( "minimum length" );
285  return QObject::tr( "maximum length" );
287  return QObject::tr( "concatenate" );
289  return QObject::tr( "collection" );
291  return QObject::tr( "array aggregate" );
293  return QObject::tr( "concatenate (unique)" );
294  }
295  return QString();
296 }
297 
298 QList<QgsAggregateCalculator::AggregateInfo> QgsAggregateCalculator::aggregates()
299 {
300  QList< AggregateInfo > aggregates;
301  aggregates
302  << AggregateInfo
303  {
304  QStringLiteral( "count" ),
305  QCoreApplication::tr( "Count" ),
306  QSet<QVariant::Type>()
307  << QVariant::DateTime
308  << QVariant::Date
309  << QVariant::Int
310  << QVariant::UInt
311  << QVariant::LongLong
312  << QVariant::ULongLong
313  << QVariant::String
314  }
315  << AggregateInfo
316  {
317  QStringLiteral( "count_distinct" ),
318  QCoreApplication::tr( "Count Distinct" ),
319  QSet<QVariant::Type>()
320  << QVariant::DateTime
321  << QVariant::Date
322  << QVariant::UInt
323  << QVariant::Int
324  << QVariant::LongLong
325  << QVariant::ULongLong
326  << QVariant::String
327  }
328  << AggregateInfo
329  {
330  QStringLiteral( "count_missing" ),
331  QCoreApplication::tr( "Count Missing" ),
332  QSet<QVariant::Type>()
333  << QVariant::DateTime
334  << QVariant::Date
335  << QVariant::Int
336  << QVariant::UInt
337  << QVariant::LongLong
338  << QVariant::String
339  }
340  << AggregateInfo
341  {
342  QStringLiteral( "min" ),
343  QCoreApplication::tr( "Min" ),
344  QSet<QVariant::Type>()
345  << QVariant::DateTime
346  << QVariant::Date
347  << QVariant::Int
348  << QVariant::UInt
349  << QVariant::LongLong
350  << QVariant::ULongLong
351  << QVariant::Double
352  << QVariant::String
353  }
354  << AggregateInfo
355  {
356  QStringLiteral( "max" ),
357  QCoreApplication::tr( "Max" ),
358  QSet<QVariant::Type>()
359  << QVariant::DateTime
360  << QVariant::Date
361  << QVariant::Int
362  << QVariant::UInt
363  << QVariant::LongLong
364  << QVariant::ULongLong
365  << QVariant::Double
366  << QVariant::String
367  }
368  << AggregateInfo
369  {
370  QStringLiteral( "sum" ),
371  QCoreApplication::tr( "Sum" ),
372  QSet<QVariant::Type>()
373  << QVariant::Int
374  << QVariant::UInt
375  << QVariant::LongLong
376  << QVariant::ULongLong
377  << QVariant::Double
378  }
379  << AggregateInfo
380  {
381  QStringLiteral( "mean" ),
382  QCoreApplication::tr( "Mean" ),
383  QSet<QVariant::Type>()
384  << QVariant::Int
385  << QVariant::UInt
386  << QVariant::LongLong
387  << QVariant::ULongLong
388  << QVariant::Double
389  }
390  << AggregateInfo
391  {
392  QStringLiteral( "median" ),
393  QCoreApplication::tr( "Median" ),
394  QSet<QVariant::Type>()
395  << QVariant::Int
396  << QVariant::UInt
397  << QVariant::Double
398  }
399  << AggregateInfo
400  {
401  QStringLiteral( "stdev" ),
402  QCoreApplication::tr( "Stdev" ),
403  QSet<QVariant::Type>()
404  << QVariant::Int
405  << QVariant::UInt
406  << QVariant::LongLong
407  << QVariant::ULongLong
408  << QVariant::Double
409  }
410  << AggregateInfo
411  {
412  QStringLiteral( "stdevsample" ),
413  QCoreApplication::tr( "Stdev Sample" ),
414  QSet<QVariant::Type>()
415  << QVariant::Int
416  << QVariant::UInt
417  << QVariant::LongLong
418  << QVariant::ULongLong
419  << QVariant::Double
420  }
421  << AggregateInfo
422  {
423  QStringLiteral( "range" ),
424  QCoreApplication::tr( "Range" ),
425  QSet<QVariant::Type>()
426  << QVariant::Date
427  << QVariant::DateTime
428  << QVariant::Int
429  << QVariant::UInt
430  << QVariant::LongLong
431  << QVariant::ULongLong
432  << QVariant::Double
433  }
434  << AggregateInfo
435  {
436  QStringLiteral( "minority" ),
437  QCoreApplication::tr( "Minority" ),
438  QSet<QVariant::Type>()
439  << QVariant::Int
440  << QVariant::UInt
441  << QVariant::LongLong
442  << QVariant::ULongLong
443  << QVariant::Double
444  << QVariant::String
445  }
446  << AggregateInfo
447  {
448  QStringLiteral( "majority" ),
449  QCoreApplication::tr( "Majority" ),
450  QSet<QVariant::Type>()
451  << QVariant::Int
452  << QVariant::UInt
453  << QVariant::LongLong
454  << QVariant::ULongLong
455  << QVariant::Double
456  << QVariant::String
457  }
458  << AggregateInfo
459  {
460  QStringLiteral( "q1" ),
461  QCoreApplication::tr( "Q1" ),
462  QSet<QVariant::Type>()
463  << QVariant::Int
464  << QVariant::UInt
465  << QVariant::LongLong
466  << QVariant::ULongLong
467  << QVariant::Double
468  }
469  << AggregateInfo
470  {
471  QStringLiteral( "q3" ),
472  QCoreApplication::tr( "Q3" ),
473  QSet<QVariant::Type>()
474  << QVariant::Int
475  << QVariant::UInt
476  << QVariant::LongLong
477  << QVariant::ULongLong
478  << QVariant::Double
479  }
480  << AggregateInfo
481  {
482  QStringLiteral( "iqr" ),
483  QCoreApplication::tr( "InterQuartileRange" ),
484  QSet<QVariant::Type>()
485  << QVariant::Int
486  << QVariant::UInt
487  << QVariant::LongLong
488  << QVariant::ULongLong
489  << QVariant::Double
490  }
491  << AggregateInfo
492  {
493  QStringLiteral( "min_length" ),
494  QCoreApplication::tr( "Min Length" ),
495  QSet<QVariant::Type>()
496  << QVariant::String
497  }
498  << AggregateInfo
499  {
500  QStringLiteral( "max_length" ),
501  QCoreApplication::tr( "Max Length" ),
502  QSet<QVariant::Type>()
503  << QVariant::String
504  }
505  << AggregateInfo
506  {
507  QStringLiteral( "concatenate" ),
508  QCoreApplication::tr( "Concatenate" ),
509  QSet<QVariant::Type>()
510  << QVariant::String
511  }
512  << AggregateInfo
513  {
514  QStringLiteral( "collect" ),
515  QCoreApplication::tr( "Collect" ),
516  QSet<QVariant::Type>()
517  }
518  << AggregateInfo
519  {
520  QStringLiteral( "array_agg" ),
521  QCoreApplication::tr( "Array Aggregate" ),
522  QSet<QVariant::Type>()
523  };
524 
525  return aggregates;
526 }
527 
528 QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate aggregate, QgsFeatureIterator &fit, QVariant::Type resultType, int userType,
529  int attr, QgsExpression *expression, const QString &delimiter, QgsExpressionContext *context, bool *ok, QString *error )
530 {
531  if ( ok )
532  *ok = false;
533 
534  if ( aggregate == QgsAggregateCalculator::ArrayAggregate )
535  {
536  if ( ok )
537  *ok = true;
538  return calculateArrayAggregate( fit, attr, expression, context );
539  }
540 
541  switch ( resultType )
542  {
543  case QVariant::Int:
544  case QVariant::UInt:
545  case QVariant::LongLong:
546  case QVariant::ULongLong:
547  case QVariant::Double:
548  {
549  bool statOk = false;
550  const QgsStatisticalSummary::Statistic stat = numericStatFromAggregate( aggregate, &statOk );
551  if ( !statOk )
552  {
553  if ( error )
554  *error = expression ? QObject::tr( "Cannot calculate %1 on numeric values" ).arg( displayName( aggregate ) )
555  : QObject::tr( "Cannot calculate %1 on numeric fields" ).arg( displayName( aggregate ) );
556  return QVariant();
557  }
558 
559  if ( ok )
560  *ok = true;
561  return calculateNumericAggregate( fit, attr, expression, context, stat );
562  }
563 
564  case QVariant::Date:
565  case QVariant::DateTime:
566  {
567  bool statOk = false;
568  const QgsDateTimeStatisticalSummary::Statistic stat = dateTimeStatFromAggregate( aggregate, &statOk );
569  if ( !statOk )
570  {
571  if ( error )
572  *error = ( expression ? QObject::tr( "Cannot calculate %1 on %2 values" ).arg( displayName( aggregate ) ) :
573  QObject::tr( "Cannot calculate %1 on %2 fields" ).arg( displayName( aggregate ) ) ).arg( resultType == QVariant::Date ? QObject::tr( "date" ) : QObject::tr( "datetime" ) );
574  return QVariant();
575  }
576 
577  if ( ok )
578  *ok = true;
579  return calculateDateTimeAggregate( fit, attr, expression, context, stat );
580  }
581 
582  case QVariant::UserType:
583  {
584  if ( aggregate == GeometryCollect )
585  {
586  if ( ok )
587  *ok = true;
588  return calculateGeometryAggregate( fit, expression, context );
589  }
590  else
591  {
592  return QVariant();
593  }
594  }
595 
596  default:
597  {
598  // treat as string
599  if ( aggregate == StringConcatenate )
600  {
601  //special case
602  if ( ok )
603  *ok = true;
604  return concatenateStrings( fit, attr, expression, context, delimiter );
605  }
606  else if ( aggregate == StringConcatenateUnique )
607  {
608  //special case
609  if ( ok )
610  *ok = true;
611  return concatenateStrings( fit, attr, expression, context, delimiter, true );
612  }
613 
614  bool statOk = false;
615  const QgsStringStatisticalSummary::Statistic stat = stringStatFromAggregate( aggregate, &statOk );
616  if ( !statOk )
617  {
618  QString typeString;
619  if ( resultType == QVariant::Invalid )
620  typeString = QObject::tr( "null" );
621  else if ( resultType == QVariant::UserType )
622  typeString = QMetaType::typeName( userType );
623  else
624  typeString = resultType == QVariant::String ? QObject::tr( "string" ) : QVariant::typeToName( resultType );
625 
626  if ( error )
627  *error = expression ? QObject::tr( "Cannot calculate %1 on %3 values" ).arg( displayName( aggregate ), typeString )
628  : QObject::tr( "Cannot calculate %1 on %3 fields" ).arg( displayName( aggregate ), typeString );
629  return QVariant();
630  }
631 
632  if ( ok )
633  *ok = true;
634  return calculateStringAggregate( fit, attr, expression, context, stat );
635  }
636  }
637 
638 #ifndef _MSC_VER
639  return QVariant();
640 #endif
641 }
642 
643 QgsStatisticalSummary::Statistic QgsAggregateCalculator::numericStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
644 {
645  if ( ok )
646  *ok = true;
647 
648  switch ( aggregate )
649  {
650  case Count:
652  case CountDistinct:
654  case CountMissing:
656  case Min:
658  case Max:
660  case Sum:
662  case Mean:
664  case Median:
666  case StDev:
668  case StDevSample:
670  case Range:
672  case Minority:
674  case Majority:
676  case FirstQuartile:
678  case ThirdQuartile:
680  case InterQuartileRange:
682  case StringMinimumLength:
683  case StringMaximumLength:
684  case StringConcatenate:
686  case GeometryCollect:
687  case ArrayAggregate:
688  {
689  if ( ok )
690  *ok = false;
692  }
693  }
694 
695  if ( ok )
696  *ok = false;
698 }
699 
700 QgsStringStatisticalSummary::Statistic QgsAggregateCalculator::stringStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
701 {
702  if ( ok )
703  *ok = true;
704 
705  switch ( aggregate )
706  {
707  case Count:
709  case CountDistinct:
711  case CountMissing:
713  case Min:
715  case Max:
717  case StringMinimumLength:
719  case StringMaximumLength:
721  case Minority:
723  case Majority:
725 
726  case Sum:
727  case Mean:
728  case Median:
729  case StDev:
730  case StDevSample:
731  case Range:
732  case FirstQuartile:
733  case ThirdQuartile:
734  case InterQuartileRange:
735  case StringConcatenate:
737  case GeometryCollect:
738  case ArrayAggregate:
739  {
740  if ( ok )
741  *ok = false;
743  }
744  }
745 
746  if ( ok )
747  *ok = false;
749 }
750 
751 QgsDateTimeStatisticalSummary::Statistic QgsAggregateCalculator::dateTimeStatFromAggregate( QgsAggregateCalculator::Aggregate aggregate, bool *ok )
752 {
753  if ( ok )
754  *ok = true;
755 
756  switch ( aggregate )
757  {
758  case Count:
760  case CountDistinct:
762  case CountMissing:
764  case Min:
766  case Max:
768  case Range:
770 
771  case Sum:
772  case Mean:
773  case Median:
774  case StDev:
775  case StDevSample:
776  case Minority:
777  case Majority:
778  case FirstQuartile:
779  case ThirdQuartile:
780  case InterQuartileRange:
781  case StringMinimumLength:
782  case StringMaximumLength:
783  case StringConcatenate:
785  case GeometryCollect:
786  case ArrayAggregate:
787  {
788  if ( ok )
789  *ok = false;
791  }
792  }
793 
794  if ( ok )
795  *ok = false;
797 }
798 
799 QVariant QgsAggregateCalculator::calculateNumericAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
801 {
802  Q_ASSERT( expression || attr >= 0 );
803 
804  QgsStatisticalSummary s( stat );
805  QgsFeature f;
806 
807  while ( fit.nextFeature( f ) )
808  {
809  if ( expression )
810  {
811  Q_ASSERT( context );
812  context->setFeature( f );
813  const QVariant v = expression->evaluate( context );
814  s.addVariant( v );
815  }
816  else
817  {
818  s.addVariant( f.attribute( attr ) );
819  }
820  }
821  s.finalize();
822  const double val = s.statistic( stat );
823  return std::isnan( val ) ? QVariant() : val;
824 }
825 
826 QVariant QgsAggregateCalculator::calculateStringAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
828 {
829  Q_ASSERT( expression || attr >= 0 );
830 
831  QgsStringStatisticalSummary s( stat );
832  QgsFeature f;
833 
834  while ( fit.nextFeature( f ) )
835  {
836  if ( expression )
837  {
838  Q_ASSERT( context );
839  context->setFeature( f );
840  const QVariant v = expression->evaluate( context );
841  s.addValue( v );
842  }
843  else
844  {
845  s.addValue( f.attribute( attr ) );
846  }
847  }
848  s.finalize();
849  return s.statistic( stat );
850 }
851 
852 QVariant QgsAggregateCalculator::calculateGeometryAggregate( QgsFeatureIterator &fit, QgsExpression *expression, QgsExpressionContext *context )
853 {
854  Q_ASSERT( expression );
855 
856  QgsFeature f;
857  QVector< QgsGeometry > geometries;
858  while ( fit.nextFeature( f ) )
859  {
860  Q_ASSERT( context );
861  context->setFeature( f );
862  const QVariant v = expression->evaluate( context );
863  if ( v.canConvert<QgsGeometry>() )
864  {
865  geometries << v.value<QgsGeometry>();
866  }
867  }
868 
869  return QVariant::fromValue( QgsGeometry::collectGeometry( geometries ) );
870 }
871 
872 QVariant QgsAggregateCalculator::concatenateStrings( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
873  QgsExpressionContext *context, const QString &delimiter, bool unique )
874 {
875  Q_ASSERT( expression || attr >= 0 );
876 
877  QgsFeature f;
878  QStringList results;
879  while ( fit.nextFeature( f ) )
880  {
881  QString result;
882  if ( expression )
883  {
884  Q_ASSERT( context );
885  context->setFeature( f );
886  const QVariant v = expression->evaluate( context );
887  result = v.toString();
888  }
889  else
890  {
891  result = f.attribute( attr ).toString();
892  }
893 
894  if ( !unique || !results.contains( result ) )
895  results << result;
896  }
897 
898  return results.join( delimiter );
899 }
900 
901 QVariant QgsAggregateCalculator::defaultValue( QgsAggregateCalculator::Aggregate aggregate ) const
902 {
903  // value to return when NO features are aggregated:
904  switch ( aggregate )
905  {
906  // sensible values:
907  case Count:
908  case CountDistinct:
909  case CountMissing:
910  return 0;
911 
912  case StringConcatenate:
914  return ""; // zero length string - not null!
915 
916  case ArrayAggregate:
917  return QVariantList(); // empty list
918 
919  // undefined - nothing makes sense here
920  case Sum:
921  case Min:
922  case Max:
923  case Mean:
924  case Median:
925  case StDev:
926  case StDevSample:
927  case Range:
928  case Minority:
929  case Majority:
930  case FirstQuartile:
931  case ThirdQuartile:
932  case InterQuartileRange:
933  case StringMinimumLength:
934  case StringMaximumLength:
935  case GeometryCollect:
936  return QVariant();
937  }
938  return QVariant();
939 }
940 
941 QVariant QgsAggregateCalculator::calculateDateTimeAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
943 {
944  Q_ASSERT( expression || attr >= 0 );
945 
947  QgsFeature f;
948 
949  while ( fit.nextFeature( f ) )
950  {
951  if ( expression )
952  {
953  Q_ASSERT( context );
954  context->setFeature( f );
955  const QVariant v = expression->evaluate( context );
956  s.addValue( v );
957  }
958  else
959  {
960  s.addValue( f.attribute( attr ) );
961  }
962  }
963  s.finalize();
964  return s.statistic( stat );
965 }
966 
967 QVariant QgsAggregateCalculator::calculateArrayAggregate( QgsFeatureIterator &fit, int attr, QgsExpression *expression,
968  QgsExpressionContext *context )
969 {
970  Q_ASSERT( expression || attr >= 0 );
971 
972  QgsFeature f;
973 
974  QVariantList array;
975 
976  while ( fit.nextFeature( f ) )
977  {
978  if ( expression )
979  {
980  Q_ASSERT( context );
981  context->setFeature( f );
982  const QVariant v = expression->evaluate( context );
983  array.append( v );
984  }
985  else
986  {
987  array.append( f.attribute( attr ) );
988  }
989  }
990  return array;
991 }
992 
const QgsVectorLayer * layer() const
Returns the associated vector layer.
void setParameters(const AggregateParameters &parameters)
Sets all aggregate parameters from a parameter bundle.
void setFidsFilter(const QgsFeatureIds &fids)
Sets a filter to limit the features used during the aggregate calculation.
Aggregate
Available aggregates to calculate.
@ StringConcatenateUnique
Concatenate unique values with a joining string (string fields only). Specify the delimiter using set...
@ StDev
Standard deviation of values (numeric fields only)
@ StringMaximumLength
Maximum length of string (string fields only)
@ ThirdQuartile
Third quartile (numeric fields only)
@ Range
Range of values (max - min) (numeric and datetime fields only)
@ ArrayAggregate
Create an array of values.
@ InterQuartileRange
Inter quartile range (IQR) (numeric fields only)
@ FirstQuartile
First quartile (numeric fields only)
@ Median
Median of values (numeric fields only)
@ GeometryCollect
Create a multipart geometry from aggregated geometries.
@ CountMissing
Number of missing (null) values.
@ StDevSample
Sample standard deviation of values (numeric fields only)
@ Majority
Majority of values.
@ StringConcatenate
Concatenate values with a joining string (string fields only). Specify the delimiter using setDelimit...
@ Mean
Mean of values (numeric fields only)
@ StringMinimumLength
Minimum length of string (string fields only)
@ CountDistinct
Number of distinct values.
@ Minority
Minority of values.
static QList< QgsAggregateCalculator::AggregateInfo > aggregates()
Structured information for available aggregates.
QString delimiter() const
Returns the delimiter used for joining values with the StringConcatenate aggregate.
static Aggregate stringToAggregate(const QString &string, bool *ok=nullptr)
Converts a string to a aggregate type.
QVariant calculate(Aggregate aggregate, const QString &fieldOrExpression, QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeedback *feedback=nullptr) const
Calculates the value of an aggregate.
static QString displayName(Aggregate aggregate)
Returns the friendly display name for a aggregate.
QgsAggregateCalculator(const QgsVectorLayer *layer)
Constructor for QgsAggregateCalculator.
Calculator for summary statistics and aggregates for a list of datetimes.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ Min
Minimum (earliest) datetime value.
@ Max
Maximum (latest) datetime value.
@ CountDistinct
Number of distinct datetime values.
@ Range
Interval between earliest and latest datetime value.
@ CountMissing
Number of missing (null) values.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the expression to check if evaluation sh...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
static std::tuple< QVariant::Type, int > determineResultType(const QString &expression, const QgsVectorLayer *layer, QgsFeatureRequest request=QgsFeatureRequest(), QgsExpressionContext context=QgsExpressionContext(), bool *foundFeatures=nullptr)
Returns a value type and user type for a given expression.
Class for parsing and evaluation of expressions (formerly called "search strings").
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
QString name
Definition: qgsfield.h:60
QVariant::Type type
Definition: qgsfield.h:58
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
Calculator for summary statistics for a list of doubles.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ InterQuartileRange
Inter quartile range (IQR)
@ Median
Median of values.
@ Variety
Variety (count of distinct) values.
@ Minority
Minority of values.
@ ThirdQuartile
Third quartile.
@ Majority
Majority of values.
@ CountMissing
Number of missing (null) values.
@ Range
Range of values (max - min)
@ StDevSample
Sample standard deviation of values.
@ FirstQuartile
First quartile.
@ StDev
Standard deviation of values.
Calculator for summary statistics and aggregates for a list of strings.
Statistic
Enumeration of flags that specify statistics to be calculated.
@ MaximumLength
Maximum length of string.
@ MinimumLength
Minimum length of string.
@ CountDistinct
Number of distinct string values.
@ CountMissing
Number of missing (null) values.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
const QString & typeName
Structured information about the available aggregates.
A bundle of parameters controlling aggregate calculation.
QString filter
Optional filter for calculating aggregate over a subset of features, or an empty string to use all fe...
QString delimiter
Delimiter to use for joining values with the StringConcatenate aggregate.
QgsFeatureRequest::OrderBy orderBy
Optional order by clauses.