File indexing completed on 2025-01-26 03:44:29

0001 /*
0002     SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "surveytargetexpressionevaluator.h"
0008 #include "surveytargetexpression.h"
0009 
0010 using namespace KUserFeedback;
0011 
0012 SurveyTargetExpressionDataProvider::SurveyTargetExpressionDataProvider()
0013 {
0014 }
0015 
0016 SurveyTargetExpressionDataProvider::~SurveyTargetExpressionDataProvider()
0017 {
0018 }
0019 
0020 SurveyTargetExpressionEvaluator::SurveyTargetExpressionEvaluator()
0021     : m_provider(nullptr)
0022 {
0023 }
0024 
0025 SurveyTargetExpressionEvaluator::~SurveyTargetExpressionEvaluator()
0026 {
0027 }
0028 
0029 void SurveyTargetExpressionEvaluator::setDataProvider(const SurveyTargetExpressionDataProvider* provider)
0030 {
0031     m_provider = provider;
0032 }
0033 
0034 static bool variantLess(const QVariant &lhs, const QVariant &rhs)
0035 {
0036 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0037     return QVariant::compare(lhs, rhs) == QPartialOrdering::Less;
0038 #else
0039     return lhs < rhs;
0040 #endif
0041 }
0042 
0043 static bool variantLessOrEqual(const QVariant &lhs, const QVariant &rhs)
0044 {
0045 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0046     const auto order = QVariant::compare(lhs, rhs);
0047     return order == QPartialOrdering::Less || order == QPartialOrdering::Equivalent;
0048 #else
0049     return lhs <= rhs;
0050 #endif
0051 }
0052 
0053 bool SurveyTargetExpressionEvaluator::evaluate(SurveyTargetExpression* expression)
0054 {
0055     // logical operations
0056     switch (expression->type()) {
0057         case SurveyTargetExpression::OpLogicAnd:
0058             return evaluate(expression->left()) && evaluate(expression->right());
0059         case SurveyTargetExpression::OpLogicOr:
0060             return evaluate(expression->left()) || evaluate(expression->right());
0061         default:
0062             break;
0063     }
0064 
0065     // comparison operations:
0066     const auto lhs = value(expression->left());
0067     const auto rhs = value(expression->right());
0068     if (lhs.type() == QVariant::Invalid || rhs.type() == QVariant::Invalid) // invalid element access can never succeed
0069         return false;
0070     if ((lhs.type() == QVariant::String && rhs.type() != QVariant::String)
0071         || (lhs.type() != QVariant::String && rhs.type() == QVariant::String))
0072         return false; // strings can only be compared to strings
0073 
0074     switch (expression->type()) {
0075         case SurveyTargetExpression::OpEqual:
0076             return lhs == rhs;
0077         case SurveyTargetExpression::OpNotEqual:
0078             return lhs != rhs;
0079         case SurveyTargetExpression::OpGreater:
0080             return variantLess(rhs, lhs);
0081         case SurveyTargetExpression::OpGreaterEqual:
0082             return variantLessOrEqual(rhs, lhs);
0083         case SurveyTargetExpression::OpLess:
0084             return variantLess(lhs, rhs);
0085         case SurveyTargetExpression::OpLessEqual:
0086             return variantLessOrEqual(lhs, rhs);
0087         default:
0088             break;
0089     }
0090 
0091     return false;
0092 }
0093 
0094 QVariant SurveyTargetExpressionEvaluator::value(SurveyTargetExpression* expression)
0095 {
0096     switch (expression->type()) {
0097         case SurveyTargetExpression::Value:
0098             return expression->value();
0099         case SurveyTargetExpression::ScalarElement:
0100         {
0101             const auto v = value(expression->source());
0102             if (v.canConvert<QVariantList>() && expression->sourceElement() == QLatin1String("size"))
0103                 return v.value<QVariantList>().size();
0104             const auto m = v.toMap();
0105             const auto it = m.find(expression->sourceElement());
0106             if (it != m.end() && !it.value().canConvert<QVariantMap>())
0107                 return it.value();
0108             if (expression->sourceElement() == QLatin1String("size"))
0109                 return m.size();
0110             return QVariant();
0111         }
0112         case SurveyTargetExpression::ListElement:
0113         {
0114             const auto v = value(expression->source()).value<QVariantList>().value(expression->value().toInt());
0115             return v.toMap().value(expression->sourceElement());
0116         }
0117         case SurveyTargetExpression::MapElement:
0118         {
0119             const auto v = value(expression->source()).toMap().value(expression->value().toString());
0120             qDebug() << v << value(expression->source()).toMap() << expression->value().toString();
0121             return v.toMap().value(expression->sourceElement());
0122         }
0123         default:
0124             break;
0125     }
0126 
0127     Q_ASSERT(false);
0128     return QVariant();
0129 }
0130 
0131 QVariant SurveyTargetExpressionEvaluator::value(const QString& source)
0132 {
0133     Q_ASSERT(m_provider);
0134     const auto it = m_dataCache.constFind(source);
0135     if (it != m_dataCache.constEnd())
0136         return it.value();
0137 
0138     const auto v = m_provider->sourceData(source);
0139     m_dataCache.insert(source, v);
0140     return v;
0141 }