File indexing completed on 2024-12-15 03:44:59
0001 /* 0002 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "sample.h" 0008 #include <core/product.h> 0009 #include <core/schemaentry.h> 0010 #include <core/schemaentryelement.h> 0011 0012 #include <QDateTime> 0013 #include <QDebug> 0014 #include <QHash> 0015 #include <QJsonArray> 0016 #include <QJsonDocument> 0017 #include <QJsonObject> 0018 #include <QSharedData> 0019 #include <QVariant> 0020 0021 using namespace KUserFeedback::Console; 0022 0023 class KUserFeedback::Console::SampleData : public QSharedData 0024 { 0025 public: 0026 QDateTime timestamp; 0027 QHash<QString, QVariant> data; 0028 }; 0029 0030 Sample::Sample() : d(new SampleData) {} 0031 Sample::Sample(const Sample&) = default; 0032 Sample::~Sample() = default; 0033 Sample& Sample::operator=(const Sample&) = default; 0034 0035 QDateTime Sample::timestamp() const 0036 { 0037 return d->timestamp; 0038 } 0039 0040 QVariant Sample::value(const QString &name) const 0041 { 0042 return d->data.value(name); 0043 } 0044 0045 QVector<Sample> Sample::fromJson(const QByteArray &json, const Product &product) 0046 { 0047 const auto array = QJsonDocument::fromJson(json).array(); 0048 QVector<Sample> samples; 0049 samples.reserve(array.size()); 0050 for (auto it = array.begin(); it != array.end(); ++it) { 0051 const auto obj = it->toObject(); 0052 Sample s; 0053 s.d->timestamp = QDateTime::fromString(obj.value(QStringLiteral("timestamp")).toString(), Qt::ISODate); 0054 foreach (const auto &entry, product.schema()) { 0055 if (!obj.contains(entry.name())) 0056 continue; 0057 switch (entry.dataType()) { 0058 case SchemaEntry::Scalar: 0059 { 0060 const auto entryData = obj.value(entry.name()).toObject(); 0061 foreach (const auto &elem, entry.elements()) { 0062 if (!entryData.contains(elem.name())) 0063 continue; 0064 // TODO schema-dependent type conversion 0065 s.d->data.insert(entry.name() + QLatin1Char('.') + elem.name(), entryData.value(elem.name()).toVariant()); 0066 } 0067 break; 0068 } 0069 case SchemaEntry::List: 0070 { 0071 const auto entryArray = obj.value(entry.name()).toArray(); 0072 QVariantList l; 0073 l.reserve(entryArray.size()); 0074 foreach (const auto &entryDataValue, entryArray) { 0075 const auto entryData = entryDataValue.toObject(); 0076 QVariantMap m; 0077 foreach (const auto &elem, entry.elements()) { 0078 if (!entryData.contains(elem.name())) 0079 continue; 0080 // TODO schema-dependent type conversion 0081 m.insert(elem.name(), entryData.value(elem.name()).toVariant()); 0082 } 0083 l.push_back(m); 0084 } 0085 s.d->data.insert(entry.name(), l); 0086 break; 0087 } 0088 case SchemaEntry::Map: 0089 { 0090 const auto entryMap = obj.value(entry.name()).toObject(); 0091 QVariantMap m; 0092 for (auto it = entryMap.begin(); it != entryMap.end(); ++it) { 0093 const auto entryData = it.value().toObject(); 0094 QVariantMap m2; 0095 foreach (const auto &elem, entry.elements()) { 0096 if (!entryData.contains(elem.name())) 0097 continue; 0098 // TODO schema-dependent type conversion 0099 m2.insert(elem.name(), entryData.value(elem.name()).toVariant()); 0100 } 0101 m.insert(it.key(), m2); 0102 } 0103 s.d->data.insert(entry.name(), m); 0104 break; 0105 } 0106 } 0107 } 0108 samples.push_back(s); 0109 } 0110 return samples; 0111 } 0112 0113 QByteArray Sample::toJson(const QVector<Sample> &samples, const Product &product) 0114 { 0115 QJsonArray array; 0116 for (const auto &s : samples) { 0117 QJsonObject obj; 0118 obj[QLatin1String("timestamp")] = s.timestamp().toString(Qt::ISODate); 0119 foreach (const auto &entry, product.schema()) { 0120 switch (entry.dataType()) { 0121 case SchemaEntry::Scalar: 0122 { 0123 QJsonObject subObj; 0124 const auto entryData = obj.value(entry.name()).toObject(); 0125 foreach (const auto &elem, entry.elements()) { 0126 const auto it = s.d->data.constFind(entry.name() + QLatin1Char('.') + elem.name()); 0127 if (it == s.d->data.constEnd()) 0128 continue; 0129 subObj[elem.name()] = QJsonValue::fromVariant(it.value()); 0130 } 0131 if (!subObj.isEmpty()) 0132 obj[entry.name()] = subObj; 0133 break; 0134 } 0135 case SchemaEntry::List: 0136 { 0137 QJsonArray a; 0138 const auto it = s.d->data.constFind(entry.name()); 0139 if (it == s.d->data.constEnd()) 0140 continue; 0141 const auto l = it.value().toList(); 0142 for (const auto &v : l) { 0143 QJsonObject subObj; 0144 const auto m = v.toMap(); 0145 for (auto it = m.begin(); it != m.end(); ++it) { 0146 subObj[it.key()] = QJsonValue::fromVariant(it.value()); 0147 } 0148 a.push_back(subObj); 0149 } 0150 obj[entry.name()] = a; 0151 break; 0152 } 0153 case SchemaEntry::Map: 0154 { 0155 QJsonObject map; 0156 const auto it = s.d->data.constFind(entry.name()); 0157 if (it == s.d->data.constEnd()) 0158 continue; 0159 const auto m = it.value().toMap(); 0160 for (auto it = m.begin(); it != m.end(); ++it) { 0161 QJsonObject subObj; 0162 const auto m = it.value().toMap(); 0163 for (auto it = m.begin(); it != m.end(); ++it) { 0164 subObj[it.key()] = QJsonValue::fromVariant(it.value()); 0165 } 0166 map[it.key()] = subObj; 0167 } 0168 obj[entry.name()] = map; 0169 break; 0170 } 0171 } 0172 } 0173 array.push_back(obj); 0174 } 0175 0176 QJsonDocument doc; 0177 doc.setArray(array); 0178 return doc.toJson(); 0179 }