Skip to content
Snippets Groups Projects
Commit 83d2b704 authored by Volker Krause's avatar Volker Krause
Browse files

Add (de)serialization code for aggregation settings

parent 637977dc
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,7 @@ set(analyzer_lib_srcs
add_library(UserFeedbackAnalyzer STATIC ${analyzer_lib_srcs})
target_link_libraries(UserFeedbackAnalyzer Qt5::Network)
target_include_directories(UserFeedbackAnalyzer PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};>")
target_compile_features(UserFeedbackAnalyzer PRIVATE cxx_generic_lambdas)
set(analyzer_srcs
aggregateddatamodel.cpp
......
......@@ -16,9 +16,24 @@
*/
#include "aggregation.h"
#include "util.h"
#include <QJsonArray>
#include <QJsonObject>
using namespace UserFeedback::Analyzer;
static const struct {
Aggregation::Type type;
const char *name;
} aggregation_types_table[] {
{ Aggregation::None, "none" },
{ Aggregation::Category, "category" },
{ Aggregation::RatioSet, "ratio_set" },
{ Aggregation::Numeric, "numeric" },
{ Aggregation::XY, "xy" }
};
Aggregation::Aggregation() = default;
Aggregation::~Aggregation() = default;
......@@ -41,3 +56,31 @@ void Aggregation::setElements(const QVector<AggregationElement>& elements)
{
m_elements = elements;
}
QJsonObject Aggregation::toJsonObject() const
{
QJsonObject obj;
obj.insert(QStringLiteral("type"), QLatin1String(aggregation_types_table[m_type].name));
QJsonArray elems;
for (const auto &e : m_elements)
elems.push_back(e.toJsonObject());
obj.insert(QStringLiteral("elements"), elems);
return obj;
}
QVector<Aggregation> Aggregation::fromJson(const Product &product, const QJsonArray& a)
{
QVector<Aggregation> aggrs;
aggrs.reserve(a.size());
for (const auto &v : a) {
if (!v.isObject())
continue;
const auto obj = v.toObject();
Aggregation aggr;
aggr.setType(Util::stringToEnum<Aggregation::Type>(obj.value(QLatin1String("type")).toString(), aggregation_types_table));
aggr.setElements(AggregationElement::fromJson(product, obj.value(QLatin1String("elements")).toArray()));
aggrs.push_back(aggr);
}
return aggrs;
}
......@@ -22,9 +22,14 @@
#include <QTypeInfo>
class QJsonArray;
class QJsonObject;
namespace UserFeedback {
namespace Analyzer {
class Product;
class Aggregation
{
Q_GADGET
......@@ -47,6 +52,9 @@ public:
QVector<AggregationElement> elements() const;
void setElements(const QVector<AggregationElement> &elements);
QJsonObject toJsonObject() const;
static QVector<Aggregation> fromJson(const Product &product, const QJsonArray &a);
private:
Type m_type = None;
QVector<AggregationElement> m_elements;
......
......@@ -16,9 +16,22 @@
*/
#include "aggregationelement.h"
#include "product.h"
#include "util.h"
#include <QJsonArray>
#include <QJsonObject>
using namespace UserFeedback::Analyzer;
static const struct {
AggregationElement::Type type;
const char *name;
} aggregation_element_types_table[] {
{ AggregationElement::Value, "value" },
{ AggregationElement::Size, "size" }
};
AggregationElement::AggregationElement() = default;
AggregationElement::~AggregationElement() = default;
......@@ -76,3 +89,44 @@ bool AggregationElement::operator==(const AggregationElement &other) const
}
Q_UNREACHABLE();
}
QJsonObject AggregationElement::toJsonObject() const
{
QJsonObject obj;
obj.insert(QStringLiteral("type"), QLatin1String(aggregation_element_types_table[m_type].name));
switch (m_type) {
case Value:
obj.insert(QStringLiteral("schemaEntry"), m_entry.name());
obj.insert(QStringLiteral("schemaEntryElement"), m_element.name());
break;
case Size:
obj.insert(QStringLiteral("schemaEntry"), m_entry.name());
break;
}
return obj;
}
QVector<AggregationElement> AggregationElement::fromJson(const Product &product, const QJsonArray& a)
{
QVector<AggregationElement> elems;
elems.reserve(a.size());
for (const auto &v : a) {
if (!v.isObject())
continue;
const auto obj = v.toObject();
AggregationElement e;
e.setType(Util::stringToEnum<AggregationElement::Type>(obj.value(QLatin1String("type")).toString(), aggregation_element_types_table));
switch (e.type()) {
case Value:
e.setSchemaEntry(product.schemaEntry(obj.value(QLatin1String("schemaEntry")).toString()));
e.setSchemaEntryElement(e.schemaEntry().element(obj.value(QLatin1String("schemaEntryElement")).toString()));
break;
case Size:
e.setSchemaEntry(product.schemaEntry(obj.value(QLatin1String("schemaEntry")).toString()));
break;
}
elems.push_back(e);
}
return elems;
}
......@@ -21,9 +21,14 @@
#include "schemaentry.h"
#include "schemaentryelement.h"
class QJsonArray;
class QJsonObject;
namespace UserFeedback {
namespace Analyzer {
class Product;
class AggregationElement
{
public:
......@@ -47,6 +52,9 @@ public:
QString displayString() const;
QJsonObject toJsonObject() const;
static QVector<AggregationElement> fromJson(const Product &product, const QJsonArray &a);
private:
SchemaEntry m_entry;
SchemaEntryElement m_element;
......
......@@ -64,6 +64,16 @@ QVector<SchemaEntry> Product::schema() const
return d->schema;
}
SchemaEntry Product::schemaEntry(const QString& name) const
{
const auto it = std::find_if(d->schema.cbegin(), d->schema.cend(), [name](const auto &entry) {
return entry.name() == name;
});
if (it == d->schema.cend())
return {};
return *it;
}
void Product::setSchema(const QVector<SchemaEntry> &schema)
{
d->schema = schema;
......@@ -83,10 +93,19 @@ QByteArray Product::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("name"), name());
QJsonArray schema;
foreach (const auto &s, d->schema)
schema.push_back(s.toJsonObject());
obj.insert(QStringLiteral("schema"), schema);
{
QJsonArray schema;
foreach (const auto &s, d->schema)
schema.push_back(s.toJsonObject());
obj.insert(QStringLiteral("schema"), schema);
}
{
QJsonArray aggrs;
foreach (const auto &a, d->aggregations)
aggrs.push_back(a.toJsonObject());
obj.insert(QStringLiteral("aggregation"), aggrs);
}
QJsonDocument doc(obj);
return doc.toJson();
}
......@@ -96,21 +115,24 @@ static Product productFromJsonObject(const QJsonObject &obj)
Product product;
product.setName(obj.value(QStringLiteral("name")).toString());
product.setSchema(SchemaEntry::fromJson(obj.value(QStringLiteral("schema")).toArray()));
product.setAggregations(Aggregation::fromJson(product, obj.value(QLatin1String("aggregation")).toArray()));
// ### temporary HACK
QVector<Aggregation> aggrs;
for (const auto &entry : product.schema()) {
for (const auto &elem : entry.elements()) {
Aggregation aggr;
aggr.setType(Aggregation::Category);
AggregationElement e;
e.setSchemaEntry(entry);
e.setSchemaEntryElement(elem);
aggr.setElements({e});
aggrs.push_back(aggr);
if (product.aggregations().isEmpty()) {
QVector<Aggregation> aggrs;
for (const auto &entry : product.schema()) {
for (const auto &elem : entry.elements()) {
Aggregation aggr;
aggr.setType(Aggregation::Category);
AggregationElement e;
e.setSchemaEntry(entry);
e.setSchemaEntryElement(elem);
aggr.setElements({e});
aggrs.push_back(aggr);
}
}
product.setAggregations(aggrs);
}
product.setAggregations(aggrs);
return product;
}
......
......@@ -48,6 +48,7 @@ public:
QVector<SchemaEntry> schema() const;
void setSchema(const QVector<SchemaEntry>& schema);
SchemaEntry schemaEntry(const QString &name) const;
QVector<Aggregation> aggregations() const;
void setAggregations(const QVector<Aggregation> &aggregations);
......
......@@ -127,6 +127,16 @@ void SchemaEntry::setElements(const QVector<SchemaEntryElement> &elements)
d->elements = elements;
}
SchemaEntryElement SchemaEntry::element(const QString& name) const
{
const auto it = std::find_if(d->elements.cbegin(), d->elements.cend(), [name](const auto &entry) {
return entry.name() == name;
});
if (it == d->elements.cend())
return {};
return *it;
}
QJsonObject SchemaEntry::toJsonObject() const
{
QJsonObject obj;
......
......@@ -96,6 +96,7 @@ public:
QVector<SchemaEntryElement> elements() const;
void setElements(const QVector<SchemaEntryElement> &elements);
SchemaEntryElement element(const QString &name) const;
QJsonObject toJsonObject() const;
static QVector<SchemaEntry> fromJson(const QJsonArray &array);
......
......@@ -12,6 +12,7 @@ function(uf_add_test _file)
add_test(NAME ${_name} COMMAND ${_name})
endfunction()
uf_add_test(producttest UserFeedbackAnalyzer)
uf_add_test(productapitest UserFeedbackTestUtils)
uf_add_test(productmodeltest UserFeedbackTestUtils)
uf_add_test(schemamodeltest UserFeedbackTestUtils)
......
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <analyzer/core/aggregation.h>
#include <analyzer/core/product.h>
#include <3rdparty/qt/modeltest.h>
#include <QDebug>
#include <QtTest/qtest.h>
#include <QObject>
#include <QStandardPaths>
using namespace UserFeedback::Analyzer;
class ProductTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase()
{
Q_INIT_RESOURCE(schemaentrytemplates);
QStandardPaths::setTestModeEnabled(true);
}
void testFromJson()
{
const auto ps = Product::fromJson(R"({
"name": "org.kde.TestProduct",
"schema": [{
"name": "entry1",
"type": "scalar",
"elements": [{ "name": "elem11", "type": "string" }]
}, {
"name": "entry2",
"type": "list",
"elements": [{ "name": "elem21", "type": "number" }]
}],
"aggregation": [{
"type": "ratio_set",
"elements": [{ "type": "value", "schemaEntry": "entry1", "schemaEntryElement": "elem11" }]
}, {
"type": "numeric",
"elements": [{ "type": "size", "schemaEntry": "entry2" }]
}]
})");
QCOMPARE(ps.size(), 1);
const auto p = ps.at(0);
QCOMPARE(p.name(), QLatin1String("org.kde.TestProduct"));
QCOMPARE(p.schema().size(), 2);
const auto aggrs = p.aggregations();
QCOMPARE(aggrs.size(), 2);
{
const auto a1 = aggrs.at(0);
QCOMPARE(a1.type(), Aggregation::RatioSet);
const auto a1elems = a1.elements();
QCOMPARE(a1elems.size(), 1);
QCOMPARE(a1elems.at(0).type(), AggregationElement::Value);
QCOMPARE(a1elems.at(0).schemaEntry().name(), QLatin1String("entry1"));
QCOMPARE(a1elems.at(0).schemaEntry().dataType(), SchemaEntry::Scalar);
QCOMPARE(a1elems.at(0).schemaEntryElement().name(), QLatin1String("elem11"));
}
{
const auto a2 = aggrs.at(1);
QCOMPARE(a2.type(), Aggregation::Numeric);
const auto a2elems = a2.elements();
QCOMPARE(a2elems.size(), 1);
QCOMPARE(a2elems.at(0).type(), AggregationElement::Size);
QCOMPARE(a2elems.at(0).schemaEntry().name(), QLatin1String("entry2"));
QCOMPARE(a2elems.at(0).schemaEntry().dataType(), SchemaEntry::List);
QVERIFY(a2elems.at(0).schemaEntryElement().name().isEmpty());
}
}
};
QTEST_MAIN(ProductTest)
#include "producttest.moc"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment