/ desktop / datalake / database.cpp
database.cpp
  1  #include "database.hpp"
  2  
  3  #include <QCoreApplication>
  4  #include <QDir>
  5  #include <QFileInfo>
  6  #include <QSqlQuery>
  7  #include <iostream>
  8  
  9  #include "cartographer.hpp"
 10  #include "config/config.hpp"
 11  
 12  KotoDatabase::KotoDatabase() {
 13    QString dbPath        = QDir(KotoConfig::instance().getConfigDirPath()).filePath("koto.db");
 14    this->shouldBootstrap = !QFileInfo::exists(dbPath);
 15  
 16    this->db = QSqlDatabase::addDatabase("QSQLITE");
 17    std::cout << "Database path: " << dbPath.toStdString() << std::endl;
 18  
 19    this->db.setDatabaseName(dbPath);
 20  }
 21  
 22  KotoDatabase& KotoDatabase::instance() {
 23    static KotoDatabase _instance;
 24    return _instance;
 25  }
 26  
 27  void KotoDatabase::connect() {
 28    if (!this->db.open()) {
 29      std::cerr << "Failed to open database" << std::endl;
 30      QCoreApplication::quit();
 31    }
 32  
 33    if (this->shouldBootstrap) this->bootstrap();
 34  }
 35  
 36  void KotoDatabase::disconnect() {
 37    this->db.close();
 38  }
 39  
 40  QSqlDatabase KotoDatabase::getDatabase() {
 41    return this->db;
 42  }
 43  
 44  bool KotoDatabase::requiredBootstrap() {
 45    return this->shouldBootstrap;
 46  }
 47  
 48  void KotoDatabase::bootstrap() {
 49    QSqlQuery query(this->db);
 50  
 51    query.exec("CREATE TABLE IF NOT EXISTS artists(id string UNIQUE PRIMARY KEY, name string, art_path string);");
 52    query.exec(
 53        "CREATE TABLE IF NOT EXISTS albums(id string UNIQUE PRIMARY KEY, artist_id string, name string, description string, narrator string, art_path string, "
 54        "genres strings, year int, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE);");
 55    query.exec(
 56        "CREATE TABLE IF NOT EXISTS tracks(id string UNIQUE PRIMARY KEY, artist_id string, album_id string, name string, disc int, position int, duration int, "
 57        "genres string, FOREIGN KEY(artist_id) REFERENCES artists(id) ON DELETE CASCADE, FOREIGN KEY (album_id) REFERENCES albums(id) ON DELETE CASCADE);");
 58    query.exec(
 59        "CREATE TABLE IF NOT EXISTS libraries_albums(id string, album_id string, path string, PRIMARY KEY (id, album_id) FOREIGN KEY(album_id) REFERENCES "
 60        "albums(id) "
 61        "ON DELETE CASCADE);");
 62    query.exec(
 63        "CREATE TABLE IF NOT EXISTS libraries_artists(id string, artist_id string, path string, PRIMARY KEY(id, artist_id) FOREIGN KEY(artist_id) REFERENCES "
 64        "artists(id) ON DELETE CASCADE);");
 65    query.exec(
 66        "CREATE TABLE IF NOT EXISTS libraries_tracks(id string, track_id string, path string, PRIMARY KEY(id, track_id) FOREIGN KEY(track_id) REFERENCES "
 67        "tracks(id) "
 68        "ON DELETE CASCADE);");
 69    query.exec(
 70        "CREATE TABLE IF NOT EXISTS playlist_meta(id string UNIQUE PRIMARY KEY, name string, art_path string, preferred_model int, album_id string, track_id "
 71        "string, "
 72        "playback_position_of_track int);");
 73    query.exec(
 74        "CREATE TABLE IF NOT EXISTS playlist_tracks(position INTEGER PRIMARY KEY AUTOINCREMENT, playlist_id string, track_id string, FOREIGN KEY(playlist_id) "
 75        "REFERENCES playlist_meta(id), FOREIGN KEY(track_id) REFERENCES tracks(id) ON DELETE CASCADE);");
 76  }
 77  
 78  void KotoDatabase::load() {
 79    QSqlQuery query(this->db);
 80  
 81    query.exec("SELECT * FROM artists;");
 82    while (query.next()) {
 83      KotoArtist* artist = KotoArtist::fromDb(query, query.record());
 84      Cartographer::instance().addArtist(artist);
 85    }
 86  
 87    query.exec("SELECT * FROM albums;");
 88    while (query.next()) {
 89      KotoAlbum* album  = KotoAlbum::fromDb(query, query.record());
 90      auto       artist = Cartographer::instance().getArtist(album->artist_uuid);
 91      if (artist.has_value()) { artist.value()->addAlbum(album); }
 92      Cartographer::instance().addAlbum(album);
 93    }
 94  
 95    query.exec("SELECT * FROM tracks;");
 96    while (query.next()) {
 97      KotoTrack* track  = KotoTrack::fromDb(query, query.record());
 98      auto       artist = Cartographer::instance().getArtist(track->artist_uuid);
 99      if (artist.has_value()) { artist.value()->addTrack(track); }
100      Cartographer::instance().addTrack(track);
101    }
102  }