Skip to content

Commit 2e7317d

Browse files
authored
Qt JSON types support (#6)
* Qt JSON types support This adds support for Qt’s JSON types as proposed in the comment of PR #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. * Use QJsonValue::toVariant() in Variable::resolve() Make the switch a bit simpler and convert directly to QVariant. * Use QJson data types in JSON lookup functions
1 parent 35e7dbf commit 2e7317d

File tree

3 files changed

+471
-1
lines changed

3 files changed

+471
-1
lines changed

templates/lib/metatype.cpp

+87-1
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,94 @@ static QVariant doQobjectLookUp(const QObject *const object,
106110
return object->property(property.toUtf8().constData());
107111
}
108112

113+
static QVariant doJsonArrayLookUp(const QJsonArray &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).toVariant();
127+
}
128+
129+
static QVariant doJsonObjectLookUp(const QJsonObject &obj,
130+
const QString &property)
131+
{
132+
if (property == QLatin1String("count") || property == QLatin1String("size")) {
133+
return obj.size();
134+
}
135+
136+
if (property == QLatin1String("items")) {
137+
QVariantList list;
138+
list.reserve(obj.size());
139+
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
140+
list.push_back(QVariantList{it.key(), it.value().toVariant()});
141+
}
142+
return list;
143+
}
144+
145+
if (property == QLatin1String("keys")) {
146+
return obj.keys();
147+
}
148+
149+
if (property == QLatin1String("values")) {
150+
QVariantList list;
151+
list.reserve(obj.size());
152+
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
153+
list.push_back(it.value().toVariant());
154+
}
155+
return list;
156+
}
157+
158+
return obj.value(property).toVariant();
159+
}
160+
109161
QVariant Cutelee::MetaType::lookup(const QVariant &object,
110-
const QString &property)
162+
const QString &property)
111163
{
112164
if (object.canConvert<QObject *>()) {
113165
return doQobjectLookUp(object.value<QObject *>(), property);
114166
}
167+
if (object.userType() == QMetaType::QJsonDocument) {
168+
const auto doc = object.toJsonDocument();
169+
if (doc.isObject()) {
170+
return doJsonObjectLookUp(doc.object(), property);
171+
}
172+
if (doc.isArray()) {
173+
return doJsonArrayLookUp(doc.array(), property);
174+
}
175+
return QVariant();
176+
}
177+
if (object.userType() == QMetaType::QJsonValue) {
178+
const auto val = object.toJsonValue();
179+
180+
switch (val.type()) {
181+
case QJsonValue::Bool:
182+
return val.toBool();
183+
case QJsonValue::Double:
184+
return val.toDouble();
185+
case QJsonValue::String:
186+
return val.toString();
187+
case QJsonValue::Array:
188+
return doJsonArrayLookUp(val.toArray(), property);
189+
case QJsonValue::Object:
190+
return doJsonObjectLookUp(val.toObject(), property);
191+
default:
192+
return QVariant();
193+
}
194+
}
195+
if (object.userType() == QMetaType::QJsonArray) {
196+
return doJsonArrayLookUp(object.toJsonArray(), property);
197+
}
198+
if (object.userType() == QMetaType::QJsonObject) {
199+
return doJsonObjectLookUp(object.toJsonObject(), property);
200+
}
115201
if (object.canConvert<QVariantList>()) {
116202
auto iter = object.value<QSequentialIterable>();
117203
if (property == QStringLiteral("size")

templates/lib/variable.cpp

+38
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,40 @@ 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+
case QJsonValue::Object:
237+
var = jsonVal.toVariant();
238+
break;
239+
default:
240+
return QVariant();
241+
}
242+
} else if (var.userType() == QMetaType::QJsonArray) {
243+
var = var.toJsonArray().toVariantList();
244+
} else if (var.userType() == QMetaType::QJsonObject) {
245+
var = var.toJsonObject().toVariantHash();
246+
}
209247
}
210248
while (i < d->m_lookups.size()) {
211249
var = MetaType::lookup(var, d->m_lookups.at(i++));

0 commit comments

Comments
 (0)