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 }