]> git.sesse.net Git - pkanalytics/commitdiff
Implement JSON export. (For the time being, automatically on startup only, and nothin...
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 5 May 2023 22:20:34 +0000 (00:20 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 5 May 2023 22:24:34 +0000 (00:24 +0200)
json.cpp [new file with mode: 0644]
json.h [new file with mode: 0644]
main.cpp
meson.build

diff --git a/json.cpp b/json.cpp
new file mode 100644 (file)
index 0000000..56b2000
--- /dev/null
+++ b/json.cpp
@@ -0,0 +1,136 @@
+#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);
+       }
+}
diff --git a/json.h b/json.h
new file mode 100644 (file)
index 0000000..4244f63
--- /dev/null
+++ b/json.h
@@ -0,0 +1,8 @@
+#ifndef _JSON_H
+#define _JSON_H 1
+
+#include <sqlite3.h>
+
+void export_to_json(sqlite3 *db, const char *filename);
+
+#endif  // !eefined(_JSON_H)
index 2a756495397f2df983e8f633db86a62782e53daa..0a6819b2d3587396e7a4f563df4d34c12f23c5a9 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -15,6 +15,7 @@
 #include "ui_mainwindow.h"
 #include "events.h"
 #include "players.h"
+#include "json.h"
 
 using namespace std;
 
@@ -555,6 +556,9 @@ int main(int argc, char *argv[])
        QApplication app(argc, argv);
        sqlite3 *db = open_db("ultimate.db");
 
+       // TODO: do this on-demand instead, from a menu
+       export_to_json(db, "ultimate.json");
+
        int requested_match = -1;
        if (argc >= 2) {
                requested_match = atoi(argv[1]);
index 0475a2130144d0f0d84007f171b2568cca3a2ded..ae33315d663e7dc9e2230392e2f759c320a5b317 100644 (file)
@@ -9,4 +9,4 @@ qt_files = qt6.preprocess(
        ui_files: ['mainwindow.ui'],
         dependencies: qt6deps)
 
-executable('stats', ['main.cpp', 'events.cpp', 'players.cpp'], qt_files, dependencies: [qt6deps, sqlite3dep])
+executable('stats', ['main.cpp', 'events.cpp', 'players.cpp', 'json.cpp'], qt_files, dependencies: [qt6deps, sqlite3dep])