Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON tree context to JsonError #120

Merged
merged 1 commit into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions lib/core/doc/res/snippets/qx-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ QX_JSON_MEMBER_OVERRIDE(MySpecialStruct, name,
//! [5]

//! [6]
QJsonArray ja;
// Somehow populate array...

for(int i = 0; i < ja.size(); ++i)
{
// Parse element
if(Qx::JsonError je = parseMyElement(ja[i]); je.isValid())
return je.withContext(QxJson::Array()).withContext(QxJson::ArrayElement(i));
}
//! [6]

//! [7]
class MyType
{
...
Expand All @@ -127,9 +139,9 @@ namespace QxJson
}
};
}
//! [6]

//! [7]

//! [8]
struct MyStruct
{
int number;
Expand Down Expand Up @@ -158,4 +170,4 @@ struct OtherStruct

QX_JSON_STRUCT(enabled, myStructs);
};
//! [7]
//! [8]
138 changes: 106 additions & 32 deletions lib/core/include/qx/core/qx-json.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
#include <QFileInfo>

// Intra-component Includes
#include "qx/core/qx-abstracterror.h"
Expand Down Expand Up @@ -76,6 +78,75 @@ namespace QxJson \
}; \
}

namespace QxJson
{

class File
{
private:
QString mIdentifier;

public:
File(const QString& filename);
File(const QFile& docFile);
File(const QFileInfo& docFile);

QString string() const;
};

class Document
{
private:
QString mName;

public:
Document(const QString& name = {});

QString string() const;
};

class Object
{
public:
Object();

QString string() const;
};

class ObjectKey
{
private:
QString mName;

public:
ObjectKey(const QString& name);

QString string() const;
};

class Array
{
public:
Array();

QString string() const;
};

class ArrayElement
{
private:
uint mElement;

public:
ArrayElement(uint element);

QString string() const;
};

using ContextNode = std::variant<File, Document, Object, ObjectKey, Array, ArrayElement>;

} // namespace QxJson

namespace Qx
{

Expand Down Expand Up @@ -106,22 +177,26 @@ class QX_CORE_EXPORT JsonError final : public AbstractError<"Qx::JsonError", 5>
private:
QString mAction;
Form mForm;
QList<QxJson::ContextNode> mContext;

//-Class Constructor-------------------------------------------------------------
//-Constructor-----------------------------------------------------------------
public:
JsonError();
JsonError(const QString& a, Form f);

//-Class Functions-------------------------------------------------------------
public:
bool isValid() const;
QString action() const;
Form form() const;

//-Instance Functions-------------------------------------------------------------
private:
quint32 deriveValue() const override;
QString derivePrimary() const override;
QString deriveSecondary() const override;
QString deriveDetails() const override;

public:
bool isValid() const;
QString action() const;
Form form() const;
QList<QxJson::ContextNode> context() const;
JsonError& withContext(const QxJson::ContextNode& node);
};

} // namespace Qx
Expand Down Expand Up @@ -315,7 +390,8 @@ struct Converter<T>
static Qx::JsonError fromJson(T& value, const QJsonValue& jValue)
{
if(!jValue.isObject())
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonObject>()), Qx::JsonError::TypeMismatch);
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonObject>()), Qx::JsonError::TypeMismatch)
.withContext(QxJson::Object());

// Underlying object
QJsonObject jObject = jValue.toObject();
Expand All @@ -342,7 +418,8 @@ struct Converter<T>
// Get value from key
if(!jObject.contains(mKey))
{
cnvError = Qx::JsonError(QxJsonPrivate::ERR_NO_KEY.arg(mKey), Qx::JsonError::MissingKey);
cnvError = Qx::JsonError(QxJsonPrivate::ERR_NO_KEY.arg(mKey), Qx::JsonError::MissingKey)
.withContext(QxJson::Object());
return false;
}
QJsonValue mValue = jObject.value(mKey);
Expand All @@ -353,6 +430,7 @@ struct Converter<T>
else
cnvError = QxJsonPrivate::performRegularConversion<mType>(value.*mPtr, mValue);

cnvError.withContext(QxJson::Object()).withContext(QxJson::ObjectKey(mKey));
return !cnvError.isValid();
}() && ...);
}, memberMetas);
Expand All @@ -373,7 +451,10 @@ struct Converter<T>
value.clear();

if(!jValue.isArray())
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonArray>()), Qx::JsonError::TypeMismatch);
{
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonArray>()), Qx::JsonError::TypeMismatch)
.withContext(QxJson::Array());
}

// Underlying Array
QJsonArray jArray = jValue.toArray();
Expand All @@ -382,13 +463,13 @@ struct Converter<T>
Qx::JsonError cnvError;

// Convert all
for(const QJsonValue& aValue : jArray)
for(auto i = 0; i < jArray.count(); ++i)
{
E converted;
if(cnvError = Converter<E>::fromJson(converted, aValue); cnvError.isValid())
if(cnvError = Converter<E>::fromJson(converted, jArray[i]); cnvError.isValid())
{
value.clear();
return cnvError;
return cnvError.withContext(QxJson::Array()).withContext(QxJson::ArrayElement(i));
}

value << converted;
Expand All @@ -411,22 +492,24 @@ struct Converter<T>
value.clear();

if(!jValue.isArray())
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonArray>()), Qx::JsonError::TypeMismatch);

{
return Qx::JsonError(QxJsonPrivate::ERR_CONV_TYPE.arg(QxJsonPrivate::typeString<QJsonArray>()), Qx::JsonError::TypeMismatch)
.withContext(QxJson::Array());
}
// Underlying Array
QJsonArray jArray = jValue.toArray();

// Error tracking
Qx::JsonError cnvError;

// Convert all
for(const QJsonValue& aValue : jArray)
for(auto i = 0; i < jArray.count(); ++i)
{
V converted;
if(cnvError = Converter<V>::fromJson(converted, aValue); cnvError.isValid())
if(cnvError = Converter<V>::fromJson(converted, jArray[i]); cnvError.isValid())
{
value.clear();
return cnvError;
return cnvError.withContext(QxJson::Array()).withContext(QxJson::ArrayElement(i));
}

value.insert(keygen<K, V>(converted), converted);
Expand Down Expand Up @@ -491,31 +574,22 @@ template<typename T>
JsonError parseJson(T& parsed, const QJsonDocument& doc)
{
if(doc.isEmpty())
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::EmptyDoc);
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::EmptyDoc).withContext(QxJson::Document());

using RootType = std::conditional_t<
(QxJson::json_containing<T>), QJsonArray, QJsonObject>;

RootType root;
if constexpr(QxJson::json_containing<T>)
{
if(!doc.isArray())
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::TypeMismatch);
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::TypeMismatch).withContext(QxJson::Document());

root = doc.array();
return parseJson(parsed, doc.array()).withContext(QxJson::Document());
}
else
{
if(!doc.isObject())
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::TypeMismatch);
return JsonError(QxJsonPrivate::ERR_PARSE_DOC, JsonError::TypeMismatch).withContext(QxJson::Document());

root = doc.object();
return parseJson(parsed, doc.object()).withContext(QxJson::Document());
}

// Use QJsonValue move constructor for semi-type erasure
QJsonValue rootAsValue = std::move(root);

return QxJson::Converter<T>::fromJson(parsed, rootAsValue);
}

template<typename T>
Expand Down
Loading