Skip to content

Commit 41cc5dd

Browse files
committed
Qt JSON types support
This adds support for Qt’s JSON types as proposed in the comment of PR cutelyst#5. The difficulty in using Qt’s JSON data types was that they can be casted to QVariantList/QVariantHash if they are inside a QVariant and e.g. `QVariant::canConvert<QVariantList>` returns true for a QJsonArray, but the next step by Cutelee is to cast them into QAssociativeIterable or QSequentialIterable. That only works for template based containers. So, my solution is to “intercept“ this types before the QVariant cast is tried and convert them directly into QVariantList or QVariantHash. If the JSON type is direct part of the context, this happens in `Cutelee::Variable::resolve()`, if the JSON type is stored in a context variable’s property or further down the road, the lookup will be done in `Cutelee::MetaType::lookup()`. Unit tests are currently written to test “normal“ usage as variable and to be used in a `{% for %}` loop tag. Maybe we should add some more tests to see if they play nicely with filters and the rest, even though I think that this implementations should make this possible without further changes.
1 parent 35e7dbf commit 41cc5dd

File tree

3 files changed

+467
-0
lines changed

3 files changed

+467
-0
lines changed

templates/lib/metatype.cpp

+81
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#include "metaenumvariable_p.h"
2626

2727
#include <QtCore/QDebug>
28+
#include <QJsonValue>
29+
#include <QJsonArray>
30+
#include <QJsonObject>
31+
#include <QJsonDocument>
2832

2933
using namespace Cutelee;
3034

@@ -106,12 +110,89 @@ static QVariant doQobjectLookUp(const QObject *const object,
106110
return object->property(property.toUtf8().constData());
107111
}
108112

113+
static QVariant doVariantListLookUp(const QVariantList &list,
114+
const QString &property)
115+
{
116+
if (property == QLatin1String("count") || property == QLatin1String("size")) {
117+
return list.size();
118+
}
119+
120+
bool ok = false;
121+
const int listIndex = property.toInt(&ok);
122+
if (!ok || listIndex >= list.size()) {
123+
return QVariant();
124+
}
125+
126+
return list.at(listIndex);
127+
}
128+
129+
static QVariant doVariantHashLookUp(const QVariantHash &hash,
130+
const QString &property)
131+
{
132+
if (property == QLatin1String("count") || property == QLatin1String("size")) {
133+
return hash.size();
134+
}
135+
136+
if (property == QLatin1String("items")) {
137+
QVariantList list;
138+
list.reserve(hash.size());
139+
for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
140+
list.push_back(QVariantList{it.key(), it.value()});
141+
}
142+
return list;
143+
}
144+
145+
if (property == QLatin1String("keys")) {
146+
return QStringList(hash.keys());
147+
}
148+
149+
if (property == QLatin1String("values")) {
150+
return hash.values();
151+
}
152+
153+
return hash.value(property);
154+
}
155+
109156
QVariant Cutelee::MetaType::lookup(const QVariant &object,
110157
const QString &property)
111158
{
112159
if (object.canConvert<QObject *>()) {
113160
return doQobjectLookUp(object.value<QObject *>(), property);
114161
}
162+
if (object.userType() == QMetaType::QJsonDocument) {
163+
const auto doc = object.toJsonDocument();
164+
if (doc.isObject()) {
165+
return doVariantHashLookUp(doc.object().toVariantHash(), property);
166+
}
167+
if (doc.isArray()) {
168+
return doVariantListLookUp(doc.array().toVariantList(), property);
169+
}
170+
return QVariant();
171+
}
172+
if (object.userType() == QMetaType::QJsonValue) {
173+
const auto val = object.toJsonValue();
174+
175+
switch (val.type()) {
176+
case QJsonValue::Bool:
177+
return val.toBool();
178+
case QJsonValue::Double:
179+
return val.toDouble();
180+
case QJsonValue::String:
181+
return val.toString();
182+
case QJsonValue::Array:
183+
return doVariantListLookUp(val.toArray().toVariantList(), property);
184+
case QJsonValue::Object:
185+
return doVariantHashLookUp(val.toObject().toVariantHash(), property);
186+
default:
187+
return QVariant();
188+
}
189+
}
190+
if (object.userType() == QMetaType::QJsonArray) {
191+
return doVariantListLookUp(object.toJsonArray().toVariantList(), property);
192+
}
193+
if (object.userType() == QMetaType::QJsonObject) {
194+
return doVariantHashLookUp(object.toJsonObject().toVariantHash(), property);
195+
}
115196
if (object.canConvert<QVariantList>()) {
116197
auto iter = object.value<QSequentialIterable>();
117198
if (property == QStringLiteral("size")

templates/lib/variable.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929

3030
#include <QtCore/QMetaEnum>
3131
#include <QtCore/QStringList>
32+
#include <QJsonArray>
33+
#include <QJsonDocument>
34+
#include <QJsonObject>
35+
#include <QJsonValue>
3236

3337
using namespace Cutelee;
3438

@@ -206,6 +210,42 @@ QVariant Variable::resolve(Context *c) const
206210

207211
} else {
208212
var = c->lookup(d->m_lookups.at(i++));
213+
if (var.userType() == QMetaType::QJsonDocument) {
214+
const auto jsonDoc = var.toJsonDocument();
215+
if (jsonDoc.isArray()) {
216+
var = jsonDoc.array().toVariantList();
217+
} else if (jsonDoc.isObject()) {
218+
var = jsonDoc.object().toVariantHash();
219+
} else {
220+
// JSON document is eather empty or null
221+
return QVariant();
222+
}
223+
} else if (var.userType() == QMetaType::QJsonValue) {
224+
const auto jsonVal = var.toJsonValue();
225+
switch(jsonVal.type()) {
226+
case QJsonValue::Bool:
227+
var = jsonVal.toBool();
228+
break;
229+
case QJsonValue::Double:
230+
var = jsonVal.toDouble();
231+
break;
232+
case QJsonValue::String:
233+
var = jsonVal.toString();
234+
break;
235+
case QJsonValue::Array:
236+
var = jsonVal.toArray().toVariantList();
237+
break;
238+
case QJsonValue::Object:
239+
var = jsonVal.toObject().toVariantHash();
240+
break;
241+
default:
242+
return QVariant();
243+
}
244+
} else if (var.userType() == QMetaType::QJsonArray) {
245+
var = var.toJsonArray().toVariantList();
246+
} else if (var.userType() == QMetaType::QJsonObject) {
247+
var = var.toJsonObject().toVariantHash();
248+
}
209249
}
210250
while (i < d->m_lookups.size()) {
211251
var = MetaType::lookup(var, d->m_lookups.at(i++));

0 commit comments

Comments
 (0)