/* * quiz_json_adapter.cpp — Реализация десериализации JSON → Quiz * * Весь процесс разбора сырых байт от сервера: * * reply->readAll() → QByteArray (бинарный буфер HTTP-ответа) * ↓ QJsonDocument::fromJson() * QJsonDocument (распарсенный JSON-документ) * ↓ .array() или .object() * QJsonArray / QJsonObject (узлы дерева JSON) * ↓ toQuizList() / toQuiz() ← этот файл * QList / Quiz (C++-объекты нашей модели) * * QJsonValue — универсальный тип, который может содержать * число, строку, bool, массив, объект или null. * Операция json["ключ"] всегда возвращает QJsonValue; * затем вызывается один из методов-преобразователей: * toInt(), toDouble(), toString(), toBool(), toObject(), toArray() */ #include "quiz_json_adapter.h" #include // нужен для работы с элементами QJsonArray в цикле // ───────────────────────────────────────────────────────────────────────────── // toQuiz — десериализация одного объекта // ───────────────────────────────────────────────────────────────────────────── Quiz QuizJsonAdapter::toQuiz(const QJsonObject &json) const { /* * Создаём пустой Quiz; все числа = 0, строки = "", bool = false. * Поля заполняются по одному из соответствующих JSON-ключей. */ Quiz q; /* * json["id"] возвращает QJsonValue с типом Double (JSON не различает * целое и вещественное). toInt() округляет до ближайшего целого. */ q.id = json["id"].toInt(); /* * toString() возвращает QString. Если ключ отсутствует или тип не строка — * вернётся пустая строка QString(), что безопасно. */ q.title = json["title"].toString(); q.description = json["description"].toString(); q.author = json["author"].toString(); /* * Дата в JSON приходит строкой в формате ISO 8601: * "2026-04-02T11:20:40.123456Z" * * Qt::ISODateWithMs — формат, совместимый с Django DateTimeField, * он понимает как микросекунды, так и часовой пояс Z (UTC). * * Если строка пустая или формат не совпадает, QDateTime будет * «недействительным» (isValid() == false) — без краша. */ q.createdAt = QDateTime::fromString(json["created_at"].toString(), Qt::ISODateWithMs); /* * toInt(): JSON "time_limit": 40 → C++ int. */ q.timeLimit = json["time_limit"].toInt(); /* * toBool(): JSON "is_published": true/false → C++ bool. * Если ключ отсутствует, вернётся false (значение по умолчанию). */ q.isPublished = json["is_published"].toBool(); return q; // возврат по значению; компилятор применит NRVO (copy elision) } // ───────────────────────────────────────────────────────────────────────────── // toQuizList — десериализация массива объектов // ───────────────────────────────────────────────────────────────────────────── QList QuizJsonAdapter::toQuizList(const QJsonArray &json) const { QList list; /* * reserve() выделяет память под json.size() элементов заранее, * чтобы не было многократных реаллокаций при append(). */ list.reserve(json.size()); /* * Итерация по QJsonArray. Каждый элемент — QJsonValue, * который может быть объектом, числом, строкой, null и т.д. * Проверяем isObject() на случай, если сервер вернул * смешанный массив или null-элементы. */ for (const QJsonValue &value : json) { if (value.isObject()) { /* * toObject() приводит QJsonValue к QJsonObject, * который затем передаётся в toQuiz() — переиспользуем * логику одиночного парсинга. */ list.append(toQuiz(value.toObject())); } } return list; }