--- /dev/null
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <sqlite3.h>
+#include "json.h"
+
+QJsonArray export_players_to_json(sqlite3 *db)
+{
+ QJsonArray players;
+
+ sqlite3_stmt *stmt;
+ int ret = sqlite3_prepare_v2(db, "SELECT player, number, name, gender FROM player ORDER BY (number+0), number", -1, &stmt, 0);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ for ( ;; ) {
+ ret = sqlite3_step(stmt);
+ if (ret == SQLITE_ROW) {
+ QJsonObject p;
+ p.insert("player_id", sqlite3_column_int(stmt, 0));
+ p.insert("number", (const char *)sqlite3_column_text(stmt, 1));
+ p.insert("name", (const char *)sqlite3_column_text(stmt, 2));
+ p.insert("gender", (const char *)sqlite3_column_text(stmt, 3));
+ players.push_back(std::move(p));
+ } else if (ret == SQLITE_DONE) {
+ break;
+ } else {
+ fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ }
+ ret = sqlite3_finalize(stmt);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+
+ return players;
+}
+
+QJsonArray export_matches_to_json(sqlite3 *db)
+{
+ QJsonArray matches;
+
+ // Load the events, splitting them into matches as we go.
+ std::map<int, QJsonArray *> events_per_match;
+ sqlite3_stmt *stmt;
+ int ret = sqlite3_prepare_v2(db, "SELECT match, t, player, type FROM event ORDER BY t", -1, &stmt, 0);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ for ( ;; ) {
+ ret = sqlite3_step(stmt);
+ if (ret == SQLITE_ROW) {
+ int match = sqlite3_column_int(stmt, 0);
+ if (events_per_match.count(match) == 0) {
+ events_per_match[match] = new QJsonArray;
+ }
+
+ QJsonObject e;
+ e.insert("t", sqlite3_column_int(stmt, 1));
+ e.insert("player", sqlite3_column_int(stmt, 2));
+ e.insert("type", (const char *)sqlite3_column_text(stmt, 3));
+ events_per_match[match]->push_back(std::move(e));
+ } else if (ret == SQLITE_DONE) {
+ break;
+ } else {
+ fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ }
+ ret = sqlite3_finalize(stmt);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+
+ // Load the matches themselves.
+ ret = sqlite3_prepare_v2(db, "SELECT match, description FROM match ORDER BY match", -1, &stmt, 0);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ for ( ;; ) {
+ ret = sqlite3_step(stmt);
+ if (ret == SQLITE_ROW) {
+ int match = sqlite3_column_int(stmt, 0);
+ QJsonObject m;
+ m.insert("match_id", match);
+ m.insert("description", (const char *)sqlite3_column_text(stmt, 1));
+ if (events_per_match.count(match)) {
+ m.insert("events", std::move(*events_per_match[match]));
+ delete events_per_match[match];
+ } else {
+ m.insert("events", QJsonArray());
+ }
+ matches.push_back(std::move(m));
+ } else if (ret == SQLITE_DONE) {
+ break;
+ } else {
+ fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+ }
+ ret = sqlite3_finalize(stmt);
+ if (ret != SQLITE_OK) {
+ fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db));
+ abort();
+ }
+
+ return matches;
+}
+
+void export_to_json(sqlite3 *db, const char *filename)
+{
+ QJsonObject obj;
+ obj.insert("players", export_players_to_json(db));
+ obj.insert("matches", export_matches_to_json(db));
+
+ QByteArray serialized = QString(QJsonDocument(obj).toJson(QJsonDocument::Compact)).toUtf8();
+ FILE *fp = fopen("ultimate.json", "w");
+ if (fp == nullptr) {
+ perror("ultimate.json");
+ exit(1);
+ }
+ if (fwrite(serialized.data(), serialized.size(), 1, fp) != 1) {
+ perror("fwrite");
+ exit(1);
+ }
+ if (fclose(fp) != 0) {
+ perror("fclose");
+ exit(1);
+ }
+}