From 821134ca913721484d345be4c67a362a0f716a82 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 16 May 2016 15:00:55 +1000 Subject: [PATCH] Add method to convert string to aggregate type --- python/core/qgsaggregatecalculator.sip | 6 +++ src/core/qgsaggregatecalculator.cpp | 50 +++++++++++++++++++ src/core/qgsaggregatecalculator.h | 7 +++ .../src/python/test_qgsaggregatecalculator.py | 33 ++++++++++++ 4 files changed, 96 insertions(+) diff --git a/python/core/qgsaggregatecalculator.sip b/python/core/qgsaggregatecalculator.sip index 7a340fe7d56..46ab52f50c7 100644 --- a/python/core/qgsaggregatecalculator.sip +++ b/python/core/qgsaggregatecalculator.sip @@ -70,5 +70,11 @@ class QgsAggregateCalculator QVariant calculate( Aggregate aggregate, const QString& fieldOrExpression, QgsExpressionContext* context = nullptr, bool* ok = nullptr ) const; + /** Converts a string to a aggregate type. + * @param string string to convert + * @param ok if specified, will be set to true if conversion was successful + * @returns aggregate type + */ + static Aggregate stringToAggregate( const QString& string, bool* ok = nullptr ); }; diff --git a/src/core/qgsaggregatecalculator.cpp b/src/core/qgsaggregatecalculator.cpp index 22a531b7743..389a0beacc7 100644 --- a/src/core/qgsaggregatecalculator.cpp +++ b/src/core/qgsaggregatecalculator.cpp @@ -105,6 +105,56 @@ QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate ag return calculate( aggregate, fit, resultType, attrNum, expression.data(), context, ok ); } +QgsAggregateCalculator::Aggregate QgsAggregateCalculator::stringToAggregate( const QString& string, bool* ok ) +{ + QString normalized = string.trimmed().toLower(); + + if ( ok ) + *ok = true; + + if ( normalized == "count" ) + return Count; + else if ( normalized == "count_distinct" ) + return CountDistinct; + else if ( normalized == "count_missing" ) + return CountMissing; + else if ( normalized == "min" ) + return Min; + else if ( normalized == "max" ) + return Max; + else if ( normalized == "sum" ) + return Sum; + else if ( normalized == "mean" ) + return Mean; + else if ( normalized == "median" ) + return Median; + else if ( normalized == "stdev" ) + return StDev; + else if ( normalized == "stdevsample" ) + return StDevSample; + else if ( normalized == "range" ) + return Range; + else if ( normalized == "minority" ) + return Minority; + else if ( normalized == "majority" ) + return Majority; + else if ( normalized == "q1" ) + return FirstQuartile; + else if ( normalized == "q3" ) + return ThirdQuartile; + else if ( normalized == "iqr" ) + return InterQuartileRange; + else if ( normalized == "min_length" ) + return StringMinimumLength; + else if ( normalized == "max_length" ) + return StringMaximumLength; + + if ( ok ) + *ok = false; + + return Count; +} + QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate aggregate, QgsFeatureIterator& fit, QVariant::Type resultType, int attr, QgsExpression* expression, QgsExpressionContext* context, bool* ok ) { diff --git a/src/core/qgsaggregatecalculator.h b/src/core/qgsaggregatecalculator.h index bf1cfa072f9..6543c1da5f2 100644 --- a/src/core/qgsaggregatecalculator.h +++ b/src/core/qgsaggregatecalculator.h @@ -96,6 +96,13 @@ class CORE_EXPORT QgsAggregateCalculator QVariant calculate( Aggregate aggregate, const QString& fieldOrExpression, QgsExpressionContext* context = nullptr, bool* ok = nullptr ) const; + /** Converts a string to a aggregate type. + * @param string string to convert + * @param ok if specified, will be set to true if conversion was successful + * @returns aggregate type + */ + static Aggregate stringToAggregate( const QString& string, bool* ok = nullptr ); + private: //! Source layer diff --git a/tests/src/python/test_qgsaggregatecalculator.py b/tests/src/python/test_qgsaggregatecalculator.py index 6c7730977f8..eb7e9594ded 100644 --- a/tests/src/python/test_qgsaggregatecalculator.py +++ b/tests/src/python/test_qgsaggregatecalculator.py @@ -334,6 +334,39 @@ class TestQgsAggregateCalculator(unittest.TestCase): self.assertTrue(ok) self.assertEqual(val, 5) + def testStringToAggregate(self): + """ test converting strings to aggregate types """ + + tests = [[QgsAggregateCalculator.Count, ' cOUnT '], + [QgsAggregateCalculator.CountDistinct, ' count_distinct '], + [QgsAggregateCalculator.CountMissing, 'COUNT_MISSING'], + [QgsAggregateCalculator.Min, ' MiN'], + [QgsAggregateCalculator.Max, 'mAX'], + [QgsAggregateCalculator.Sum, 'sum'], + [QgsAggregateCalculator.Mean, 'MEAn '], + [QgsAggregateCalculator.Median, 'median'], + [QgsAggregateCalculator.StDev, 'stdev'], + [QgsAggregateCalculator.StDevSample, 'stdevsample'], + [QgsAggregateCalculator.Range, 'range'], + [QgsAggregateCalculator.Minority, 'minority'], + [QgsAggregateCalculator.Majority, 'majority'], + [QgsAggregateCalculator.FirstQuartile, 'q1'], + [QgsAggregateCalculator.ThirdQuartile, 'q3'], + [QgsAggregateCalculator.InterQuartileRange, 'iqr'], + [QgsAggregateCalculator.StringMinimumLength, 'min_length'], + [QgsAggregateCalculator.StringMaximumLength, 'max_length']] + + for t in tests: + agg, ok = QgsAggregateCalculator.stringToAggregate(t[1]) + self.assertTrue(ok) + self.assertEqual(agg, t[0]) + + # test some bad values + agg, ok = QgsAggregateCalculator.stringToAggregate('') + self.assertFalse(ok) + agg, ok = QgsAggregateCalculator.stringToAggregate('bad') + self.assertFalse(ok) + if __name__ == "__main__": unittest.main()