Commit 83d2b704 authored by Volker Krause's avatar Volker Krause
Browse files

Add (de)serialization code for aggregation settings

parent 637977dc
......@@ -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"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment